[英]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_
所以我嘗試了上面的所有方法,但它們仍然不是我想要的(將解釋原因)。
groupby
,我們稱之為target_variable
。 所以代碼的第一部分將如下所示:df.groupby('target_variable', group_keys=False)
我正在設置group_keys=False
,因為我不想將索引繼承到 output。
apply
從target_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%,洗牌。
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.