在pd.DataFrame中创建三个样本组

时间:2016-10-30 18:42:20

标签: python pandas dataframe

我有一个pd.DataFrame,其结构与下面的示例类似:

index  x     y     z
0      x0    y0    None
1      x1    y1    None
2      x2    y2    None
3      x3    y3    None
4      x4    y4    None
5      x5    y5    None
6      x6    y6    None

我的目标是创建3个DataFrame子集:

  • Group1是一个训练集,可用于训练模型以 x y 预测 z ;
  • Group2是一个验证集,用于评估在Group1中训练的模型(或不同模型/参数调整)的准确性,我将填写的正确值z {/ em>适用于Group12

  • Group3一直保持到选择模型来预测 z

在这种情况下,进行作业的最有效方法是什么?我在考虑在一个DataFrame中创建子组,如下所示:

index  x     y     z       group
- - - - - - - - - - - - - - - - - - - - 
0      x0    y0    None    training
1      x1    y1    None    validation
2      x2    y2    None    held out
3      x3    y3    None    held out
4      x4    y4    None    validation
5      x5    y5    None    training
6      x6    y6    None    held out

但我看到elsewhere随机分配的提示通常会创建一个新的DataFrame。是因为这更可行吗?

rows = np.random.choice(df.index.values, 10)
sampled_df = df.ix[rows]

另外,由于我想一次抽样3组而不是2组,我不确定什么是没有替换的最佳采样方法。

1 个答案:

答案 0 :(得分:2)

您可以使用

df['group'] = np.random.choice(
    np.repeat(['training', 'validation', 'held out'], (2,2,3)), len(df), replace=False)

为每行分配training/validation/held out标签。 (2,2,3) 以上表示您希望拥有的每种类型的行数。由于每一行 应该得到一个标签,元组的总和应该等于len(df)

分配标签比创建子数据框更好吗?

如果您指定了标签,则最终会得到如下代码:

df['group'] = np.random.choice(
    np.repeat(['training', 'validation', 'held out'], (2,2,3)), len(df), replace=False)
goodness = dict()
params = dicts()
for model in models: 
    params[model] = fit(model, df.loc[df['group'] == 'train'])
    goodness[model] = validate(model, params[model], df.loc[df['group'] == 'validation'])
best_model = max(models, key=goodness.get)
result = process(best_model, params[best_model], df.loc[df['group'] == 'held_out'])

如果您拆分df(使用MaxU's solution),您最终会得到以下代码:

train, validate, held_out = np.split(df.sample(frac=1), [2,4])
goodness = dict()
params = dicts()
for model in models: 
    params[model] = fit(model, train)
    goodness[model] = validate(model, params[model], validate)
best_model = max(models, key=goodness.get)
result = process(best_model, params[best_model], held_out)

每次Python遇到df['group'] == 'train'时,整个系列 扫描df['group'] - O(N)操作。 df.loc[f['group'] == 'train'] 然后从df复制行以形成新的子DataFrame。因为这是在一个完成 循环,for model in models,并为每个循环完成两次,这个O(N) 操作执行2*len(model)次。

相反,如果您在开始时拆分DataFrame,那么复制 只做一次。所以MaxU的代码更快。

另一方面,使用标签按需创建子DataFrames将保存 因为你没有实例化所有三个子数据框,所以有点内存 一旦。但是,除非你对记忆非常紧张,否则你可能想要更快 代码比更高效的内存代码。因此,如果是这种情况,请使用MaxU's solution

当然,您可以使用

df['group'] = np.random.choice(
    np.repeat(['training', 'validation', 'held out'], (2,2,3)), len(df), replace=False)
train, validate, held_out = [df.loc[df['group'] == label] for label in ['train', 'validation', 'held out']]

而不是

train, validate, held_out = np.split(df.sample(frac=1), [2,4])

但这样做也没有速度或内存优势。你' d 仍然是从DataFrame扫描和复制三次而不是一次。所以 应该首选MaxU的解决方案。