Python:每个组的随机选择

Python:每个组的随机选择,python,random,pandas,Python,Random,Pandas,假设我有一个数据帧,看起来像: Name Group_Id AAA 1 ABC 1 CCC 2 XYZ 2 DEF 3 YYH 3 如何为每个组Id随机选择一行(或多行)?假设我希望每个组Id随机抽取一次,我会得到: Name Group_Id AAA 1 XYZ 2 DEF 3 使用random.choice,您可以执行以下操作: import random name_group = {'AAA': 1, 'ABC':1, 'CCC':2, 'XYZ':2, 'DEF'

假设我有一个数据帧,看起来像:

Name Group_Id
AAA  1
ABC  1
CCC  2
XYZ  2
DEF  3 
YYH  3
如何为每个
组Id
随机选择一行(或多行)?假设我希望每个
组Id
随机抽取一次,我会得到:

Name Group_Id
AAA  1
XYZ  2
DEF  3

使用
random.choice
,您可以执行以下操作:

import random
name_group = {'AAA': 1, 'ABC':1, 'CCC':2, 'XYZ':2, 'DEF':3, 'YYH':3}

names = [name for name in name_group.iterkeys()] #create a list out of the keys in the name_group dict

first_name = random.choice(names)
first_group = name_group[first_name]
print first_name, first_group
random.choice(seq)


您可以使用、和的组合:

输出:

   Group_ID Name
0         1  AAA
1         2  XYZ
2         3  DEF

在优雅的一行中使用groupby和random.choice:

df.groupby('Group_Id').apply(lambda x :x.iloc[random.choice(range(0,len(x)))])

From
0.16.x
提供了一种从对象轴返回项目随机样本的方法

In [664]: df.groupby('Group_Id').apply(lambda x: x.sample(1)).reset_index(drop=True)
Out[664]:
  Name  Group_Id
0  ABC         1
1  XYZ         2
2  DEF         3

对于每个组只随机选择一行,请尝试
df.sample(frac=1.0).groupby('group_Id').head(1)

有两种方法可以非常简单地做到这一点,一种方法不使用任何基本语法:

df[['x','y']].groupby('x').agg(pd.DataFrame.sample)
对于50k行数据集,这需要14.4ms

另一个稍微快一点的方法是numpy

df[['x','y']].groupby('x').agg(np.random.choice)
对于(相同的)50k行数据集,这需要10.9ms的时间

一般来说,在使用pandas时,最好坚持其本机语法。特别是初学者

一种非常奇怪的方式:

takesamp = lambda d: d.sample(n)
df = df.groupby('Group_Id').apply(takesamp)

如果一个组的样本少于所需的样本量
n
,则提供的解决方案将失败。这解决了这个问题:

n = 10
df.groupby('Group_Id').apply(lambda x: x.sample(min(n,len(x)))).reset_index(drop=True)
我找到了另一个:

size=2
count_s = df['Id'].value_counts()
df.iloc[np.concatenate([previous_count + np.random.choice(count, size) 
                        for count, previous_count in zip(count_s, 
                                                         count_s.shift(fill_value=0))])]
版本1.1.0中的新功能。

set replace=False,如果不希望每个组两次获得相同的行。如果使用时间戳列创建基于频率的pd.Grouper(),则建议的方法将生成两个同名的时间戳索引列。不太理想的情况。下面我发布了一个更简单(代码更少,更容易记住,一般来说复杂性更低)的方法来做同样的事情。
random.choice(range(0,len(x))
最好写为
np.random.randint(0,len(x))
有些人可能稍微倾向于使用numpy.random.choice,这允许您指定a)要从总体中采集的样本数量和b)是否需要替换<代码>df.sample(frac=1.0)。groupby('Group_Id')。头(1)太多了faster@ihadanny”的建议更为“泛泛”,也可推广到n>1,尽管这是最泛泛的答案,但它如何可能推广到每组抽样
n
项目?:-)@matanster
agg
对我不起作用,但
apply
起作用。它还可以接受函数的参数:
df[['x','y']].groupby('x').apply(pd.DataFrame.sample,n=n,replace=False)
。请参见文档。此方法将从每个组的每个列中进行不同的随机选择,而不是选择每个组中的整行。来自@ihadanny的答案将选择整行,而且速度更快。或者:
df.groupby('Group\u Id')。apply(pd.DataFrame.sample,n=1)。reset\u index(drop=True)
这是最快的答案,可用于选择跨多列的行。
takesamp = lambda d: d.sample(n)
df = df.groupby('Group_Id').apply(takesamp)
n = 10
df.groupby('Group_Id').apply(lambda x: x.sample(min(n,len(x)))).reset_index(drop=True)
size=2
count_s = df['Id'].value_counts()
df.iloc[np.concatenate([previous_count + np.random.choice(count, size) 
                        for count, previous_count in zip(count_s, 
                                                         count_s.shift(fill_value=0))])]
df.groupby('Group_Id').sample(n=1)