【问题标题】: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为什么我在手动拆分测试和训练数据而不是使用 Python 拆分功能时会得到不同的结果
【发布时间】:2019-09-29 11:05:11
【问题描述】:

如果我通过 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 训练和 1/3 测试。有一个名为 human 的列,它给出的值是 1 到 9,我使用人类 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)

我期待的结果或多或少相同,而且两次调用的所有数据类型似乎都相同。

我错过了什么?

【问题讨论】:

  • 您如何在手动示例中制作test.csvtrain.csv?两种方法之间的拆分是否完全相同?
  • 我所做的拆分是在记录的前 2/3 和最后 1/3 上手动进行的。然而,由 split 函数完成的拆分是在内部进行的,因此集合不同但大小相同....对象的类型不是我认为的实际数据
  • 你为什么要这样做:X_train = training_data.iloc[:, training_data.columns.str.contains('|'.join(['x1','x2','x3']))] ?我认为这可能会让您一无所有...您是否检查过您的X_train 在该行之后的样子?此外,一般来说,train_test_split 会在数据集中存在某种顺序的情况下打乱行,以尝试获得标签的均匀分布。
  • 如何从文件中拆分数据? train_test_split 随机拆分(统一采样数据)。如果您在某个特定位置拆分文件,您可能会得到不平衡的数据(例如,如果数据按y 排序)或其他类似问题。
  • 如果将参数shuffle = False 添加到X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.33) 会得到类似的结果吗?

标签: python dataframe modeling


【解决方案1】:

我假设这两种方法实际上都按照您的意图进行,并且您的 X_train/test 和 y_train/tests 的形状来自这两种方法是相同的。您可以绘制数据集的底层分布将您的第二个实现与交叉验证的模型进行比较(以获得更好的严谨性)。


绘制初始训练中标签 (y) 的分布(即制作条形图/密度图) - 测试集与第二个训练集(来自手动实施)。您可以更深入地研究并在数据中绘制其他列,查看两个实现的结果集之间的数据分布是否有任何不同。如果分布不同,那么您的两个模型之间就会出现差异。如果您的差异很大,则可能是您的标签(或其他列)实际上是为您的手动实施排序的,因此您在比较的数据集中会得到非常不同的分布。

另外,如果您想确保您的手动拆分结果是基于模型结果而不是基础数据分布的“代表性”集合(可以很好地概括),我会将其与交叉验证的结果进行比较模型,而不是一组结果。

基本上,虽然概率很小并且train_test_split 进行了一些改组,但您基本上可以得到一个表现良好的“训练/测试”对,只是运气不好。 (为了在不进行交叉验证的情况下减少这种情况的可能性,我建议使用train_test_split 函数的stratify 参数。那么至少你确定第一个实现“更加努力”以获得平衡的训练/测试对。)

如果您决定交叉验证(使用test_train_split),您将获得折叠的平均模型预测及其周围的置信区间,并可以检查您的第二个模型结果是否在该区间内。如果它没有再次出现,则仅意味着您的拆分实际上以某种方式“损坏”(例如,通过排序值)。


附:我还要补充一点,决策树是已知会大量过度拟合的模型 [1]。也许改用随机森林? (由于引导/装袋,您应该获得更稳定的结果,这类似于交叉验证以减少过度拟合的机会。)

1 - http://cv.znu.ac.ir/afsharchim/AI/lectures/Decision%20Trees%203.pdf

【讨论】:

  • 感谢您的回复,很抱歉这么晚才阅读。我确实检查了分布,它们几乎相同。数据基本上是 9 个人,而不是 python 拆分,我的手动拆分是人类 1-6,测试是 7-9 所以应该是相同的表示,我至少会想到。生病继续挖。我还做了随机森林,它在 python 拆分上给出了更好的结果,但在我的手动拆分上也有同样的问题。谢谢
  • 实际上,在手动选择人类 1-6 和 7-9 时,分布非常不同。在进行 pythom 拆分时,它会像下面提到的那样进行洗牌,并且分布几乎相同。手动操作时,它们有很大不同...我很想在这里张贴一张图片,但是缺少工具栏来这样做..感谢大家的帮助
【解决方案2】:

scikit-learn 中的 train_test_split 函数根据 documentation 使用 sklearn.model_selection.ShuffleSplit,这意味着,此方法在拆分时会随机化您的数据。

当您手动拆分时,您并没有将其随机化,因此如果您的标签没有在整个数据集中均匀分布,您当然会遇到性能问题,因为由于训练数据不包含足够多的数据,您的模型将无法充分泛化其他标签的样本。

如果我的怀疑是正确的,您应该通过将shuffle=False 传递给train_test_split 来获得类似的结果。

【讨论】:

  • train_test_split 总是返回与它设置随机种子相同的结果,无论如何我都这样做了,问题仍然存在。
【解决方案3】:

假设您的数据集包含此数据。

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

希望这能回答你的问题

【讨论】:

    【解决方案4】:

    这听起来像是一个简单的检查,但是..

    在第一个示例中,您从“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']))] 
    

    祝你好运,如果有帮助,请告诉我们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 2018-12-21
      • 2021-02-14
      相关资源
      最近更新 更多