我有一个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>适用于Group1
和2
。
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组,我不确定什么是没有替换的最佳采样方法。
答案 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的解决方案。