2017-08-03 885 views
1

问题:我有一个拥有1,000,000行的大熊猫数据框,连续(浮点)功能列为F, 0和1.在数据中,F的分布高度偏斜。如何从一个连续变量分层的Pandas数据框中分层随机抽样

我想利用从数据帧N行的随机样本(没有替换),之间加权,使得的˚F样品中的直方图将大致均匀(或尽可能接近均匀!) ˚F = 0和˚F = 1

显而易见的解决方案是

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

但这失败的错误消息,大概是因为train_test_split仅应该关于离散或分类变量进行分层。

ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of groups for any class cannot be less than 2.

理想情况下,解决方案将是快速和强大的,并作为奖金短。我最终想出了一个解决方案,包括stats.gaussian_kde来估计密度F,然后将该密度输入到bigDF.sample(weights = 1/density),但它涉及大量的手工调整,此外似乎并未实际给出完全均匀的分布。如果没有人有一个好的解决方案,我可能会试图把它写成答案。

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

回答

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() 

distribution

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

distribution after stratified

这不是完美的,但我们可以看到,我们取得了比较好的近似均匀分布。