为什么在手动拆分测试和训练数据时会得到不同的结果,而不是使用 Python 拆分函数
Why do I get different results when I do a manual split of test and train data as opposed to using the Python splitting function
如果我 运行 通过 train_test_split 函数使用数据的简单 dtree 回归模型,我会得到不错的 r2 分数和较低的 mse 值。
training_data = pandas.read_csv('data.csv',usecols=['y','x1','x2','x3'])
y = training_data.iloc[:,0]
x = training_data.iloc[:,1:]
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.33)
regressor = DecisionTreeRegressor(random_state = 0)
# fit the regressor with X and Y data
regressor.fit(X_train, y_train)
y_pred = regressor.predict(X_test)
然而,如果我手动将数据文件拆分为两个文件 2/3 train 和 1/3 test。有一个名为 human 的列,它给出了 1 到 9 的值,它是人类,我使用 human 1-6 进行训练,7-9 进行测试
我的 r2 分数为负,mse 很高
training_data = pandas.read_csv("train"+".csv",usecols=['y','x1','x2','x3'])
testing_data = pandas.read_csv("test"+".csv", usecols=['y','x1','x2','x3'])
y_train = training_data.iloc[:,training_data.columns.str.contains('y')]
X_train = training_data.iloc[:,training_data.columns.str.contains('|'.join(['x1','x2','x3']))]
y_test = testing_data.iloc[:,testing_data.columns.str.contains('y')]
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(l_vars))]
y_train = pandas.Series(y_train['y'], index=y_train.index)
y_test = pandas.Series(y_test['y'], index=y_test.index)
regressor = DecisionTreeRegressor(random_state = 0)
regressor.fit(X_train, y_train)
y_pred = regressor.predict(X_test)
我原本希望得到大致相同的结果,而且两次调用的所有数据类型似乎都相同。
我错过了什么?
scikit-learn
中的 train_test_split
函数根据 documentation 使用 sklearn.model_selection.ShuffleSplit
,这意味着,此方法在拆分时随机化数据。
当你手动分割时,你没有随机化它,所以如果你的标签没有均匀分布在你的数据集中,你当然会遇到性能问题,因为你的模型不会被足够泛化,因为训练数据不是包含足够的其他标签样本。
如果我的怀疑是正确的,将 shuffle=False
传递给 train_test_split
应该会得到类似的结果。
我假设这里的两种方法实际上都在做您打算做的事情,并且您的 X_train/test 和 y_train/tests 的形状都来自这两种方法。您可以 绘制数据集的基础分布图 或 将您的第二个实现与交叉验证模型进行比较 (为了更严格)。
绘制初始训练中标签 (y) 的分布(即绘制条形 charts/density 图)- 测试集与第二个训练集(来自手动实施)中的对比。您可以深入研究并绘制数据中的其他列,看看两种实现的结果集之间的数据分布是否有任何不同。如果分布与合理范围不同,您的两个模型之间就会出现差异。如果您的差异很大,则可能是您的标签(或其他列)实际上是针对您的手动实施进行排序的,因此您在比较的数据集中会得到非常不同的分布。
此外,如果您想确保您的手动拆分结果是基于模型结果而不是基础数据分布的 'representative' 集(可以很好地概括),我会将其与结果进行比较一个交叉验证的模型,而不是一组结果。
本质上,虽然概率很小并且 train_test_split
做了一些洗牌,但你基本上可以得到一对表现良好的 'train/test' 对,只是运气不好。 (为了在不进行交叉验证的情况下减少这种情况的可能性,我建议使用 train_test_split
函数的 stratify
参数。那么至少你确定第一个实现 'tries harder'获得平衡 train/test 对。)
如果您决定交叉验证(使用 test_train_split
),您将获得折叠的平均模型预测及其周围的置信区间,并可以检查您的第二个模型结果是否落在该区间内。如果它不再出现,则仅意味着您的拆分实际上是 'corrupted' 某种方式(例如,通过对值进行排序)。
P.S。我还要补充一点,决策树是众所周知的过度拟合模型 [1]。也许改用随机森林? (你应该得到更稳定的结果,因为 bootstraping/bagging 这将类似于交叉验证以减少过度拟合的机会。)
1 - http://cv.znu.ac.ir/afsharchim/AI/lectures/Decision%20Trees%203.pdf
假设您的数据集包含此数据。
1 + 1 = 2
2 + 2 = 4
4 - 4 = 0
2 - 2 = 0
所以假设您想要 50% 的火车拆分。 train_test_split 像这样打乱它以便更好地概括
1+1=2
2-2= 0
所以当它看到这些数据时,它知道该怎么做
2+2
4-4#since it learned both addition and subtraction
但是当你像这样手动洗牌时
1 + 1 = 2
2 + 2 =4#only learned addition
当它看到这个数据时不知道该做什么
2 - 2
4 - 4#test data is subtraction
希望这能回答您的问题
这听起来像是一个简单的检查,但是..
在第一个示例中,您从 'data.csv' 读取数据,在第二个示例中,您从 'train.csv' 和 'test.csv' 读取数据。既然你说你手动拆分文件,我有一个关于如何完成的问题。如果您只是在 2/3 的标记处剪切文件并保存为 'train.csv',其余的保存为 'test.csv',那么您在不知不觉中对文件中数据的一致性做出了假设。数据文件可以有一个有序的结构,这会扭曲训练或测试,这就是 train_test_split 随机化行的原因。如果您还没有这样做,请先尝试随机化行,然后写入您的训练和测试 csv 文件以确保您有一个同类数据集。
另一行可能不合适的是第 6 行:
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(l_vars))]
也许 l_vars 包含您所期望的内容。也许应该阅读以下内容以更加一致。
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(['x1','x2','x3']))]
祝你好运,如果有帮助请告诉我们。
如果我 运行 通过 train_test_split 函数使用数据的简单 dtree 回归模型,我会得到不错的 r2 分数和较低的 mse 值。
training_data = pandas.read_csv('data.csv',usecols=['y','x1','x2','x3'])
y = training_data.iloc[:,0]
x = training_data.iloc[:,1:]
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.33)
regressor = DecisionTreeRegressor(random_state = 0)
# fit the regressor with X and Y data
regressor.fit(X_train, y_train)
y_pred = regressor.predict(X_test)
然而,如果我手动将数据文件拆分为两个文件 2/3 train 和 1/3 test。有一个名为 human 的列,它给出了 1 到 9 的值,它是人类,我使用 human 1-6 进行训练,7-9 进行测试
我的 r2 分数为负,mse 很高
training_data = pandas.read_csv("train"+".csv",usecols=['y','x1','x2','x3'])
testing_data = pandas.read_csv("test"+".csv", usecols=['y','x1','x2','x3'])
y_train = training_data.iloc[:,training_data.columns.str.contains('y')]
X_train = training_data.iloc[:,training_data.columns.str.contains('|'.join(['x1','x2','x3']))]
y_test = testing_data.iloc[:,testing_data.columns.str.contains('y')]
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(l_vars))]
y_train = pandas.Series(y_train['y'], index=y_train.index)
y_test = pandas.Series(y_test['y'], index=y_test.index)
regressor = DecisionTreeRegressor(random_state = 0)
regressor.fit(X_train, y_train)
y_pred = regressor.predict(X_test)
我原本希望得到大致相同的结果,而且两次调用的所有数据类型似乎都相同。
我错过了什么?
scikit-learn
中的 train_test_split
函数根据 documentation 使用 sklearn.model_selection.ShuffleSplit
,这意味着,此方法在拆分时随机化数据。
当你手动分割时,你没有随机化它,所以如果你的标签没有均匀分布在你的数据集中,你当然会遇到性能问题,因为你的模型不会被足够泛化,因为训练数据不是包含足够的其他标签样本。
如果我的怀疑是正确的,将 shuffle=False
传递给 train_test_split
应该会得到类似的结果。
我假设这里的两种方法实际上都在做您打算做的事情,并且您的 X_train/test 和 y_train/tests 的形状都来自这两种方法。您可以 绘制数据集的基础分布图 或 将您的第二个实现与交叉验证模型进行比较 (为了更严格)。
绘制初始训练中标签 (y) 的分布(即绘制条形 charts/density 图)- 测试集与第二个训练集(来自手动实施)中的对比。您可以深入研究并绘制数据中的其他列,看看两种实现的结果集之间的数据分布是否有任何不同。如果分布与合理范围不同,您的两个模型之间就会出现差异。如果您的差异很大,则可能是您的标签(或其他列)实际上是针对您的手动实施进行排序的,因此您在比较的数据集中会得到非常不同的分布。
此外,如果您想确保您的手动拆分结果是基于模型结果而不是基础数据分布的 'representative' 集(可以很好地概括),我会将其与结果进行比较一个交叉验证的模型,而不是一组结果。
本质上,虽然概率很小并且 train_test_split
做了一些洗牌,但你基本上可以得到一对表现良好的 'train/test' 对,只是运气不好。 (为了在不进行交叉验证的情况下减少这种情况的可能性,我建议使用 train_test_split
函数的 stratify
参数。那么至少你确定第一个实现 'tries harder'获得平衡 train/test 对。)
如果您决定交叉验证(使用 test_train_split
),您将获得折叠的平均模型预测及其周围的置信区间,并可以检查您的第二个模型结果是否落在该区间内。如果它不再出现,则仅意味着您的拆分实际上是 'corrupted' 某种方式(例如,通过对值进行排序)。
P.S。我还要补充一点,决策树是众所周知的过度拟合模型 [1]。也许改用随机森林? (你应该得到更稳定的结果,因为 bootstraping/bagging 这将类似于交叉验证以减少过度拟合的机会。)
1 - http://cv.znu.ac.ir/afsharchim/AI/lectures/Decision%20Trees%203.pdf
假设您的数据集包含此数据。
1 + 1 = 2
2 + 2 = 4
4 - 4 = 0
2 - 2 = 0
所以假设您想要 50% 的火车拆分。 train_test_split 像这样打乱它以便更好地概括
1+1=2
2-2= 0
所以当它看到这些数据时,它知道该怎么做
2+2
4-4#since it learned both addition and subtraction
但是当你像这样手动洗牌时
1 + 1 = 2
2 + 2 =4#only learned addition
当它看到这个数据时不知道该做什么
2 - 2
4 - 4#test data is subtraction
希望这能回答您的问题
这听起来像是一个简单的检查,但是..
在第一个示例中,您从 'data.csv' 读取数据,在第二个示例中,您从 'train.csv' 和 'test.csv' 读取数据。既然你说你手动拆分文件,我有一个关于如何完成的问题。如果您只是在 2/3 的标记处剪切文件并保存为 'train.csv',其余的保存为 'test.csv',那么您在不知不觉中对文件中数据的一致性做出了假设。数据文件可以有一个有序的结构,这会扭曲训练或测试,这就是 train_test_split 随机化行的原因。如果您还没有这样做,请先尝试随机化行,然后写入您的训练和测试 csv 文件以确保您有一个同类数据集。
另一行可能不合适的是第 6 行:
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(l_vars))]
也许 l_vars 包含您所期望的内容。也许应该阅读以下内容以更加一致。
X_test = testing_data.iloc[:,testing_data.columns.str.contains('|'.join(['x1','x2','x3']))]
祝你好运,如果有帮助请告诉我们。