问题:我有一个包含1,000,000行的大型Pandas数据帧,其中一个连续(浮点)功能 F 的列在0和1之间变化。 F的分布在数据中高度倾斜。
我想从数据帧中随机取样(不替换)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)
,但它涉及大量的手动调整,并且另外,似乎没有实际给出完全均匀的分布。如果没有人有一个好的解决方案,我可能会尝试将其写成答案。
有谁知道一个非常好的方法吗?
答案 0 :(得分: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()
这并不完美,但正如我们所看到的,我们得到了一个相对较好的近似均匀分布。