簡體   English   中英

Pandas 分層抽樣

[英]Stratified Sampling in Pandas

我查看了Sklearn 分層抽樣文檔以及pandas 文檔以及來自 Pandas 的分層樣本基於列的 sklearn 分層抽樣,但它們沒有解決這個問題。

我正在尋找一種快速的 pandas/sklearn/numpy 方法來從數據集中生成大小為 n 的分層樣本。 但是,對於小於指定采樣數的行,它應該取所有條目。

具體例子:

在此處輸入圖像描述

謝謝: :)

將數字傳遞給樣本時,請使用min 考慮數據幀df

df = pd.DataFrame(dict(
        A=[1, 1, 1, 2, 2, 2, 2, 3, 4, 4],
        B=range(10)
    ))

df.groupby('A', group_keys=False).apply(lambda x: x.sample(min(len(x), 2)))

   A  B
1  1  1
2  1  2
3  2  3
6  2  6
7  3  7
9  4  9
8  4  8

擴展groupby答案,我們可以確保樣本是均衡的。 為此,當所有類的樣本數> = n_samples ,我們可以為所有類取n_samples (先前的答案)。 當少數類包含< n_samples ,我們可以使所有類的樣本數與少數類相同。

def stratified_sample_df(df, col, n_samples):
    n = min(n_samples, df[col].value_counts().min())
    df_ = df.groupby(col).apply(lambda x: x.sample(n))
    df_.index = df_.index.droplevel(0)
    return df_

所以我嘗試了上面的所有方法,但它們仍然不是我想要的(將解釋原因)。

第 1 步:是的,我們需要對目標變量進行groupby ,我們稱之為target_variable 所以代碼的第一部分將如下所示:
df.groupby('target_variable', group_keys=False)

我正在設置group_keys=False ,因為我不想將索引繼承到 output。

第 2 步:使用applytarget_variable中的各個類中采樣。

這是我發現上述答案不太普遍的地方。 在我的示例中,這就是我在df中擁有的 label 數字:

array(['S1','S2','normal'], dtype=object),
array([799, 2498,3716391])

所以你可以看到我的target_variable有多不平衡。 我需要做的是確保我將S1標簽的數量作為每個 class 的最小樣本數。

min(np.unique(df['target_variable'], return_counts=True))

這就是@piRSquared答案所缺乏的。 那么你要在class個數中選擇min的,這里是799 ,每個class的個數。這個不是一般規律,可以取其他數。 例如:

max(len(x), min(np.unique(data_use['snd_class'], return_counts=True)[1])

與每個 class 的數量相比,這將為您提供最小的 class 的max

他們回答中的另一個技術問題是,建議您在采樣后洗牌 output。 正如您不希望連續行中的所有S1樣本,然后是S2 ,依此類推。 你想確保你的行是隨機堆疊的。 也就是sample(frac=1)進來的時候,取1是因為我想把shuffle后的數據全部返回。 如果您出於任何原因需要更少,請隨意提供一個小數,例如0.6 ,這將返回原始樣本的 60%,洗牌。

第 3 步:最后一行對我來說是這樣的:
df.groupby('target_variable', group_keys=False).apply(lambda x: x.sample(min(len(x), min(np.unique(df['target_variable'], return_counts=True)[1]))).sample(frac=1))

我在np.unique(df['target_variable]. return_counts=True)[1]中選擇索引 1,因為這適合將每個類的編號作為numpy array 歡迎酌情修改。

以下示例總共有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)

根據用戶piRSquared的回復,我們可能有:

import pandas as pd


def stratified_sample(df: pd.DataFrame, groupby_column: str, sampling_rate: float = 0.01) -> pd.DataFrame:
    assert 0.0 < sampling_rate <= 1.0
    assert groupby_column in df.columns

    num_rows = int((df.shape[0] * sampling_rate) // 1)
    num_classes = len(df[groupby_column].unique())
    num_rows_per_class = int(max(1, ((num_rows / num_classes) // 1)))
    df_sample = df.groupby(groupby_column, group_keys=False).apply(lambda x: x.sample(min(len(x), num_rows_per_class)))

    return df_sample

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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