按行索引拆分DataFrame为训练/验证/测试集时遇问题
解决按行循环拆分DataFrame为训练/验证/测试集的问题
看起来你想按行的顺序依次把数据分配到训练、验证、测试集(第1条去训练,第2条去验证,第3条去测试,然后循环重复),但目前的代码有几个关键问题,我来帮你修正:
你的代码存在的问题
- 条件逻辑错误:你用了
i%2和i%3的组合,这完全不符合“依次分配”的需求,会导致数据分配混乱(比如某些行可能被同时分到多个集合,或者漏分)。 - DataFrame.append用法错误:Pandas的
append方法需要传入行数据(比如dfClimbing.iloc[i:i+1]),而且它不会原地修改DataFrame,需要重新赋值给变量;另外直接append整数i是完全错误的,你需要添加的是DataFrame的行,不是索引数字。 - 效率低下:循环逐行添加到空DataFrame的方式在数据量大时会很慢,Pandas更推荐用批量筛选的方式。
正确的实现方式
方法1:符合你思路的循环修正版
如果你坚持用循环的方式,修正后的代码如下:
import pandas as pd # 假设dfClimbing是你的原始DataFrame climbingTngDataset = pd.DataFrame([]) climbingValDataset = pd.DataFrame([]) climbingTestDataset = pd.DataFrame([]) for i in range(len(dfClimbing)): # 按索引模3的结果分配:0→训练,1→验证,2→测试 if i % 3 == 0: # 选取第i行,注意iloc[i:i+1]返回的是DataFrame,不是Series climbingTngDataset = pd.concat([climbingTngDataset, dfClimbing.iloc[i:i+1]], ignore_index=True) elif i % 3 == 1: climbingValDataset = pd.concat([climbingValDataset, dfClimbing.iloc[i:i+1]], ignore_index=True) else: climbingTestDataset = pd.concat([climbingTestDataset, dfClimbing.iloc[i:i+1]], ignore_index=True)
注意:Pandas已经弃用了
append方法,推荐用pd.concat来合并DataFrame,而且每次合并后要重新赋值给变量,因为concat不会修改原对象。
方法2:更高效的Pandas批量筛选(推荐)
循环逐行处理效率很低,尤其是数据量大的时候,用索引筛选的方式更简洁高效:
import pandas as pd # 生成每个行的分配标签 dfClimbing['split'] = dfClimbing.index % 3 # 批量筛选得到三个数据集 climbingTngDataset = dfClimbing[dfClimbing['split'] == 0].drop('split', axis=1).reset_index(drop=True) climbingValDataset = dfClimbing[dfClimbing['split'] == 1].drop('split', axis=1).reset_index(drop=True) climbingTestDataset = dfClimbing[dfClimbing['split'] == 2].drop('split', axis=1).reset_index(drop=True)
这个方法先给每行添加一个split标签(0/1/2对应训练/验证/测试),然后通过布尔索引批量筛选,最后删除临时的split列并重置索引,比循环快得多。
补充说明
如果你说的“第1条观测”是指从显示的第1行开始计数(而非默认的索引0),只需要调整标签生成逻辑即可:
# 让第1行(索引0)对应训练,第2行(索引1)对应验证,第3行(索引2)对应测试 dfClimbing['split'] = (dfClimbing.index + 1) % 3 # 对应筛选逻辑 climbingTngDataset = dfClimbing[dfClimbing['split'] == 1].drop('split', axis=1).reset_index(drop=True) climbingValDataset = dfClimbing[dfClimbing['split'] == 2].drop('split', axis=1).reset_index(drop=True) climbingTestDataset = dfClimbing[dfClimbing['split'] == 0].drop('split', axis=1).reset_index(drop=True)
这样就完全匹配你描述的“第1条进训练,第2条进验证,第3条进测试”的需求了。
内容的提问来源于stack exchange,提问作者Jay Py
相关产品推荐
相关产品推荐

