[英]Groupby and random sample based on a column value
我有一个 dataframe 我想按grp1, grp2
列分组,然后根据how_many
列从每个组中随机抽样。
这是我的样本数据
grp1 grp2 how_many val
0 a 1 2 2993
1 a 1 2 8244
2 a 2 1 7148
3 a 1 2 5326
4 a 3 2 5577
5 a 3 2 5651
6 a 1 2 6297
7 a 2 1 2657
8 a 2 1 9774
9 a 1 2 4075
10 a 3 2 6780
11 b 1 1 1765
12 b 1 1 5592
13 b 1 1 9936
14 b 2 4 4324
15 b 2 4 6823
16 b 2 4 9184
17 b 2 4 7498
18 b 2 4 3810
这是预期的结果(当然是随机的):
grp1 grp2 how_many val
0 a 1 2 2993
1 a 1 2 5326
2 a 2 1 9774
3 a 3 2 6780
4 a 3 2 5651
5 b 1 1 5592
6 b 2 4 6823
7 b 2 4 9184
8 b 2 4 7498
9 b 2 4 3810
我的方法是遵循这些说明,但是,就我而言,我没有稳定的样本量,它会根据列值而变化。
我还尝试在 groupby 列上使用multi_index
,但收到错误消息,指出MemoryError: Unable to allocate 107. GiB for an array with shape (57244869081,) and data type int16
。 这只是我数据的一小部分。
任何帮助,将不胜感激
如果每组的how_many
列中的值相同,则两种解决方案都有效。
使用 DataFrame.sample 创建 lambda DataFrame.sample
组调用:
df1= (df.groupby(['grp1','grp2'])
.apply(lambda x: x.sample(x['how_many'].iat[0]))
.reset_index(drop=True))
print (df1)
grp1 grp2 how_many val
0 a 1 2 2993
1 a 1 2 6297
2 a 2 1 9774
3 a 3 2 5651
4 a 3 2 5577
5 b 1 1 1765
6 b 2 4 6823
7 b 2 4 4324
8 b 2 4 7498
9 b 2 4 9184
开箱即用的解决方案以提高性能:
首先在DataFrame.sample
中通过frac=1
创建随机所有行,然后通过Series.le
创建计数器并通过GroupBy.cumcount
比较<=
,最后如果需要按组排序:
df1 = df.sample(frac=1)
df1 = df1[df1.groupby(['grp1','grp2']).cumcount().add(1).le(df1['how_many'])]
df1 = df1.sort_values(['grp1','grp2'])
print (df1)
grp1 grp2 how_many val
0 a 1 2 2993
1 a 1 2 8244
2 a 2 1 7148
5 a 3 2 5651
4 a 3 2 5577
13 b 1 1 9936
16 b 2 4 9184
17 b 2 4 7498
15 b 2 4 6823
14 b 2 4 4324
详情:
首先是随机更改的列顺序:
df1 = df.sample(frac=1)
print (df1)
grp1 grp2 how_many val
15 b 2 4 6823
18 b 2 4 3810
10 a 3 2 6780
11 b 1 1 1765
14 b 2 4 4324
2 a 2 1 7148
16 b 2 4 9184
7 a 2 1 2657
9 a 1 2 4075
1 a 1 2 8244
13 b 1 1 9936
17 b 2 4 7498
8 a 2 1 9774
4 a 3 2 5577
12 b 1 1 5592
0 a 1 2 2993
5 a 3 2 5651
6 a 1 2 6297
3 a 1 2 5326
然后为每个组创建计数器并按掩码过滤-按列比较how_many
返回第一行,但因为随机更改的顺序返回随机行:
print (df1.assign(counter=df1.groupby(['grp1','grp2']).cumcount().add(1),
mask=df1.groupby(['grp1','grp2']).cumcount().add(1).le(df1['how_many'])))
grp1 grp2 how_many val counter mask
15 b 2 4 6823 1 True
18 b 2 4 3810 2 True
10 a 3 2 6780 1 True
11 b 1 1 1765 1 True
14 b 2 4 4324 3 True
2 a 2 1 7148 1 True
16 b 2 4 9184 4 True
7 a 2 1 2657 2 False
9 a 1 2 4075 1 True
1 a 1 2 8244 2 True
13 b 1 1 9936 2 False
17 b 2 4 7498 5 False
8 a 2 1 9774 3 False
4 a 3 2 5577 2 True
12 b 1 1 5592 3 False
0 a 1 2 2993 3 False
5 a 3 2 5651 3 False
6 a 1 2 6297 4 False
3 a 1 2 5326 5 False
过滤:
df1 = df1[df1.groupby(['grp1','grp2']).cumcount().add(1).le(df1['how_many'])]
print (df1)
grp1 grp2 how_many val
15 b 2 4 6823
18 b 2 4 3810
10 a 3 2 6780
11 b 1 1 1765
14 b 2 4 4324
2 a 2 1 7148
16 b 2 4 9184
9 a 1 2 4075
1 a 1 2 8244
4 a 3 2 5577
如有必要,排序:
df1 = df1.sort_values(['grp1','grp2'])
print (df1)
grp1 grp2 how_many val
9 a 1 2 4075
1 a 1 2 8244
2 a 2 1 7148
10 a 3 2 6780
4 a 3 2 5577
11 b 1 1 1765
15 b 2 4 6823
18 b 2 4 3810
14 b 2 4 4324
16 b 2 4 9184
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.