按列对分组数据帧进行采样
Posted
技术标签:
【中文标题】按列对分组数据帧进行采样【英文标题】:Sampling a grouped dataframe by column 【发布时间】:2017-08-20 17:28:35 【问题描述】:我有一个数据框,我将其分组如下并将某些操作应用于特定列:
df = df.groupby(['A', 'B', 'C']).agg('ID': 'count', 'AMT': 'sum')
对于每个 groupby 组合 (~15) 我想随机抽样属于每个组合的行并返回一个样本 ID 并在第三个输出列中报告它。或者我真的只是希望该组合中的行中的一个 ID 出现在表中,我不在乎它是否“随机”。
我尝试了以下方法:
df = df.groupby(['A', 'B', 'C']).agg('ID': 'count', 'AMT': 'sum', 'ID': 'sample')
并收到错误:
AttributeError: Cannot access callable attribute 'sample' of 'SeriesGroupBy' objects, try using the 'apply' method
于是我尝试了:
func = lambda x: x.sample
df = df.groupby(['A', 'B', 'C']).agg('ID': 'count', 'AMT': 'sum', 'ID': apply(func))
没用所以我试了
df = df.groupby(['A', 'B', 'C']).agg('ID': 'count', 'AMT': 'sum', 'ID': lambda x: x.sample)
这也不起作用。我查看了以下相关问题的链接,但它们似乎也没有帮助我。
Select multiple groups from pandas groupby object
http://pandas.pydata.org/pandas-docs/stable/groupby.html
Get specific element from Groups after applying groupby - PANDAS
How to access pandas groupby dataframe by key
https://chrisalbon.com/python/pandas_apply_operations_to_dataframes.html
关于如何处理的任何想法?
【问题讨论】:
【参考方案1】:鉴于您使用agg
进行聚合,您必须返回单个元素。所以你可以尝试使用
'ID': lambda x: x.sample.tolist()
【讨论】:
【参考方案2】:您尝试使用的代码存在一些问题。
lambda x: x.sample
返回 函数 本身而不是调用它(执行 lambda x: x.sample()
)。
x.sample()
返回一个 Series
对象。 .agg()
排除单个标量值或列表,因此会导致异常。你可以做x.sample().tolist()
,但现在你有一个列表而不是单个值。在这里使用numpy.random.choice()
更方便。
在传递给.agg()
的字典中多次指定同一列不起作用。只有最后一个会坚持。将您要用作列表或字典的函数分配给该列。
考虑到上述情况,您将得到以下解决方案:
import numpy as np
df = df.groupby(['A', 'B', 'C']).agg('ID': ('count', np.random.choice), 'AMT': 'sum')
【讨论】:
【参考方案3】:考虑示例数据框df
np.random.seed([3,1415])
df = pd.DataFrame(dict(
A=list('x'*8 + 'y'*8 + 'z'*8) * 2,
B=list('x'*4 + 'y'*4 + 'z'*4) * 4,
C=list('x'*2 + 'y'*2 + 'z'*2) * 8,
ID=range(48),
AMT=np.random.rand(48)
))
print(df)
A AMT B C ID
0 x 0.444939 x x 0
1 x 0.407554 x x 1
2 x 0.460148 x y 2
3 x 0.465239 x y 3
4 x 0.462691 y z 4
5 x 0.016545 y z 5
6 x 0.850445 y x 6
7 x 0.817744 y x 7
8 y 0.777962 z y 8
9 y 0.757983 z y 9
...
39 y 0.778883 x y 39
40 z 0.651676 y z 40
41 z 0.136097 y z 41
42 z 0.544838 y x 42
43 z 0.035073 y x 43
44 z 0.275079 z y 44
45 z 0.706685 z y 45
46 z 0.713614 z z 46
47 z 0.776050 z z 47
解决方案#1
您可以使用np.random.choice
选择一个
f = dict(
ID=dict(Count='count', Sample=np.random.choice),
AMT=dict(Sum='sum', Max='max', Min='min')
)
df.groupby(['A', 'B', 'C']).agg(f)
AMT ID
Sum Max Min Sample Count
A B C
x x x 2.458188 0.866059 0.407554 25 4
y 1.993843 0.691271 0.377185 27 4
y x 3.070036 0.850445 0.700900 7 4
z 1.139663 0.462691 0.016545 28 4
y x x 2.824838 0.926879 0.253200 13 4
y 2.166114 0.778883 0.117642 39 4
z y 2.351120 0.796487 0.018688 8 4
z 3.367248 0.934829 0.700566 10 4
z y x 1.118176 0.544838 0.035073 19 4
z 1.133523 0.651676 0.136097 16 4
z y 1.870361 0.706685 0.275079 44 4
z 2.412484 0.836997 0.085823 47 4
解决方案#2
挑选1个以上
您可以使用pd.DataFrame.sample
获取df
的整片
df.groupby(['A', 'B', 'C']).apply(pd.DataFrame.sample, n=2)
A AMT B C ID
A B C
x x x 25 x 0.866059 x x 25
0 x 0.444939 x x 0
y 26 x 0.691271 x y 26
27 x 0.377185 x y 27
y x 6 x 0.850445 y x 6
31 x 0.700946 y x 31
z 28 x 0.225146 y z 28
29 x 0.435280 y z 29
y x x 13 y 0.926879 x x 13
37 y 0.253200 x x 37
y 38 y 0.548054 x y 38
39 y 0.778883 x y 39
z y 33 y 0.018688 z y 33
32 y 0.796487 z y 32
z 11 y 0.831104 z z 11
10 y 0.934829 z z 10
z y x 42 z 0.544838 y x 42
43 z 0.035073 y x 43
z 41 z 0.136097 y z 41
17 z 0.199844 y z 17
z y 20 z 0.278735 z y 20
45 z 0.706685 z y 45
z 22 z 0.085823 z z 22
47 z 0.776050 z z 47
【讨论】:
以上是关于按列对分组数据帧进行采样的主要内容,如果未能解决你的问题,请参考以下文章