[英]Sample rows of pandas dataframe in proportion to counts in a column
我有一個大型的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函數示例,但我不知道如何使用它來實現這個目標。
您可以使用groupby和sample
sample_df = df.groupby('group_id').apply(lambda x: x.sample(frac=0.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))
下面的示例共有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)
這不僅僅是分組和使用.sample
簡單。 你需要先實際獲得分數。 既然您說要獲得不同比例的行總數的10%,則需要計算每個組從主數據幀中取出的數量。 例如,如果我們使用您在問題中提到的除法,那么A
組將以1/20
表示總行數的一小部分, B
組將得到1/30
而C
組最終得到1/60
。 您可以將這些分數放在字典中,然后使用.groupby
和pd.concat
將每個組的行數*連接成一個數據幀。 您將使用.sample
方法中的n
參數而不是frac
參數。
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'))
這是為了強調滿足group_id A應該具有一半采樣行的要求的重要性,group_id B是采樣行的六分之二,group_id C是采樣行的六分之一,而不管原始組划分。
從相等的部分開始:每組從40行開始
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
第一種解決方案:A組為6行(采樣行的1/2),B組為4行(采樣行的三分之一),C組為2行(采樣行的六分之一)。
第二種解決方案:每組4行(每三個采樣行)
使用不同大小的組:A為40,B為60,C為20
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
第一種解決方案:一致的第二種解決方案:現在,B組已采用6個采樣行,而它應該只占4個。
使用另一組不同大小的組:60為A,40為B,20為C
df3 = pd.DataFrame({'group_id': np.repeat(['A', 'B', 'C'], (60, 40, 20)),
'vals': np.random.randn(120)})
N = len(df3)
print(pd.concat(dff.sample(n=int(fracs.get(i) * N)) for i,dff in df3.groupby('group_id')))
# group_id vals
# 48 A 1.214525
# 19 A -0.237562
# 0 A 3.385037
# 11 A 1.948405
# 8 A 0.696629
# 39 A -0.422851
# 62 B 1.669020
# 94 B 0.037814
# 67 B 0.627173
# 93 B 0.696366
# 104 C 0.616140
# 113 C 0.577033
print(df3.groupby('group_id').apply(lambda x: x.sample(frac=0.1)))
# group_id vals
# group_id
# A 4 A 0.284448
# 11 A 1.948405
# 8 A 0.696629
# 0 A 3.385037
# 31 A 0.579405
# 24 A -0.309709
# B 70 B -0.480442
# 69 B -0.317613
# 96 B -0.930522
# 80 B -1.184937
# C 101 C 0.420421
# 106 C 0.058900
這是第二個解決方案提供一致性的唯一時間(出於好運,我可能會補充)。
我希望這證明是有用的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.