【问题标题】:How to do explode and keep a fair proportion of number value for each new row Pandas如何为每一行 Pandas 做爆炸并保持公平比例的数值
【发布时间】:2022-01-17 18:30:23
【问题描述】:

我有这个数据框:

           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

这可以通过explode 功能实现吗?我会设法用for row in data.itertuples(): 得出这个结果,但是如果数据框很大,for 循环会很慢。那么您知道如何通过爆炸或其他快速方法解决这个问题吗?

如果有任何帮助,我将不胜感激。

【问题讨论】:

  • edf = df.explode("A"); edf.B = edf.groupby(edf.index).B.transform("size").rdiv(1)。您没有将您的全部尝试显示为代码,因此我不尝试解释。另外,如果这对你来说足够快的话,idk :)
  • 很公平。不管怎么说,还是要谢谢你。除非我使用 for 循环,否则我没有设法解决这个问题。我不确定在没有以任何方式连接的情况下使用 for 循环将这种尝试发布到这篇文章是否值得。

标签: python pandas dataframe pandas-explode


【解决方案1】:

你可以explode“A”;然后groupby索引和transformcount方法(计算每个索引的数量)并将'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

【讨论】:

  • 比我的回答好太多了! :P
【解决方案2】:

创建一个布尔掩码,指示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

【讨论】:

    【解决方案3】:

    您可以使用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]})
    

    【讨论】:

    • 您显示的输出与您的代码产生的输出不匹配。
    • 我喜欢它是一条线的答案。但是,您的答案的一部分是 ...B=... 我怎样才能在其中放置一个变量,以便这行代码是动态的并且可以在函数中使用它?
    • @kvetjo 你可以在assign 中使用字典:assign(**{'B': lambda ...}),现在列名是一个字符串并且是动态的;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 2014-09-08
    • 2017-08-19
    相关资源
    最近更新 更多