我正在尝试转换 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
这是使用 count 函数进行聚合的逆过程。有没有一种简单的方法可以在 pandas 中实现它(不使用 for 循环或列表理解)?
一种可能是允许
DataFrame.applymap
函数返回多行(类似于 apply
的 GroupBy
方法)。然而,我认为现在在 pandas 中这是不可能的。
你可以使用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
您可以随意修改结果的索引
甚至还有一种更简单、更高效的解决方案。 我必须对大约 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
我知道这是一个老问题,但我很难让 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 秒。
这个问题很老了,答案并不反映pandas的现代能力。您可以使用
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 的好处。
这个问题非常非常古老,现有的答案并不能反映 pandas 的现代能力。
import pandas as pd
df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count': [1, 0, 2]})
def replicate_row(row):
_class = row.to_dict()['class']
return [{'class': _class}] * row['count']
result = df.apply(replicate_row, axis=1)
flat_list = [item for sublist in result for item in sublist]
new_df = pd.DataFrame(flat_list)
print(new_df)
输出:
class
0 A
1 C
2 C