来自熊猫的分层样本

时间:2016-12-08 08:47:14

标签: python pandas

我有一个pandas DataFrame,大致如下:

cli_id | X1 | X2 | X3 | ... | Xn |  Y  |
----------------------------------------
123    | 1  | A  | XX | ... | 4  | 0.1 |
456    | 2  | B  | XY | ... | 5  | 0.2 |
789    | 1  | B  | XY | ... | 5  | 0.3 |
101    | 2  | A  | XX | ... | 4  | 0.1 |
...

我有客户端ID,很少有分类属性,Y是事件的概率,其值从0到1乘以0.1。

我需要在每个组中进行分层样本(10倍),大小为200

我经常使用它来分割成火车/测试时采用分层样本:

def stratifiedSplit(X,y,size):
    sss = StratifiedShuffleSplit(y, n_iter=1, test_size=size, random_state=0)

    for train_index, test_index in sss:
        X_train, X_test = X.iloc[train_index], X.iloc[test_index]
        y_train, y_test = y.iloc[train_index], y.iloc[test_index]

    return X_train, X_test, y_train, y_test

但在这种情况下我不知道如何修改它。

2 个答案:

答案 0 :(得分:13)

如果每个组的样本数相同,或者每个组的比例是恒定的,您可以尝试类似

的内容
df.groupby('Y').apply(lambda x: x.sample(n=200))

df.groupby('Y').apply(lambda x: x.sample(frac=.1))

要针对多个变量执行分层抽样,只需对更多变量进行分组。为此可能需要构造新的分箱变量。

但是,如果组的尺寸太小,w.r.t。比例如groupize 1和propotion .25,则不会返回任何项目。这是因为pythons舍入了int函数int(0.25)=0

的实现

答案 1 :(得分:4)

我不确定你的意思是:

strats = []
for k in range(11):
    y_val = k*0.1
    dummy_df = your_df[your_df['Y'] == y_val]
    stats.append( dummy_df.sample(200) )

这使得虚拟数据帧仅包含您想要的Y值,然后采样200个。

好的,所以你需要不同的块来拥有相同的结构。我想这有点困难,这就是我要做的事情:

首先,我会得到X1看起来像的直方图:

hist, edges = np.histogram(your_df['X1'], bins=np.linespace(min_x, max_x, nbins))

我们现在有一个带nbins个分区的直方图。

现在的策略是根据X1的值来绘制一定数量的行。我们将从带有更多观察值的垃圾箱中抽取更多,而用更少的垃圾箱从垃圾箱中抽取更多,以便保留X的结构。

特别是,每个垃圾箱的相对贡献应该是:

rel = [float(i) / sum(hist) for i in hist]

这类似于[0.1, 0.2, 0.1, 0.3, 0.3]

如果我们想要200个样本,我们需要绘制:

draws_in_bin = [int(i*200) for i in rel]

现在我们知道从每个垃圾箱中抽取多少观察结果:

strats = []
for k in range(11):
        y_val = k*0.1

        #get a dataframe for every value of Y
        dummy_df = your_df[your_df['Y'] == y_val]

        bin_strat = []
        for left_edge, right_edge, n_draws in zip(edges[:-1], edges[1:], draws_in_bin):

             bin_df = dummy_df[ (dummy_df['X1']> left_edge) 
                              & (dummy_df['X1']< right_edge) ]

             bin_strat.append(bin_df.sample(n_draws))
             # this takes the right number of draws out 
             # of the X1 bin where we currently are
             # Note that every element of bin_strat is a dataframe
             # with a number of entries that corresponds to the 
             # structure of draws_in_bin
        #
        #concatenate the dataframes for every bin and append to the list
        strats.append( pd.concat(bin_strat) )