【问题标题】:Different results when using train_test_split vs manually splitting the data使用 train_test_split 与手动拆分数据时的不同结果
【发布时间】:2019-09-27 22:29:11
【问题描述】:

我有一个 pandas 数据框,我想对其进行预测并获得每个特征的均方根误差。我正在关注手动拆分数据集的在线指南,但我认为使用sklearn.model_selection 中的train_test_split 会更方便。不幸的是,在手动拆分数据与使用 train_test_split 之后查看 rmse 值时,我得到了不同的结果。

一个(希望)可重现的例子:

import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

np.random.seed(0)
df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=['feature_1','feature_2','feature_3','feature_4'])
df['target'] = np.random.randint(2,size=100)
df2 = df.copy()

这是一个函数knn_train_test,用于手动拆分数据、拟合模型、进行预测等:

def knn_train_test(train_col, target_col, df):
    knn = KNeighborsRegressor()
    np.random.seed(0)

    # Randomize order of rows in data frame.
    shuffled_index = np.random.permutation(df.index)
    rand_df = df.reindex(shuffled_index)

    # Divide number of rows in half and round.
    last_train_row = int(len(rand_df) / 2)

    # Select the first half and set as training set.
    # Select the second half and set as test set.
    train_df = rand_df.iloc[0:last_train_row]
    test_df = rand_df.iloc[last_train_row:]

    # Fit a KNN model using default k value.
    knn.fit(train_df[[train_col]], train_df[target_col])

    # Make predictions using model.
    predicted_labels = knn.predict(test_df[[train_col]])

    # Calculate and return RMSE.
    mse = mean_squared_error(test_df[target_col], predicted_labels)
    rmse = np.sqrt(mse)
    return rmse

rmse_results = {}
train_cols = df.columns.drop('target')

# For each column (minus `target`), train a model, return RMSE value
# and add to the dictionary `rmse_results`.
for col in train_cols:
    rmse_val = knn_train_test(col, 'target', df)
    rmse_results[col] = rmse_val

# Create a Series object from the dictionary so 
# we can easily view the results, sort, etc
rmse_results_series = pd.Series(rmse_results)
rmse_results_series.sort_values()

#Output
feature_3    0.541110
feature_2    0.548452
feature_4    0.559285
feature_1    0.569912
dtype: float64

现在,这里有一个函数 knn_train_test2,它使用 train_test_split 分割数据:

def knn_train_test2(train_col, target_col, df2):

    knn = KNeighborsRegressor()
    np.random.seed(0)

    X_train, X_test, y_train, y_test = train_test_split(df2[[train_col]],df2[[target_col]], test_size=0.5)

    knn.fit(X_train,y_train)

    predictions = knn.predict(X_test)

    mse = mean_squared_error(y_test,predictions)

    rmse = np.sqrt(mse)

    return rmse

rmse_results = {}
train_cols = df2.columns.drop('target')

for col in train_cols:
    rmse_val = knn_train_test2(col, 'target', df2)
    rmse_results[col] = rmse_val


rmse_results_series = pd.Series(rmse_results)
rmse_results_series.sort_values()

# Output
feature_4    0.522303
feature_3    0.556417
feature_1    0.569210
feature_2    0.572713
dtype: float64

为什么我得到不同的结果?我想我一般误解了拆分>训练>测试过程,或者可能误解/错误指定train_test_split。提前谢谢你

【问题讨论】:

  • 这不是预期的吗?我不是 ML 专家,但如果你在这两种情况下随机拆分数据,从它们训练的模型应该不同,这会导致不同的 rmse?
  • 是的,这是意料之中的。
  • 对,当然。谢谢回复。很明显的答案!

标签: python numpy machine-learning scikit-learn train-test-split


【解决方案1】:

您的自定义 train_test_split 实现与 scikit-learn 的实现不同,这就是为什么您会为相同的种子获得不同的结果。

Here你可以找到官方实现。首先值得注意的是,scikit-learn 默认会进行 10 次重新洗牌和拆分迭代。 (检查n_splits参数)

只有如果您的方法与 scitkit-learn 方法的效果完全相同,那么您可以期望对相同的种子有相同的结果。

【讨论】:

    【解决方案2】:

    这是基本的机器学习性质。当您手动拆分数据时,您将拥有不同版本的训练和测试集。当你使用 sklearn 函数时,你会得到不同的训练和测试集。您的模型将根据它收到的训练数据进行预测,因此您的最终结果对于两者都不同。

    如果要重现结果,请使用 train_test_split 通过设置种子值来创建多个训练集。种子值用于在 train_test_split 函数中重现相同的结果。然后在运行您的 ml 函数时,也要在其中设置一个种子,因为即使 ML 函数也开始使用随机权重进行训练。用相同的种子在这些数据集上尝试你的模型,你会得到结果。

    【讨论】:

      【解决方案3】:

      手动拆分数据只是切片,但train_test_split 也会随机化切片数据。尝试修复随机数种子,看看每次使用train_test_split是否都能得到相同的结果。

      【讨论】:

      • 不,我的意思是,如果你修复了种子,在使用train_test_split 运行时应该会看到相同的结果,否则即使使用train_test_split 也会有不同的结果,这证明了随机采样操作而不是只是切片。
      猜你喜欢
      • 2018-12-10
      • 2021-01-28
      • 2021-08-16
      • 2021-05-10
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 2021-10-21
      • 2015-09-23
      相关资源
      最近更新 更多