【问题标题】:Pandas groupby for k-fold cross-validation with aggregationPandas groupby 用于聚合的 k 折交叉验证
【发布时间】:2014-09-19 20:54:12
【问题描述】:

假设我有一个数据框 df,列:id |site|时间|点击|展示次数

我想使用 k 折交叉验证的机器学习技术(将数据随机分成 k=10 个相等大小的分区 - 基于例如列 id)。我认为这是来自 id: {0,1,...9} 的映射(所以新列“折叠”从 0-9 开始) 然后迭代地将 9/10 分区作为训练数据,将 1/10 分区作为验证数据 (所以首先 fold==0 是验证,rest 是训练,然后 fold==1,rest 是训练) [所以我认为这是一个基于折叠列分组的生成器]

最后我想按站点和时间对所有训练数据进行分组(验证数据也是如此)(换句话说,对折叠索引求和,但保留站点和时间索引)

在 pandas 中这样做的正确方法是什么?

我现在想到的做法是

df_sum=df.groupby( 'fold','site','time').sum() 
#so df_sum has indices fold,site, time 
# create new Series object,dat, name='cross'  by mapping fold indices 
# to      'training'/'validation'
df_train_val=df_sum.groupby( [ dat,'site','time']).sum()
df_train_val.xs('validation',level='cross')

现在我遇到的直接问题是带有列的 groupby 将处理引入 Series 对象,但 multiindices 上的 groupby 不起作用 [上面的 df_train_val 分配不起作用]。显然我可以使用reset_index,但考虑到我想对站点和时间进行分组[例如聚合1到9的折叠],这似乎是错误的。 (我认为索引上的分组比“原始”列上的分组要快得多)

所以问题 1 这是在 pandas 中进行交叉验证和聚合的正确方法。更一般地,根据多索引值进行分组,然后重新分组。

问题 2 - 有没有一种将任意映射与多级索引混合的方法。

【问题讨论】:

  • Sci-kit learn 有一个k-fold 方法与pandas 兼容,除非你有sci-kit learn 的实现不满足的需求,否则不需要自己实现
  • 好吧,我没有使用 sci-kit learn,问题不在于实现 k-fold,而在于执行 k-fold 后的聚合步骤:df_train_val 分配。我相信这些数据处理操作在 pandas 中比 scikit-learn 更容易、更快。例如,我可以先在 scikit-learn 中进行 k-fold,然后按其他变量分组。但随后我将每个折叠的数据 [wrt site & time] 分组。按折叠、站点、时间分组一次然后按折叠 0...9 重新分配到“训练”或“验证”似乎更有效
  • 首先分组然后 k-fold 更有意义,是的,索引分组应该更快,但是,根据您的组的大小和分布,您可能会发现它非常慢。这是我在处理大型数据集时的经验,无论如何它可能对您的数据集没问题我认为您的方法是合理的

标签: pandas group-by


【解决方案1】:

这个生成器似乎可以做我想做的事。您传入分组数据(1 个索引对应于折叠 [0 到 n_folds])。

def split_fold2(fold_data, n_folds, new_fold_col='fold'):
    i_fold=0
    indices=list(fold_data.index.names)
    slicers=[slice(None)]*len(fold_data.index.names)
    fold_index=fold_data.index.names.index(new_fold_col)
    indices.remove(new_fold_col)

    while (i_fold<n_folds):
        slicers[fold_index]=[i for i in range(n_folds) if i !=i_fold]
        slicers_tuple=tuple(slicers)
        train_data=fold_data.loc[slicers_tuple,:].groupby(level=indices).sum()
        val_data=fold_data.xs(i_fold,level=new_fold_col)
        yield train_data,val_data
        i_fold+=1

在我的数据集上,这需要:

CPU times: user 812 ms, sys: 180 ms, total: 992 ms  Wall time: 991 ms 

(取回一倍) 将 train_data 分配替换为 train_data=fold_data.select(lambda x: x[fold_index]!=i_fo​​ld).groupby(level=indices).sum() 需要

CPU times: user 2.59 s, sys: 263 ms, total: 2.85 s Wall time: 2.83 s

【讨论】:

    猜你喜欢
    • 2016-01-15
    • 2020-11-30
    • 1970-01-01
    • 2016-02-17
    • 2019-12-18
    • 2020-08-29
    • 2018-08-29
    • 2017-06-09
    • 2017-07-02
    相关资源
    最近更新 更多