在熊猫中阻止自举采样

时间:2018-08-01 19:46:51

标签: python pandas

我正在尝试在Pandas中实现Block Bootstrapping。

例如,假设我的DataFrame类似于:

df = pd.DataFrame({
    'personid': [1, 1, 1, 2, 2, 3, 3, 3, 3],
    'month': ['Jan', 'Feb', 'Mar', 'Aug', 'Sep', 'Mar', 'Apr', 'May', 'Jun'],
    'values': [100, 200, 300, 400, 500, 600, 700, 800, 900],
})

df
     month  personid value
0    Jan    1        100
1    Feb    1        200
2    Mar    1        300
3    Aug    2        400
4    Sep    2        500
5    Mar    3        600
6    Apr    3        700
7    May    3        800
8    Jun    3        900

尤其是,DataFame在monthpersonid处是唯一的,实际上包含许多行,其中每个personid与不同的月份关联。

我想在personid级别实现“块引导”。也就是说,我想从personid中所有唯一值的集合中进行替换采样,然后从该采样中返回一个DataFrame,其中包含所有相关的monthvalue列。 / p>

例如,我有这样的东西:

personids = df.personid.unique()

在这种情况下会导致

 array([1, 2, 3])

然后,我将替换样品:

np.random.choice(personids, size=personids.size, replace=True)

在这种情况下,这可能会导致:

array([3, 3, 2])

因此,现在,如果是得到的采样,我想要一个自举数据框,将其命名为bootstrapped_df,以使bootstrapped_df等于:

     month  personid value
0    Mar    3        600
1    Apr    3        700
2    May    3        800
3    Jun    3        900
4    Mar    3        600
5    Apr    3        700
6    May    3        800
7    Jun    3        900
8    Aug    2        400
9    Sep    2        500

到目前为止,我这样做的方式是:

def create_bootstrapped_df(df, sampled_personids):
    """
    Create "Block" Bootstrapped DataFrame given a vector of sampled_personids

    Keyword Args:
        df: DataFrame containing cost data at the personid, month level
        sampled_personids: A vector of personids that is already sampled with replacement.
    """
    bootstrapped = []
    for person in sampled_personids:
        person_df = df.loc[df.personid == person]
        bootstrapped.append(person_df)
    bootstrapped_sample = pd.concat(bootstrapped)
    bootstrapped_sample.reset_index(drop=True, inplace=True)
    return bootstrapped_sample

该函数的基本作用是循环遍历采样的Personid向量,并将原始Data Frame的子集提取出每个Personid。然后将所有内容结合在一起。恐怕这效率很低。有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

实际上,我只是想出一种非常简单的方法来做到这一点。如果我将personid设置为索引,则可以按索引将DataFrame子集化,它将完成我想要的事情。

例如,如果我这样做:

sampled_personids = np.random.choice(personids, size=personids.size, replace=True)

那让我失望

array([1, 2, 2])

然后,如果我这样做:

df.loc[sampled_personids]

我得到:

          month personid value
personid
1         Jan   1        100
1         Feb   1        200
1         Mar   1        300
2         Aug   2        400
2         Sep   2        500
2         Aug   2        400
2         Sep   2        500

答案 1 :(得分:0)

您可以使用merge。首先使用随机的bootstrapped_df创建一个personids

bootstrapped_df = pd.DataFrame({'personid':np.random.choice( personids, size=personids.size, 
                                                             replace=True)})

对我来说是

   personid
0         2
1         1
2         1

然后将merge与参数how='left'一起使用:

bootstrapped_df = bootstrapped_df.merge(df,how='left')

我得到bootstrapped_df

   personid month  values
0         2   Aug     400
1         2   Sep     500
2         1   Jan     100
3         1   Feb     200
4         1   Mar     300
5         1   Jan     100
6         1   Feb     200
7         1   Mar     300

编辑您可以在一行中完成所有操作:

bootstrapped_df = (pd.DataFrame({'personid':np.random.choice( personids, size=personids.size, 
                                                             replace=True)})
                     .merge(df,how='left'))