Python - How to split cell in a column to a new row based of a delmimeter
numpy, pandas, python
Solution
Blend of Speed and Elegance
def pir(df, c):
colc = df[c].str.split('\.|;|#')
clst = colc.values.tolist()
lens = [len(l) for l in clst]
cdf = pd.DataFrame({c: np.concatenate(clst)}, df.index.repeat(lens))
return df.drop(c, 1).join(cdf).reset_index(drop=True)
Forget Elegance, Give me Speed!
def pir2(df, c):
colc = df[c].str.split('\.|;|#')
clst = colc.values.tolist()
lens = [len(l) for l in clst]
j = df.columns.get_loc(c)
v = df.values
n, m = v.shape
r = np.arange(n).repeat(lens)
return pd.DataFrame(
np.column_stack([v[r, 0:j], np.concatenate(clst), v[r, j+1:]]),
columns=df.columns
)
pir(df, 'COL_C')
# pir2(df, 'COL_C')
COL_A COL_B COL_C
0 Hello World Hi
1 Hello World 123
2 Hello World move
3 New line Can
4 New line I
5 New line parse
6 New line this
7 New line data
Timing
%timeit pir(df, 'COL_C')
1000 loops, best of 3: 1.42 ms per loop
%timeit pir2(df, 'COL_C')
1000 loops, best of 3: 278 µs per loop
%timeit split_list_in_cols_to_rows(df.assign(COL_C=df.COL_C.str.split(r'[.,;#]')), lst_cols='COL_C')
100 loops, best of 3: 4.16 ms per loop
%%timeit
COL_C2 = df.COL_C.str.split('\.|;|#').apply(pd.Series).stack()
df.drop('COL_C', 1).join(pd.Series(index=COL_C2.index.droplevel(1), data=COL_C2.values, name='COL_C')).reset_index(drop=True)
100 loops, best of 3: 2.81 ms per loop
Setup
from io import StringIO
import pandas as pd
txt = """COL_A | COL_B | COL_C
Hello | World | Hi#123;move
New | line | Can.I#parse;this.data """
df = pd.read_csv(StringIO(txt), sep='\s*\|\s*', engine='python')
Problem
Relatively new and trying to split some data with python from a CSV file. I am trying to parse this data and split it into a new row if a specific delimiter appears. Those delimiters are '.' ';' and '#'. There are also no spaces in COL_C. In addition, it wouldn't matter the order of the delimiters, if we find one of them, automatically create the new line. Here is the example data `COL_A | COL_B |COL_C` `--------------------` `Hello | World | Hi.Can;You#Help` the output i'm trying to get would be: `COL_A | COL_B | COL_C` `----------------------` `Hello | World | Hi` `Hello | World | Can` `Hello | World | You` `Hello | World | Help` example 2: `COL_A | COL_B | COL_C` `----------------------` `Hello | World | Hi#123;move` `New | line | Can.I#parse;this.data` the output i'm trying to get would be: `COL_A | COL_B | COL_C` `----------------------` `Hello | World | Hi` `Hello | World | 123` `Hello | World | move` `New | Line | Can` `New | Line | I` `New | Line | parse` `New | Line | this` `New | Line | data` If this data set had another row without Hello World and had world hello in the first two columns, i would like to display that with the corresponding third column's data parsed out into new rows. thanks!