如何在需要 pd.get_dummies 的新数据上运行模型

SOK*_*SOK 4 python scikit-learn

我有一个运行以下命令的模型:

import pandas as pd
import numpy as np

# initialize list of lists 
data = [['tom', 10,1,'a'], ['tom', 15,5,'a'], ['tom', 14,1,'a'], ['tom', 15,4,'b'], ['tom', 18,1,'b'], ['tom', 15,6,'a'], ['tom', 17,3,'a']
       , ['tom', 14,7,'b'], ['tom',16 ,6,'a'], ['tom', 22,2,'a'],['matt', 10,1,'c'], ['matt', 15,5,'b'], ['matt', 14,1,'b'], ['matt', 15,4,'a'], ['matt', 18,1,'a'], ['matt', 15,6,'a'], ['matt', 17,3,'a']
       , ['matt', 14,7,'c'], ['matt',16 ,6,'b'], ['matt', 10,2,'b']]

# Create the pandas DataFrame 
df = pd.DataFrame(data, columns = ['Name', 'Attempts','Score','Category']) 

print(df.head(2))
  Name  Attempts  Score Category
0  tom        10      1        a
1  tom        15      5        a
Run Code Online (Sandbox Code Playgroud)

然后我使用以下代码创建了一个虚拟 df 以在模型中使用:

from sklearn.linear_model import LogisticRegression

df_dum = pd.get_dummies(df)
print(df_dum.head(2))
  Attempts  Score  Name_matt  Name_tom  Category_a  Category_b  Category_c
0        10      1          0         1           1           0           0
1        15      5          0         1           1           0           0
Run Code Online (Sandbox Code Playgroud)

然后我创建了以下模型:

#Model

X = df_dum.drop(('Score'),axis=1)
y = df_dum['Score'].values

#Training Size
train_size = int(X.shape[0]*.7)
X_train = X[:train_size]
X_test = X[train_size:]
y_train = y[:train_size]
y_test = y[train_size:]


#Fit Model
model = LogisticRegression(max_iter=1000)
model.fit(X_train,y_train)


#Send predictions back to dataframe
Z = model.predict(X_test)
zz = model.predict_proba(X_test)

df.loc[train_size:,'predictions']=Z
dfpredictions = df.dropna(subset=['predictions'])

print(dfpredictions)
    Name  Attempts  Score Category  predictions
14  matt        18      1        a          1.0
15  matt        15      6        a          1.0
16  matt        17      3        a          1.0
17  matt        14      7        c          1.0
18  matt        16      6        b          1.0
19  matt        10      2        b          1.0
Run Code Online (Sandbox Code Playgroud)

现在我有了我想要预测的新数据:

newdata = [['tom', 10,'a'], ['tom', 15,'a'], ['tom', 14,'a']]

newdf = pd.DataFrame(newdata, columns = ['Name', 'Attempts','Category']) 

print(newdf)

 Name  Attempts Category
0  tom        10        a
1  tom        15        a
2  tom        14        a
Run Code Online (Sandbox Code Playgroud)

然后创建虚拟对象并运行预测

newpredict = pd.get_dummies(newdf)

predict = model.predict(newpredict)
Run Code Online (Sandbox Code Playgroud)

输出:

ValueError: X has 3 features per sample; expecting 6
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为没有类别bc也没有名为 的名称matt

我的问题是,鉴于我的新数据并不总是具有原始数据中使用的完整列集,因此设置此模型的最佳方法是什么。每天我都有新数据,所以我不太确定最有效且无错误的方法。

这是一个示例数据 - 我的数据集在运行时有 2000 列pd.get_dummies。非常感谢!

fin*_*hub 7

让我更详细地解释 Nicolas 和 BlueSkyz 的建议。

\n\n

pd.get_dummies当您确定生产/新数据集中的特定分类变量不会有任何新类别(例如,基于您公司或数据库的内部数据分类/一致性规则的性别、产品等)时,此功能非常有用。

\n\n

然而,对于大多数机器学习任务来说,未来可能会出现模型训练中未使用的新类别,这sklearn.OneHotEncoder应该是标准选择。handle_unknown的参数sklearn.OneHotEncoder可以设置为\'ignore\'做到这一点:将来应用编码器时忽略新类别。从文档中:

\n\n
\n

如果转换期间存在未知分类特征,是否引发错误或忽略(默认为引发)。当此参数设置为 \xe2\x80\x98ignore\xe2\x80\x99 且在转换过程中遇到未知类别时,该功能生成的 one-hot 编码列将全为零。在逆变换中,未知类别将表示为 None

\n
\n\n

基于 LabelEncoding 和 OneHotEncoding 的示例的完整流程如下:

\n\n
# Create a categorical boolean mask\ncategorical_feature_mask = df.dtypes == object\n# Filter out the categorical columns into a list for easy reference later on in case you have more than a couple categorical columns\ncategorical_cols = df.columns[categorical_feature_mask].tolist()\n\n# Instantiate the OneHotEncoder Object\nfrom sklearn.preprocessing import OneHotEncoder\nohe = OneHotEncoder(handle_unknown=\'ignore\', sparse = False)\n# Apply ohe on data\nohe.fit(df[categorical_cols])\ncat_ohe = ohe.transform(df[categorical_cols])\n\n#Create a Pandas DataFrame of the hot encoded column\nohe_df = pd.DataFrame(cat_ohe, columns = ohe.get_feature_names(input_features = categorical_cols))\n#concat with original data and drop original columns\ndf_ohe = pd.concat([df, ohe_df], axis=1).drop(columns = categorical_cols, axis=1)\n\n# The following code is for your newdf after training and testing on original df\n# Apply ohe on newdf\ncat_ohe_new = ohe.transform(newdf[categorical_cols])\n#Create a Pandas DataFrame of the hot encoded column\nohe_df_new = pd.DataFrame(cat_ohe_new, columns = ohe.get_feature_names(input_features = categorical_cols))\n#concat with original data and drop original columns\ndf_ohe_new = pd.concat([newdf, ohe_df_new], axis=1).drop(columns = categorical_cols, axis=1)\n\n# predict on df_ohe_new\npredict = model.predict(df_ohe_new)\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出(您可以将其分配回 newdf):

\n\n
array([1, 1, 1])\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如果您确实只想使用pd.get_dummies,那么以下方法也可以:

\n\n
newpredict = newpredict.reindex(labels = df_dum.columns, axis = 1, fill_value = 0).drop(columns = [\'Score\'])\npredict = model.predict(newpredict)\n
Run Code Online (Sandbox Code Playgroud)\n\n

上面的代码片段将确保您的新虚拟 df (newpredict) 中具有与原始 df_dum (带有0值)相同的列,并删除该\'Score\'列。这里的输出与上面相同。此代码将确保新数据集中存在但现在原始训练数据中存在的任何分类值都将被删除,同时保持列的顺序与原始 df 中的顺序相同。

\n\n

编辑:\n我忘记添加的一件事是pd.get_dummies执行速度通常比sklearn.OneHotEncoder

\n