Python:有条件地从数据帧中选择统一样本
假设我有一个这样的数据帧Python:有条件地从数据帧中选择统一样本,python,pandas,dataframe,uniform,Python,Pandas,Dataframe,Uniform,假设我有一个这样的数据帧 category1 category2 other_col another_col .... a 1 a 2 a 2 a 3 a 3 a 1 b 10 b 10 b 10 b 11 b 11 b 11 我想从我的数据帧中获取一个样
category1 category2 other_col another_col ....
a 1
a 2
a 2
a 3
a 3
a 1
b 10
b 10
b 10
b 11
b 11
b 11
我想从我的数据帧中获取一个样本,以便category1
有统一的次数。我假设类别1
中每种类型的数量相等。我知道这可以通过pandas使用pandas.sample()
实现。然而,我还想确保我选择的样本同样具有category2
。因此,例如,如果我的样本量为5,我希望得到如下结果:
a 1
a 2
b 10
b 11
b 10
a 1
a 1
b 10
b 10
b 10
我不想要这样的东西:
a 1
a 2
b 10
b 11
b 10
a 1
a 1
b 10
b 10
b 10
虽然这是一个有效的随机样本n=4
,但它不能满足我的要求,因为我想尽量改变类别2
的类型
请注意,在第一个示例中,由于a
只采样了两次,因此3
没有从category2
中表示出来。这没关系。目标是尽可能统一地表示该样本数据
如果有助于提供一个更清晰的例子,那么可以将水果、蔬菜、肉类、谷物、垃圾分类。在10个样本中,我希望尽可能多地代表每个类别。所以理想情况下,每个都有两个。然后,属于所选类别的这两个选定行中的每一行都将具有子类别,这些子类别也将尽可能统一地表示。因此,例如,水果可以有红色水果、黄色水果等子类别。对于从10种水果中选择的2种水果类别,红色水果和黄色水果都将在样本中表示。当然,如果我们有更大的样本量,我们会包括更多的水果子类别(绿色水果、蓝色水果等)。诀窍是建立一个平衡的数组。我提供了一种笨拙的方法。然后通过引用平衡数组循环执行groupby对象采样
def rep_sample(df, col, n, *args, **kwargs):
nu = df[col].nunique()
m = len(df)
mpb = n // nu
mku = n - mpb * nu
fills = np.zeros(nu)
fills[:mku] = 1
sample_sizes = (np.ones(nu) * mpb + fills).astype(int)
gb = df.groupby(col)
sample = lambda sub_df, i: sub_df.sample(sample_sizes[i], *args, **kwargs)
subs = [sample(sub_df, i) for i, (_, sub_df) in enumerate(gb)]
return pd.concat(subs)
示范
这里有一个解决方案,它按组分层进行真正的随机抽样(不会每次都得到相同的样本,但平均得到,从统计学角度来看,这可能更好): 要测试它,请执行以下操作:
test = pd.DataFrame({'category1':[0,0,0,0,0,0,1,1,1,1,1,1],
'category2':[1,2,2,3,3,1,10,10,10,11,11,11]})
lens = []
for i in range(1000):
lens.append(
len(
stratified_sample(test, 3, ['category1','category2'])
)
)
print(np.mean(lens))
在
df.sample
中使用权重关键字时,这很简单:
>>> df.sample(n = 5, weights = (df['category2'].value_counts()/len(df['category2']))**-1)
输出:
category1 category2
2 "a" 2
1 "a" 2
10 "b" 11
3 "a" 3
11 "b" 11
为了解释,权重如下所示:
11 4.0
10 4.0
3 6.0
2 6.0
1 6.0
我只是对
df['category2']
中的每个值进行百分比计数,然后将这些值倒过来,这使得序列中所有值的权重都很均匀。那么df呢。删除重复项(子集=['category1','category2'])。示例(n=4)
?@MaxU IIUC,这将创建一个偏差,其中匹配特定对值的第一行是所选的行。我不确定这是OP想要的。嗯。。。这是一个有趣的问题…@MaxU我在想,在你的优秀评论的基础上使用df.reindex(np.random.permutation(df.index)).drop_duplicates(subset=['Category1','Category2'])sample(n=4),这是一个问题,但即使这样,如果样本大小是这样的话,比如说,某对样本中需要两个样本呢?删除重复的
使这不可能。