簡體   English   中英

對pandas數據幀的行進行采樣,與列中的計數成比例

[英]Sample rows of pandas dataframe in proportion to counts in a column

我有一個大型的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函數示例,但我不知道如何使用它來實現這個目標。

您可以使用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/30C組最終得到1/60 您可以將這些分數放在字典中,然后使用.groupbypd.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM