如何从按连续变量分层的 Pandas 数据框中获取分层随机样本

Posted

技术标签:

【中文标题】如何从按连续变量分层的 Pandas 数据框中获取分层随机样本【英文标题】:How do you take a stratified random sample from a Pandas dataframe that stratifies by a continuous variable 【发布时间】:2018-01-11 05:03:16 【问题描述】:

问题:我有一个包含 1,000,000 行的大型 Pandas 数据框,其中有一列用于连续(浮点)特征 F,该特征在 0 和 1 之间变化。F 的分布em> 在数据中高度倾斜。

我想从数据帧中抽取 N 行的随机样本(不替换),加权以使样本中 F 的直方图大致均匀(或尽可能接近均匀) !) 在 F = 0 和 F = 1 之间。

显而易见的解决方案是

_ , sampleDF = train_test_split(bigDF, test_size = N, stratify = bigDF['F'] )

但这会失败并显示错误消息,大概是因为 train_test_split 只应该针对离散或分类变量进行分层。

ValueError: y 中人口最少的类只有 1 个成员,太少了。任何类的最小组数不能少于 2 个。

理想情况下,此问题的解决方案将是快速且强大的,并且作为奖励短。我最终想出了一个涉及stats.gaussian_kde 的解决方案来估计F 的密度,然后将该密度提供给bigDF.sample(weights = 1/density),但它涉及很多手动调整,此外还没有t 似乎实际上给出了完全均匀的分布。如果没有人有好的解决方案,我可能会尝试将其写下来作为答案。

有没有人知道一个非常好的方法来做到这一点?

【问题讨论】:

【参考方案1】:

您将需要这些导入:

from scipy.stats import gaussian_kde
import numpy as np

这是我目前正在使用的功能:

def samplestrat(df, stratifying_column_name, num_to_sample, maxrows_to_est = 10000, bw_per_range = 50, eval_points = 1000 ):
    '''Take a sample of dataframe df stratified by stratifying_column_name
    '''
    strat_col_values = df[stratifying_column_name].values
    samplcol = (df.sample(maxrows_to_est)  if df.shape[0] > maxrows_to_est else df  )[stratifying_column_name].values
    vmin, vmax = min(samplcol), max(samplcol)
    pts = np.linspace(vmin,vmax  ,eval_points) 
    kernel = gaussian_kde( samplcol , bw_method = float(  (vmax - vmin)/bw_per_range  )   )
    density_estim_full = np.interp(strat_col_values, pts , kernel.evaluate(pts) )
    return df.sample(n=num_to_sample, weights = 1/(density_estim_full))

对一些合成数据进行测试:

def sigmoid(x,mi, mx): return mi + (mx-mi)*(lambda t: (1+200**(-t+0.5))**(-1) )( (x-mi)/(mx-mi) )
toyDF = pd.DataFrame( data =  sigmoid(np.random.normal(loc = 10.0, scale = 1.0, size = 10000) , 7 , 13)  ,  columns=['val']  )
pd.DataFrame.hist(toyDF, column = 'val', bins =20 )
plt.show()

df_stratified_sample = samplestrat(toyDF, 'val', 1500 )
pd.DataFrame.hist(df_stratified_sample, column = 'val', bins =20 )
plt.show()

这并不完美,但正如我们所见,我们得到了一个相对较好的均匀分布近似值。

【讨论】:

以上是关于如何从按连续变量分层的 Pandas 数据框中获取分层随机样本的主要内容,如果未能解决你的问题,请参考以下文章

计算数据框中的连续值并获取发生这种情况的索引

减去 Pandas 或 Pyspark 数据框中的连续列

对 pandas 数据框中的连续值进行分组

Pandas 从分组数据框中计算连续相等值的长度

如何从 imdb 获取更多信息并将其保存在 pandas 数据框中? [复制]

如何将分层表转换为json