对pandas数据帧的行进行采样,与列中的计数成比例

时间:2017-09-03 19:04:25

标签: python pandas

我有一个大型的pandas数据框,大约有10,000,000行。每个代表一个特征向量。特征向量以自然组形式出现,组标签位于名为group_id的列中。我想随机抽样10%说明行,但与每个group_id的数量成比例。

例如,如果group_id'sA, B, A, C, A, B,那么我希望我的一半采样行拥有group_id A,其中六分之二拥有group_id B和六分之一group_id C

我可以看到pandas函数sample,但我不知道如何使用它来实现这个目标。

4 个答案:

答案 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/30C结尾。您可以将这些分数放入字典中,然后使用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)