我有这个数据帧:
A B
0 [0, 1, 2] 1
1 foo 1
2 [3, 4] 1
我想对"A"列使用分解函数,然后在"B"列的情况下为每个分解行保持正确和公平的比例。所以结果应该看起来像这样:
A B
0 0 0.33
0 1 0.33
0 2 0.33
1 foo 1
2 3 0.5
2 4 0.5
使用分解功能可以做到这一点吗?我会设法得到这个结果for row in data.itertuples():
但是在大型数据帧的情况下,for循环非常慢。那么,您知道如何通过爆炸或其他快速方法解决此问题吗?
如果有任何帮助,我将不胜感激。
你可以explode
"A";然后groupby
索引和transform
count
方法(计算每个索引的数量),并将'B'
中的元素除以其相应的索引计数。
out = df.explode('A')
out['B'] /= out['B'].groupby(level=0).transform('count')
输出:
A B
0 0 0.333333
0 1 0.333333
0 2 0.333333
1 foo 1.000000
2 3 0.500000
2 4 0.500000
创建一个布尔掩码,该掩码指示A
包含列表的行:
mask = df['A'].apply(lambda x: isinstance(x, list))
用整数 1 预填充新的分母列(以保持除以这些值不变):
df['denom'] = 1
对于A
为列表的每一行,用列表的长度覆盖B
的值:
df.loc[mask, 'denom'] = df['A'].str.len()
分解列A
,计算B
的新值,并删除denom
:
res = df.explode('A').reset_index(drop=True)
res['B'] = res['B'] / res['denom']
res = res.drop(columns='denom')
结果:
print(res)
A B
0 0 0.333333
1 1 0.333333
2 2 0.333333
3 foo 1.000000
4 3 0.500000
5 4 0.500000
您可以使用explode
,然后groupby
+apply
:
(df.explode('A')
.assign(B=lambda d: d.groupby(level=0)['B'].apply(lambda s:s/len(s)))
)
输出:
A B
0 0 0.333333
0 1 0.333333
0 2 0.333333
1 foo 1.000000
2 4 0.500000
2 5 0.500000
输入:
df = pd.DataFrame({'A': [[0,1,2], 'foo', [4,5]],
'B': [1,1,1]})