本文深入探討了在pandas中對(duì)大型數(shù)據(jù)集進(jìn)行分組采樣的高效方法。針對(duì)傳統(tǒng)`groupby().sample()`無法滿足各組不同采樣數(shù)量`n`以及動(dòng)態(tài)替換策略(`replace=true/false`)的需求,我們提出并詳細(xì)解釋了如何利用`groupby().apply()`結(jié)合自定義函數(shù)來實(shí)現(xiàn)這一復(fù)雜采樣邏輯,顯著提升了處理效率和代碼可讀性,適用于大規(guī)模數(shù)據(jù)場(chǎng)景。
在數(shù)據(jù)分析中,我們經(jīng)常需要對(duì)數(shù)據(jù)集進(jìn)行分組(groupby)操作,并從每個(gè)組中抽取一定數(shù)量的樣本。然而,當(dāng)每個(gè)組所需的樣本數(shù)量n不同,并且采樣是否需要替換(replace)也依賴于組的原始大小時(shí),標(biāo)準(zhǔn)的df.groupby("col").sample(n=...)方法就顯得力不從心了。對(duì)于大型數(shù)據(jù)集,簡(jiǎn)單的循環(huán)遍歷和過濾操作會(huì)導(dǎo)致性能瓶頸。本教程將介紹一種高效且靈活的解決方案,利用groupby().apply()結(jié)合自定義函數(shù)來解決這一挑戰(zhàn)。
假設(shè)我們有一個(gè)包含數(shù)千萬甚至上億條記錄的大型數(shù)據(jù)集df_main,其中包含一個(gè)分組列a(具有大量唯一值,例如10萬個(gè))。我們還有一個(gè)輔助數(shù)據(jù)集df_sample_counts,它指定了列a中每個(gè)唯一值應(yīng)該采樣多少條記錄。此外,采樣規(guī)則要求:
傳統(tǒng)的df.groupby("a").sample(n=1)只能對(duì)所有組應(yīng)用相同的n值。而通過循環(huán)遍歷每個(gè)組并單獨(dú)采樣,雖然能實(shí)現(xiàn)功能,但在處理大數(shù)據(jù)集時(shí)效率低下,無法滿足生產(chǎn)環(huán)境的需求。
Pandas的groupby().apply()方法為執(zhí)行復(fù)雜的組級(jí)操作提供了強(qiáng)大的靈活性。我們可以定義一個(gè)自定義函數(shù),該函數(shù)將接收每個(gè)分組的DataFrame作為輸入,并在其中實(shí)現(xiàn)動(dòng)態(tài)采樣邏輯。
首先,我們創(chuàng)建兩個(gè)示例DataFrame,模擬原始數(shù)據(jù)和采樣數(shù)量配置。
import pandas as pd import numpy as np # 模擬采樣數(shù)量配置 DataFrame (df1) data_counts = {'a': [1, 2, 3], 'count': [1, 3, 2]} df1 = pd.DataFrame(data_counts) print("df1 (采樣數(shù)量配置):") print(df1) print("-" * 30) # 模擬原始數(shù)據(jù) DataFrame (df2) data_original = {'a': [1, 1, 1, 2, 2, 3, 3], 'x': ['a', 'b', 'c', 'd', 'e', 'f', 'g']} df2 = pd.DataFrame(data_original) print("df2 (原始數(shù)據(jù)):") print(df2)
輸出示例:
df1 (采樣數(shù)量配置): a count 0 1 1 1 2 3 2 3 2 ------------------------------ df2 (原始數(shù)據(jù)): a x 0 1 a 1 1 b 2 1 c 3 2 d 4 2 e 5 3 f 6 3 g
為了在自定義函數(shù)中高效地獲取每個(gè)組的采樣數(shù)量n,我們將df1轉(zhuǎn)換為一個(gè)字典,其中鍵是分組列a的值,值是對(duì)應(yīng)的采樣數(shù)量count。
sample_counts_dict = df1.set_index("a")["count"].to_dict() print("\n采樣數(shù)量查找字典:") print(sample_counts_dict)
輸出示例:
采樣數(shù)量查找字典: {1: 1, 2: 3, 3: 2}
這個(gè)函數(shù)將是解決方案的核心。它接收一個(gè)分組的DataFrame (df_group),查找字典 (dct) 和一個(gè)隨機(jī)種子 (random_state)。
def get_sample(df_group, dct, random_state): # 獲取當(dāng)前組的分組鍵 'a' 的值 # df_group["a"].iat[0] 比 df_group["a"].iloc[0] 更快,因?yàn)樗苯釉L問底層數(shù)組 group_key = df_group["a"].iat[0] # 從字典中獲取當(dāng)前組的采樣數(shù)量 n n_samples = dct.get(group_key) # 如果字典中沒有對(duì)應(yīng)的采樣數(shù)量,則不進(jìn)行采樣,返回None if n_samples is None: return None # 或返回一個(gè)空的DataFrame,取決于具體需求 # 根據(jù)組的實(shí)際大小和所需的采樣數(shù)量 n_samples 決定 replace 參數(shù) # 如果組的大小小于或等于 n_samples,則允許替換 (replace=True) # 否則,不允許替換 (replace=False) replace_flag = len(df_group) <= n_samples # 執(zhí)行采樣操作 return df_group.sample(n=n_samples, random_state=random_state, replace=replace_flag)
函數(shù)邏輯詳解:
現(xiàn)在,我們將自定義函數(shù)get_sample應(yīng)用到df2的groupby("a")結(jié)果上。
# 使用 groupby().apply() 進(jìn)行分組采樣 # group_keys=False 可以避免在結(jié)果中添加分組鍵作為額外的索引層,提高效率 sampled_df = df2.groupby("a", group_keys=False).apply( get_sample, dct=sample_counts_dict, random_state=6 # 保持隨機(jī)性可復(fù)現(xiàn) ) print("\n最終采樣結(jié)果:") print(sampled_df)
輸出示例:
最終采樣結(jié)果: a x 0 1 a 3 2 d 4 2 e 4 2 e 5 3 f 6 3 g
從結(jié)果可以看出:
通過結(jié)合使用Pandas的groupby().apply()方法和精心設(shè)計(jì)的自定義函數(shù),我們能夠優(yōu)雅且高效地解決在大型數(shù)據(jù)集中進(jìn)行復(fù)雜分組采樣的問題。這種方法不僅能夠靈活地處理每個(gè)組不同的采樣數(shù)量n,還能根據(jù)組的實(shí)際大小動(dòng)態(tài)調(diào)整采樣時(shí)的替換策略,從而滿足多樣化的數(shù)據(jù)分析需求,同時(shí)保持代碼的清晰性和可維護(hù)性。
以上就是Pandas中基于組的靈活采樣:實(shí)現(xiàn)不同n值與動(dòng)態(tài)替換策略的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個(gè)人都需要一臺(tái)速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊(cè)表數(shù)據(jù)和不必要的后臺(tái)進(jìn)程會(huì)占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號(hào)
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號(hào)