将函数应用于可以返回多行的pandas DataFrame

bte*_*tel 15 python dataframe pandas

我正在尝试转换DataFrame,这样一些行将被复制给定次数.例如:

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]})

  class  count
0     A      1
1     B      0
2     C      2
Run Code Online (Sandbox Code Playgroud)

应转变为:

  class 
0     A   
1     C   
2     C 
Run Code Online (Sandbox Code Playgroud)

这与计数功能的聚合相反.是否有一种简单的方法可以在熊猫中实现它(不使用for循环或列表推导)?

一种可能性是允许DataFrame.applymap函数返回多行(类似apply方法GroupBy).但是,我认为现在大熊猫不可能.

Wes*_*ney 22

你可以使用groupby:

def f(group):
    row = group.irow(0)
    return DataFrame({'class': [row['class']] * row['count']})
df.groupby('class', group_keys=False).apply(f)
Run Code Online (Sandbox Code Playgroud)

所以你得到了

In [25]: df.groupby('class', group_keys=False).apply(f)
Out[25]: 
  class
0     A
0     C
1     C
Run Code Online (Sandbox Code Playgroud)

您可以根据需要修复结果的索引

  • 好答案!如果我有几十个其他列,除了明确地将它们全部输入之外,是否有一种简单的方法可以将这些列保留在 `f` 的结果中? (2认同)

小智 7

甚至还有一种更简单、更高效的解决方案。我必须对大约 350 万行的表进行类似的修改,并且之前建议的解决方案非常慢。

更好的方法是使用 numpy 的重复过程生成一个新索引,其中每个行索引根据给定的计数重复多次,并使用iloc根据该索引选择原始表中的行:

import pandas as pd
import numpy as np

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count': [1, 0, 2]})
spread_ixs = np.repeat(range(len(df)), df['count'])
spread_ixs 

array([0, 2, 2])

df.iloc[spread_ixs, :].drop(columns='count').reset_index(drop=True)

  class
0     A
1     C
2     C
Run Code Online (Sandbox Code Playgroud)


Rad*_*ard 5

我知道这是一个老问题,但我无法让 Wes 的答案适用于数据框中的多列,因此我使他的代码更通用。我想我会分享以防其他人在这个问题上遇到同样的问题。

您只需指定其中包含计数的列,然后您就会得到一个扩展的数据框作为回报。

import pandas as pd
df = pd.DataFrame({'class 1': ['A','B','C','A'],
                   'class 2': [ 1,  2,  3,  1], 
                   'count':   [ 3,  3,  3,  1]})
print df,"\n"

def f(group, *args):
    row = group.irow(0)
    Dict = {}
    row_dict = row.to_dict()
    for item in row_dict: Dict[item] = [row[item]] * row[args[0]]
    return pd.DataFrame(Dict)

def ExpandRows(df,WeightsColumnName):
    df_expand = df.groupby(df.columns.tolist(), group_keys=False).apply(f,WeightsColumnName).reset_index(drop=True)
    return df_expand


df_expanded = ExpandRows(df,'count')
print df_expanded
Run Code Online (Sandbox Code Playgroud)

返回:

  class 1  class 2  count
0       A        1      3
1       B        2      3
2       C        3      3
3       A        1      1 

  class 1  class 2  count
0       A        1      1
1       A        1      3
2       A        1      3
3       A        1      3
4       B        2      3
5       B        2      3
6       B        2      3
7       C        3      3
8       C        3      3
9       C        3      3
Run Code Online (Sandbox Code Playgroud)

关于速度,我的基本 df 是 10 列 x 6k 行,扩展时是 ~100,000 行需要 ~7 秒。在这种情况下,我不确定分组是否必要或明智,因为它将所有列组合成分组形式,但是嘿,无论只有 7 秒。