19

我正在尝试转换 DataFrame,以便某些行将被复制给定次数。例如:

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

  class  count
0     A      1
1     B      0
2     C      2

应转化为:

  class 
0     A   
1     C   
2     C 

这是带有计数功能的聚合的逆向。有没有一种简单的方法可以在 pandas 中实现它(不使用 for 循环或列表推导)?

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

4

4 回答 4

30

您可以使用 groupby:

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

所以你得到

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

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

于 2012-10-24T15:25:40.213 回答
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

回报:

  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

关于速度,我的基本 df 是 10 列 x 约 6k 行,当扩展为约 100,000 行时需要约 7 秒。在这种情况下,我不确定分组是必要的还是明智的,因为它会将所有列都分组,但是无论如何只有 7 秒。

于 2015-05-04T21:25:03.923 回答
4

甚至还有一个更简单且显着更有效的解决方案。我不得不对大约 350 万行的表进行类似的修改,并且之前建议的解决方案非常慢。

更好的方法是使用numpy的repeat过程生成一个新索引,其中每个行索引根据其给定的计数重复多次,并使用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
于 2020-01-01T12:55:13.990 回答
1

这个问题很老了,答案并不反映熊猫的现代能力。您可以使用iterrows循环遍历每一行,然后使用 DataFrame 构造函数创建具有正确行数的新 DataFrame。最后,用于pd.concat将所有行连接在一起。

pd.concat([pd.DataFrame(data=[row], index=range(row['count'])) 
           for _, row in df.iterrows()], ignore_index=True)

  class  count
0     A      1
1     C      2
2     C      2

这具有使用任何大小的 DataFrame 的好处。

于 2017-08-29T19:16:40.563 回答