我有一个数据框(从CSV文件派生),大约有100M条目,如下所示:
df1:
var1 var2
0 1 2
1 2 1
2 1 {3,4,5}
3 5 6
4 {4,5,6,7} 8
我需要将其转换为一个新的数据框,其中(对于每一行)大括号中的每个元素都需要与另一列中的元素相关联,即
df2:
var1 var2
0 1 2
1 2 1
2 1 3
3 1 4
4 1 5
5 5 6
6 4 8
7 5 8
8 6 8
9 7 8
每个元素都是一个字符串,甚至是大括号条目本身。请注意,支撑元素可以位于任一列中。有谁知道如何有效地为大约100M条目的数据集实现这一目标?提前致谢。
Python示例:
import pandas as pd
df1 = pd.DataFrame([{'var1': '1', 'var2': '2'},
{'var1': '2', 'var2': '1'},
{'var1': '1', 'var2': '{3,4,5}'},
{'var1': '5', 'var2': '6'},
{'var1': '{4,5,6,7}', 'var2': '8'}])
df2 = pd.DataFrame([{'var1': '1', 'var2': '2'},
{'var1': '2', 'var2': '1'},
{'var1': '1', 'var2': '3'},
{'var1': '1', 'var2': '4'},
{'var1': '1', 'var2': '5'},
{'var1': '5', 'var2': '6'},
{'var1': '4', 'var2': '8'},
{'var1': '5', 'var2': '8'},
{'var1': '6', 'var2': '8'},
{'var1': '7', 'var2': '8'}])
到目前为止,我已经这样做了,但它很慢并使用了另一个数据框。
# Put row with braces in the second column
def swap_cols(row):
if '{' in row[0]:
return (row[1], row[0])
return row
# Convert the braces into a list
def parse_str(s):
if '{' in s:
s = s[1:-1]
return s.split(',')
return [s]
df3 = df1.apply(swap_cols, axis=1)
df3.var2 = df3.var2.apply(parse_str)
# Show that it works
for ridx, row in df3.iterrows():
for ele in row.var2:
print row.var1, ele
答案 0 :(得分:2)
您可以np.vstack
与np.meshgrid
和reshape
使用
sdf = df.apply(lambda x:(x.str.strip('{}').str.split(',')))
def cartesian(x):
return np.vstack(np.array([np.array(np.meshgrid(*i)).T.reshape(-1,2) for i in x.values]))
ndf = pd.DataFrame(cartesian(sdf),columns=sdf.columns)
如果你想剥离和拆分然后应用笛卡儿
%%time
100 loops, best of 3: 4 ms per loop
如果您确实有条带化和分割数据帧,那么:
1000 loops, best of 3: 564 µs per loop
输出:
var1 var2 0 1 2 1 2 1 2 1 3 3 1 4 4 1 5 5 5 6 6 4 8 7 5 8 8 6 8 9 7 8
答案 1 :(得分:0)
你可以尝试:
# isolate these cases as they will be treated separately
case1 = df1['var1'].str.contains('{')
case2 = df1['var2'].str.contains('}')
# convert to lists
import ast
df1 = df1.apply(lambda col: col.str.replace('{', '[').str.replace('}', ']')) \
.applymap(ast.literal_eval)
在第二种情况下:
df1[case2].groupby('var1')['var2'].apply(lambda g: pd.Series(g.sum())) \
.reset_index(-1, drop=True).reset_index()
应用sum
将连接var1
的每个值的列表(如果有多个),并且转换为pandas.Series
将提供您正在寻找的形状。
然后你可以将所有内容连接起来:
pd.concat([
df1[~case1 & ~case2],
df1[case1].groupby('var2')['var1'].apply(lambda g: pd.Series(g.sum())).reset_index(-1, drop=True).reset_index(),
df1[case2].groupby('var1')['var2'].apply(lambda g: pd.Series(g.sum())).reset_index(-1, drop=True).reset_index()
]).sort_values('var1') # sorting optional
答案 2 :(得分:0)
使用numpy.repeat
和numpy.concatenate
进行展平:
#create lists by remove {} and split
splitted1 = df1['var1'].str.strip('{}').str.split(',')
#get legths of lists
lens1 = splitted1.str.len()
splitted2 = pd.Series(np.repeat(df1['var2'].values, lens1)).str.strip('{}').str.split(',')
lens2 = splitted2.str.len()
df = pd.DataFrame({'a':np.repeat(np.concatenate(splitted1), lens2),
'b':np.concatenate(splitted2)})
print (df)
a b
0 1 2
1 2 1
2 1 3
3 1 4
4 1 5
5 5 6
6 4 8
7 5 8
8 6 8
9 7 8