【问题标题】:scikit-learn - predict trained model on new inputscikit-learn - 预测新输入的训练模型
【发布时间】:2020-02-11 14:02:22
【问题描述】:

我有一个如下数据集:

| "Consignor Code" | "Consignee Code" | "Origin" | "Destination" | "Carrier Code" | 
|------------------|------------------|----------|---------------|----------------| 
| "6402106844"     | "66903717"       | "DKCPH"  | "CNPVG"       | "6402746387"   | 
| "6402106844"     | "66903717"       | "DKCPH"  | "CNPVG"       | "6402746387"   | 
| "6402106844"     | "6404814143"     | "DKCPH"  | "CNPVG"       | "6402746387"   | 
| "6402107662"     | "66974631"       | "DKCPH"  | "VNSGN"       | "6402746393"   | 
| "6402107662"     | "6404518090"     | "DKCPH"  | "THBKK"       | "6402746393"   | 
| "6402107662"     | "6404518090"     | "DKBLL"  | "THBKK"       | "6402746393"   | 
| "6408507648"     | "6403601344"     | "DKCPH"  | "USTPA"       | "66565231"     | 


我正在尝试在其上构建我的第一个 ML 模型。为此,我正在使用 scikit-learn。这是我的代码:

#Import the dependencies
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import make_scorer, accuracy_score
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.externals import joblib
from sklearn import preprocessing
import pandas as pd

#Import the dataset (A CSV file)
dataset = pd.read_csv('shipments.csv', header=0, skip_blank_lines=True)
#Drop any rows containing NaN values
dataset.dropna(subset=['Consignor Code', 'Consignee Code',
                       'Origin', 'Destination', 'Carrier Code'], inplace=True)

#Convert the numeric only cells to strings
dataset['Consignor Code'] = dataset['Consignor Code'].astype('int64')
dataset['Consignee Code'] = dataset['Consignee Code'].astype('int64')
dataset['Carrier Code'] = dataset['Carrier Code'].astype('int64')

#Define our target (What we want to be able to predict)
target = dataset.pop('Destination')

#Convert all our data to numeric values, so we can use the .fit function.
#For that, we use LabelEncoder
le = preprocessing.LabelEncoder()
target = le.fit_transform(list(target))
dataset['Origin'] = le.fit_transform(list(dataset['Origin']))
dataset['Consignor Code'] = le.fit_transform(list(dataset['Consignor Code']))
dataset['Consignee Code'] = le.fit_transform(list(dataset['Consignee Code']))
dataset['Carrier Code'] = le.fit_transform(list(dataset['Carrier Code']))

#Prepare the dataset.
X_train, X_test, y_train, y_test = train_test_split(
    dataset, target, test_size=0.3, random_state=0)


#Prepare the model and .fit it.
model = RandomForestClassifier()
model.fit(X_train, y_train)

#Make a prediction on the test set.
predictions = model.predict(X_test)

#Print the accuracy score.
print("Accuracy score: {}".format(accuracy_score(y_test, predictions)))

现在上面的代码返回:

Accuracy score: 0.7172413793103448

现在我的问题可能很愚蠢 - 但我如何使用我的 model 来实际向我展示它对新数据的预测?

考虑下面的新输入,我希望它预测Destination:

"6408507648","6403601344","DKCPH","","66565231"

如何使用这些数据查询我的模型并得到预测的Destination?

【问题讨论】:

  • 只需像在X_test 上所做的那样,就新数据调用model.predict。 X_test 的结构应该与任何新数据相同。
  • 顺便说一句-您应该将标签编码器和任何其他类似的预处理放入pipeline。在拆分数据之前进行这样的预处理是一个严重的错误。
  • 我怀疑它会起作用。由于fit_transform(),编码器会遇到一些问题。另外,我发现你用 4 个变量训练数据很奇怪,但你的输入包含 5 个。
  • 使用fit_transforms() 使编码器适合传递的数据集,然后进行转换。如果您需要对新值(输入)进行编码,它将适合新数据,并且与训练模型的值不匹配。您应该为每个变量安装不同的编码器实例,然后 transform 这样您就可以使用相同的编码 transform 新数据(您想用来预测)。
  • 这就是我对@oliverbj 上面的评论的意思

标签: python machine-learning scikit-learn


【解决方案1】:

这里有一个包含预测的完整工作示例。最重要的部分是为每个特征定义不同的标签编码器,这样你就可以用相同的编码来拟合新数据,否则你会遇到错误(现在可能会显示,但你会在计算准确度时注意到):

dataset = pd.DataFrame({'Consignor Code':["6402106844","6402106844","6402106844","6402107662","6402107662","6402107662","6408507648"],
                   'Consignee Code': ["66903717","66903717","6404814143","66974631","6404518090","6404518090","6403601344"],
                   'Origin':["DKCPH","DKCPH","DKCPH","DKCPH","DKCPH","DKBLL","DKCPH"],
                   'Destination':["CNPVG","CNPVG","CNPVG","VNSGN","THBKK","THBKK","USTPA"],
                   'Carrier Code':["6402746387","6402746387","6402746387","6402746393","6402746393","6402746393","66565231"]})

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import make_scorer, accuracy_score
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.externals import joblib
from sklearn import preprocessing
import pandas as pd

