Python 在大熊猫数据帧中将条目重新分配到多行
我有一个数据帧(源自CSV文件),其中包含大约100万个条目,如下所示:Python 在大熊猫数据帧中将条目重新分配到多行,python,pandas,numpy,dataframe,Python,Pandas,Numpy,Dataframe,我有一个数据帧(源自CSV文件),其中包含大约100万个条目,如下所示: 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
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
每个元素都是一个字符串,甚至是大括号条目本身。请注意,支撑图元可以位于任一列中。有人知道我如何才能有效地为大约1亿个条目的数据集实现这一点吗?提前谢谢
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
你可以试试:
# 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
用于展平:
#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
您可以将
np.vstack
与np.meshgrid
和重塑
一起使用,即
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
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
我添加了numpy标签,这可以吸引有趣的答案:)所以没有一个答案是有用的?我想看看现实生活中的性能比较。