本文詳細(xì)介紹了如何在pandas中對(duì)大型數(shù)據(jù)集進(jìn)行高效的分組抽樣,特別是當(dāng)每個(gè)分組需要不同數(shù)量的樣本,并且需要根據(jù)分組大小動(dòng)態(tài)調(diào)整是否允許重復(fù)抽樣(`replace`參數(shù))時(shí)。通過(guò)構(gòu)建一個(gè)自定義函數(shù)并結(jié)合`groupby().apply()`方法,可以實(shí)現(xiàn)比傳統(tǒng)循環(huán)更優(yōu)的性能和更靈活的控制,確保抽樣邏輯的準(zhǔn)確性和效率。
在數(shù)據(jù)分析和機(jī)器學(xué)習(xí)任務(wù)中,我們經(jīng)常需要從數(shù)據(jù)集中抽取樣本。當(dāng)數(shù)據(jù)集非常龐大,并且需要根據(jù)某個(gè)或多個(gè)列進(jìn)行分組,然后對(duì)每個(gè)分組執(zhí)行抽樣時(shí),情況會(huì)變得復(fù)雜。更進(jìn)一步,如果每個(gè)分組所需的樣本數(shù)量不同,并且需要根據(jù)分組的實(shí)際大小動(dòng)態(tài)決定是否允許重復(fù)抽樣,那么傳統(tǒng)的groupby().sample()方法就顯得力不從心。
Pandas提供了DataFrame.groupby().sample(n=...)方法,可以方便地對(duì)每個(gè)分組抽取固定數(shù)量的樣本。例如:
df.groupby("a").sample(n=1, random_state=1)
然而,這個(gè)方法無(wú)法直接處理每個(gè)分組需要不同n值的情況。一種常見(jiàn)的、但效率低下的做法是遍歷每個(gè)分組,然后單獨(dú)進(jìn)行過(guò)濾和抽樣:
# 假設(shè) 'm_values' 是一個(gè)字典或列表,包含每個(gè)組 'a' 對(duì)應(yīng)的樣本數(shù)量 for group_val, m in m_values.items(): filter_df = df.loc[(df['a'] == group_val)] # ... 進(jìn)行抽樣,并根據(jù)條件設(shè)置 replace 參數(shù) # ... 最后將結(jié)果合并
這種基于循環(huán)的方法在處理?yè)碛写罅课ㄒ环纸M(例如10萬(wàn)個(gè))的大型數(shù)據(jù)集(例如9000萬(wàn)行)時(shí),會(huì)因?yàn)轭l繁的數(shù)據(jù)過(guò)濾、創(chuàng)建子DataFrame以及最終的合并操作而導(dǎo)致性能瓶頸。
此外,關(guān)于replace參數(shù)的動(dòng)態(tài)設(shè)置也是一個(gè)關(guān)鍵點(diǎn):
Pandas的groupby().apply()方法允許我們將一個(gè)自定義函數(shù)應(yīng)用到每個(gè)分組上,從而實(shí)現(xiàn)復(fù)雜的、組級(jí)別的數(shù)據(jù)操作。這是解決上述問(wèn)題的理想方案,因?yàn)樗軐ython循環(huán)的邏輯“推”到C層面執(zhí)行,從而獲得更好的性能。
首先,我們需要一個(gè)機(jī)制來(lái)告訴每個(gè)分組應(yīng)該抽取多少樣本。這通??梢酝ㄟ^(guò)一個(gè)包含分組鍵和對(duì)應(yīng)樣本數(shù)量的DataFrame來(lái)構(gòu)建,并將其轉(zhuǎn)換為字典,以便快速查找。
假設(shè)我們有一個(gè)DataFrame df1,其中包含每個(gè)組a所需的樣本數(shù)量:
import pandas as pd # df1: 定義每個(gè)組 'a' 對(duì)應(yīng)的樣本數(shù)量 df1 = pd.DataFrame({ 'a': [1, 2, 3], 'count': [1, 3, 2] }) # 將 df1 轉(zhuǎn)換為字典,方便查找 sample_counts_map = df1.set_index("a")["count"].to_dict() # sample_counts_map -> {1: 1, 2: 3, 3: 2}
接下來(lái),我們創(chuàng)建一個(gè)函數(shù),該函數(shù)將作為apply()的參數(shù),對(duì)每個(gè)分組DataFrame進(jìn)行操作。這個(gè)函數(shù)需要接收分組DataFrame、樣本數(shù)量映射字典以及隨機(jī)種子作為參數(shù)。
def get_sample(group_df, sample_counts_dict, random_state): """ 對(duì)每個(gè)分組DataFrame進(jìn)行抽樣。 根據(jù)分組鍵從 sample_counts_dict 獲取所需的樣本數(shù)量, 并根據(jù)分組大小動(dòng)態(tài)調(diào)整 replace 參數(shù)。 Args: group_df (pd.DataFrame): 當(dāng)前分組的DataFrame。 sample_counts_dict (dict): 包含每個(gè)組 'a' 對(duì)應(yīng)樣本數(shù)量的字典。 random_state (int): 隨機(jī)種子,用于保證抽樣結(jié)果的可復(fù)現(xiàn)性。 Returns: pd.DataFrame: 抽樣后的DataFrame,如果該組不需要抽樣則返回 None。 """ # 獲取當(dāng)前分組的鍵值 (例如 'a' 列的值) group_key = group_df["a"].iat[0] # iat[0] 效率更高,因?yàn)槲覀冎澜M內(nèi) 'a' 值都相同 # 從映射字典中獲取該組所需的樣本數(shù)量 n_samples = sample_counts_dict.get(group_key) # 如果該組的鍵不在映射字典中,或者 n_samples 為 None,則不進(jìn)行抽樣 if n_samples is None: return None # 動(dòng)態(tài)設(shè)置 replace 參數(shù) # 如果分組的實(shí)際記錄數(shù)小于或等于所需樣本數(shù) n_samples,則必須允許重復(fù)抽樣 (replace=True) # 否則,如果分組記錄數(shù)大于 n_samples,則不允許重復(fù)抽樣 (replace=False) allow_replace = len(group_df) <= n_samples # 執(zhí)行抽樣 return group_df.sample(n=n_samples, random_state=random_state, replace=allow_replace)
最后,我們將這個(gè)自定義函數(shù)應(yīng)用到原始DataFrame的groupby對(duì)象上。
# df2: 原始數(shù)據(jù),待抽樣 df2 = pd.DataFrame({ 'a': [1, 1, 1, 2, 2, 3, 3], 'x': ['a', 'b', 'c', 'd', 'e', 'f', 'g'] }) # 使用 groupby().apply() 進(jìn)行抽樣 # group_keys=False 可以避免在結(jié)果中添加分組鍵作為索引,提高性能 sampled_df = df2.groupby("a", group_keys=False).apply( get_sample, sample_counts_dict=sample_counts_map, random_state=6 ) 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é)果可以看出:
這完美地實(shí)現(xiàn)了我們動(dòng)態(tài)抽樣的需求。
通過(guò)利用Pandas的groupby().apply()方法結(jié)合一個(gè)精心設(shè)計(jì)的自定義抽樣函數(shù),我們可以高效地解決大型數(shù)據(jù)集上復(fù)雜的分組抽樣問(wèn)題。這種方法不僅能夠靈活地為每個(gè)分組指定不同的樣本數(shù)量,還能根據(jù)分組的實(shí)際大小智能地調(diào)整是否允許重復(fù)抽樣,從而在保證數(shù)據(jù)質(zhì)量的同時(shí),顯著提升處理效率。
以上就是Pandas大數(shù)據(jù)集分組抽樣:靈活控制每組樣本量與替換行為的詳細(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)