#Import the dataset (A CSV file)
#Drop any rows containing NaN values
dataset.dropna(subset=['Consignor Code', 'Consignee Code',
                       'Origin', 'Destination', 'Carrier Code'], inplace=True)


#Define our target (What we want to be able to predict)
target = dataset.pop('Destination')

#Convert all our data to numeric values, so we can use the .fit function.
#For that, we use LabelEncoder
le_origin = preprocessing.LabelEncoder()
le_consignor = preprocessing.LabelEncoder()
le_consignee = preprocessing.LabelEncoder()
le_carrier = preprocessing.LabelEncoder()
le_target = preprocessing.LabelEncoder()
target = le_target.fit_transform(list(target))
dataset['Origin'] = le_origin.fit_transform(list(dataset['Origin']))
dataset['Consignor Code'] = le_consignor.fit_transform(list(dataset['Consignor Code']))
dataset['Consignee Code'] = le_consignee.fit_transform(list(dataset['Consignee Code']))
dataset['Carrier Code'] = le_carrier.fit_transform(list(dataset['Carrier Code']))

#Prepare the dataset.
X_train, X_test, y_train, y_test = train_test_split(
    dataset, target, test_size=0.3, random_state=42)


#Prepare the model and .fit it.
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

#Make a prediction on the test set.
predictions = model.predict(X_test)

#Print the accuracy score.
print("Accuracy score: {}".format(accuracy_score(y_test, predictions)))

new_input = ["6408507648","6403601344","DKCPH","66565231"]
fitted_new_input = np.array([le_consignor.transform([new_input[0]])[0],
                                le_consignee.transform([new_input[1]])[0],
                                le_origin.transform([new_input[2]])[0],
                                le_carrier.transform([new_input[3]])[0]])
new_predictions = model.predict(fitted_new_input.reshape(1,-1))

print(le_target.inverse_transform(new_predictions))

最后,你的树预测:

['THBKK']

【讨论】:

  • 这些行是我定义了多个编码器,可以使用 for loop 显示的 dan 更轻松地完成,或者使用 dict 理解更容易。如果它可以帮助您解决问题,请随时接受我的回答,因为现在您可以使用此代码使用新数据进行预测 :)
  • 您确实应该在编码之前进行训练测试拆分,否则从技术上讲它是目标泄漏。
  • @Celius 哇!太感谢了。这给了我一个很好的起点。请问最后的预测?在我的数据集(>8k 行)上,它给了我SGSIN 的最终预测,准确度为0.71。但是,每次我运行代码时,最终的预测都是不同的。对于这个特定的输入,理想的方法是返回USTPA。我该如何改进它?
  • 您可以从修复random_state 开始,以确保可以复制模型(生成始终相同的结果),无论是对于train_test_split 还是对于RandomForest。此外,您可能需要检查超参数调整以获得更好的优化。我刚刚编辑了我的答案以修复RandomForest 中的随机状态。检查max_depth、min_child_weight、max_features 和其他一些您可以调整以提高其性能的超参数。
  • 是的,为了您的客户/客户,您应该启用它。这将确保它是可重现的,这对客户端来说非常重要,否则他们会得到随机结果,并且(如果他们不了解 RandomForest 分类器的工作原理)你会立即质疑他们为什么会变得不同(不一致在他们的眼中)结果。
【解决方案2】:

这里有一些东西可以快速说明这一点。在实践中我不会这样做,并且可能存在一些错误。例如,我认为如果测试集中有看不见的类,这将失败。

#Prepare the dataset.
X_train, X_test, y_train, y_test = train_test_split(
    dataset, target, test_size=0.3, random_state=0)

#Convert all our data to numeric values, so we can use the .fit function.
#For that, we use LabelEncoder
le_target = preprocessing.LabelEncoder()
y_train = le_target.fit_transform(y_train)
y_test = le_target.transform(y_test)

# Now create a separate encoder for each of your features:
encoders = {}
for feature in ["Origin", "Consignor Code", "Consignee Code", "Carrier Code"]:
# NOTE: The LabelEncoder docs state clearly at the start that you shouldn't be using it on your inputs. I'm not going to get into that here though but just be aware that it's not a good encoding.
    encoders[feature] = preprocessing.LabelEncoder()
    X_train[feature] = encoders[feature].fit_transform(X_train[feature])
    X_test[feature] = encoders[feature].transform(X_test[feature])    

#Prepare the model and .fit it.
model = RandomForestClassifier()
model.fit(X_train, y_train)

#Make a prediction on the test set.
predictions = model.predict(X_test)

le_target.inverse_transform(predictions)

这里的关键概念是为您的特征使用单独的编码器,因为这些编码器对象会记住如何编码该特征。这是在fit 阶段完成的。然后,您需要对任何新数据调用 transform 以正确编码。

【讨论】:

  • 感谢您抽出宝贵时间帮助我!
猜你喜欢
  • 2014-10-13
  • 2022-01-05
  • 2019-09-09
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 2015-10-14
  • 2021-01-12
  • 2022-10-19
相关资源
最近更新 更多