Python 如何在需要pd.get_假人的新数据上运行模型

Python 如何在需要pd.get_假人的新数据上运行模型,python,scikit-learn,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'],

我有一个模型运行以下各项:

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
然后,我使用以下代码创建了一个虚拟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
然后,我创建了以下模型:

#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
现在我有了新的数据,我想预测:

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
然后创建假人并运行预测

newpredict = pd.get_dummies(newdf)

predict = model.predict(newpredict)
输出:

ValueError: X has 3 features per sample; expecting 6
这是有道理的,因为没有类别
b
c
,也没有名字叫
matt

我的问题是,考虑到我的新数据并不总是包含原始数据中使用的完整列,如何设置此模型是最好的方法。每天我都有新的数据,所以我不太确定哪种方法最有效、最无错误


这是一个示例数据-当运行
pd.get\u dummies
时,我的数据集有2000列。非常感谢

让我更详细地解释一下尼古拉斯和布鲁斯基的建议

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

但是,对于大多数机器学习任务,如果您希望将来有新的类别,而这些类别没有在模型培训中使用,
sklearn.onehotcoder
应该是标准选择
handle\u unknown
sklearn的参数。OneHotEncoder可以设置为
'ignore'
,这样做:在将来应用编码器时忽略新类别。从:

如果在转换期间存在未知的分类特征,是引发错误还是忽略(默认为引发)。当此参数设置为“忽略”并且在转换过程中遇到未知类别时,此功能产生的一个热编码列将全部为零。在逆变换中,未知类别将表示为无

对于您的示例,基于LabelEncoding和OneHotEncoding的完整流程如下所示:

# Create a categorical boolean mask
categorical_feature_mask = df.dtypes == object
# Filter out the categorical columns into a list for easy reference later on in case you have more than a couple categorical columns
categorical_cols = df.columns[categorical_feature_mask].tolist()

# Instantiate the OneHotEncoder Object
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(handle_unknown='ignore', sparse = False)
# Apply ohe on data
ohe.fit(df[categorical_cols])
cat_ohe = ohe.transform(df[categorical_cols])

#Create a Pandas DataFrame of the hot encoded column
ohe_df = pd.DataFrame(cat_ohe, columns = ohe.get_feature_names(input_features = categorical_cols))
#concat with original data and drop original columns
df_ohe = pd.concat([df, ohe_df], axis=1).drop(columns = categorical_cols, axis=1)

# The following code is for your newdf after training and testing on original df
# Apply ohe on newdf
cat_ohe_new = ohe.transform(newdf[categorical_cols])
#Create a Pandas DataFrame of the hot encoded column
ohe_df_new = pd.DataFrame(cat_ohe_new, columns = ohe.get_feature_names(input_features = categorical_cols))
#concat with original data and drop original columns
df_ohe_new = pd.concat([newdf, ohe_df_new], axis=1).drop(columns = categorical_cols, axis=1)

# predict on df_ohe_new
predict = model.predict(df_ohe_new)
输出(可分配回newdf):

但是,如果您真的只想使用
pd.get_dummies
,那么以下功能也可以使用:

newpredict = newpredict.reindex(labels = df_dum.columns, axis = 1, fill_value = 0).drop(columns = ['Score'])
predict = model.predict(newpredict)
上述代码片段将确保您的新dummies df(newpredict)中的列与原始df_dum(具有
0
值)中的列相同,并删除
'Score'
列。这里的输出与上面相同。此代码将确保删除新数据集中但现在在原始训练数据中存在的任何分类值,同时保持列的顺序与原始df中的顺序相同

编辑:
有一件事我忘了补充,那就是
pd.get_dummies
通常比
sklearn执行得快得多。OneHotEncoder

我记得在这个网站上有一个很长的讨论,人们在讨论中得出结论,出于这个确切的原因,最好使用
sklearn
一个热编码器。@NicolasGervais得到了它。如果您使用同一个OneHotEncoder对象,当您第一次安装它时,它将记住总共有多少列。很高兴@SOK能为您提供帮助。如果在实施过程中遇到任何问题,请告诉我。谢谢@finlytics hub。目前我唯一的问题是一个
类型错误:(“参数必须是字符串或数字”
当我在
ohe.fit(dfmodel[Category\u cols])
阶段时。有什么想法要调试吗?@SOK你能检查
Category\u cols
的输出吗?它应该是这样的
['Name',Category']
。我假设您在
ohe.fit
中引用的
dfmodel
与您在原始帖子中定义的
df
完全相同?是的,抱歉
dfmodel
df
相同。当我调试它时,它列出了您所说的
categorical\u cols
,在我的示例中,它大约有7列(这些都是分类的)所以我不太清楚为什么(我正在申请我的更大的模型)有更多的专栏,上面的问题
newpredict = newpredict.reindex(labels = df_dum.columns, axis = 1, fill_value = 0).drop(columns = ['Score'])
predict = model.predict(newpredict)