我有一个大型的pandas数据框,大约有10,000,000行。每个代表一个特征向量。特征向量以自然组形式出现,组标签位于名为group_id
的列中。我想随机抽样10%
说明行,但与每个group_id
的数量成比例。
例如,如果group_id's
为A, B, A, C, A, B
,那么我希望我的一半采样行拥有group_id
A
,其中六分之二拥有group_id
B
和六分之一group_id
C
。
我可以看到pandas函数sample,但我不知道如何使用它来实现这个目标。
答案 0 :(得分:8)
您可以使用groupby和sample
sample_df = df.groupby('group_id').apply(lambda x: x.sample(frac=0.1))
答案 1 :(得分:1)
这不仅仅是分组和使用.sample
这么简单。你需要先实际获得分数。既然您说要获得不同比例的行总数的10%,则需要计算每个组从主数据帧中取出的数量。例如,如果我们使用您在问题中提到的差异,则组A
将以1/20
结尾,只占总行数的一小部分,组B
将获得{{} 1}}和群组1/30
以C
结尾。您可以将这些分数放入字典中,然后使用1/60
和.groupby
将每个组中的行数* 连接到数据框中。您将使用pd.concat
方法中的n
参数代替.sample
参数。
frac
这是为了强调满足group_id A应该有一半 采样行 的要求的重要性,group_id B是 的六分之二采样行 和group_id C 采样行的六分之一 ,无论原始组划分如何。
从等份开始:每组以40行开头
fracs = {'A': 1/20, 'B': 1/30, 'C': 1/60}
N = len(df)
pd.concat(dff.sample(n=int(fracs.get(i)*N)) for i,dff in df.groupby('group_id'))
第一种解决方案:A组为6行(采样行的1/2),B组为4行(采样行的三分之一),C组为2行(采样行的六分之一)。 / p>
第二个解决方案:每组4行(每个采样行的三分之一)
使用不同大小的组:40为A,60为B,20为C
df1 = pd.DataFrame({'group_id': ['A','B', 'C']*40,
'vals': np.random.randn(120)})
N = len(df1)
fracs = {'A': 1/20, 'B': 1/30, 'C': 1/60}
print(pd.concat(dff.sample(n=int(fracs.get(i) * N)) for i,dff in df1.groupby('group_id')))
# group_id vals
# 12 A -0.175109
# 51 A -1.936231
# 81 A 2.057427
# 111 A 0.851301
# 114 A 0.669910
# 60 A 1.226954
# 73 B -0.166516
# 82 B 0.662789
# 94 B -0.863640
# 31 B 0.188097
# 101 C 1.802802
# 53 C 0.696984
print(df1.groupby('group_id').apply(lambda x: x.sample(frac=0.1)))
# group_id vals
# group_id
# A 24 A 0.161328
# 21 A -1.399320
# 30 A -0.115725
# 114 A 0.669910
# B 34 B -0.348558
# 7 B -0.855432
# 106 B -1.163899
# 79 B 0.532049
# C 65 C -2.836438
# 95 C 1.701192
# 80 C -0.421549
# 74 C -1.089400
第一个解决方案:一致 第二个解决方案:现在B组已经采集了6个采样行,而它们只能采用4个。
使用另一组不同大小的组:60为A,40为B,20为C
df2 = pd.DataFrame({'group_id': np.repeat(['A', 'B', 'C'], (40, 60, 20)),
'vals': np.random.randn(120)})
N = len(df2)
print(pd.concat(dff.sample(n=int(fracs.get(i) * N)) for i,dff in df2.groupby('group_id')))
# group_id vals
# 29 A 0.306738
# 35 A 1.785479
# 21 A -0.119405
# 4 A 2.579824
# 5 A 1.138887
# 11 A 0.566093
# 80 B 1.207676
# 41 B -0.577513
# 44 B 0.286967
# 77 B 0.402427
# 103 C -1.760442
# 114 C 0.717776
print(df2.groupby('group_id').apply(lambda x: x.sample(frac=0.1)))
# group_id vals
# group_id
# A 4 A 2.579824
# 32 A 0.451882
# 5 A 1.138887
# 17 A -0.614331
# B 47 B -0.308123
# 52 B -1.504321
# 42 B -0.547335
# 84 B -1.398953
# 61 B 1.679014
# 66 B 0.546688
# C 105 C 0.988320
# 107 C 0.698790
这是第二个解决方案提供一致性的唯一时间(出于好运,我可能会补充)。
我希望这证明有用。
答案 2 :(得分:1)
我正在寻找类似的解决方案。 @Vaishali提供的代码绝对可以正常工作。当我们要根据每个样本与完整数据的比例从每个组中提取样本时,@ Abdou所做的尝试也很有意义。
# original : 10% from each group
sample_df = df.groupby('group_id').apply(lambda x: x.sample(frac=0.1))
# modified : sample size based on proportions of group size
n = df.shape[0]
sample_df = df.groupby('group_id').apply(lambda x: x.sample(frac=length(x)/n))
答案 3 :(得分:1)
以下示例总共N行,其中每个组以其原始比例出现在最接近的整数处,然后随机播放并重置索引 使用:
df = pd.DataFrame(dict(
A=[1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4],
B=range(20)
))
又甜又甜:
df.sample(n=N, weights='A', random_state=1).reset_index(drop=True)
长版
df.groupby('A', group_keys=False).apply(lambda x: x.sample(int(np.rint(N*len(x)/len(df))))).sample(frac=1).reset_index(drop=True)