Python 如何对列的子集进行热编码?
我有一个数据集,它有一些分类列。以下是一个小样本:Python 如何对列的子集进行热编码?,python,pandas,scikit-learn,feature-extraction,Python,Pandas,Scikit Learn,Feature Extraction,我有一个数据集,它有一些分类列。以下是一个小样本: Temp precip dow tod -20.44 snow 4 14.5 -22.69 snow 4 15.216666666666667 -21.52 snow 4 17.316666666666666 -21.52 snow 4 17.733333333333334 -20.51 snow 4 18.15 在这里,dow和precip是分类的,而其他的都是连续的 有没
Temp precip dow tod
-20.44 snow 4 14.5
-22.69 snow 4 15.216666666666667
-21.52 snow 4 17.316666666666666
-21.52 snow 4 17.733333333333334
-20.51 snow 4 18.15
在这里,dow
和precip
是分类的,而其他的都是连续的
有没有办法为这些列创建一个
OneHotEncoder
?我不想使用pd.get_dummies
,因为除非新数据中包含每个dow
和precip
的数据,否则无法将数据放入正确的格式。简短的回答是肯定的,但有一些警告
首先,您将无法直接在precip
功能上使用。您将需要使用将这些标签编码为整数
其次,如果只想对这些特征进行编码,可以将适当的值传递给n_值
和category_特征
参数
例如:
我将假定道琼斯指数是一周中的一天,它有七个值,而precip将有(雨、雨夹雪、雪和混合)作为值
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
df2 = df.copy()
le = LabelEncoder()
le.fit(['rain', 'sleet', 'snow', 'mix'])
df2.precip = le.transform(df2.precip)
df2
Temp precip dow tod
0 -20.44 3 4 14.500000
1 -22.69 3 4 15.216667
2 -21.52 3 4 17.316667
3 -21.52 3 4 17.733333
4 -20.51 3 4 18.150000
# Initialize OneHotEncoder with 4 values for precip and 7 for dow.
ohe = OneHotEncoder(n_values=np.array([4,7]), categorical_features=[1,2])
X = ohe.fit_transform(df2)
X.toarray()
array([[ 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. ,
1. , 0. , 0. , -20.44 , 14.5 ],
[ 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. ,
1. , 0. , 0. , -22.69 ,
15.21666667],
[ 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. ,
1. , 0. , 0. , -21.52 ,
17.31666667],
[ 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. ,
1. , 0. , 0. , -21.52 ,
17.73333333],
[ 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. ,
1. , 0. , 0. , -20.51 , 18.15 ]])
好的,这是可行的,但是你要么原地修改你的数据,要么创建一个副本,这样事情就会变得有点混乱。一种更有组织性的方法是使用
我想指出的是,在即将发布的sklearn v0.20中,将会有一个新的版本,它将使这类事情变得更加容易
我不想使用pd.get_dummies
,因为这样做不会把数据放进去
除非每个道琼斯指数和precip指数的正确格式在新数据中
假设您希望编码但同时维护这两列--您确定这对您不起作用吗
df = pd.DataFrame({
'temp': np.random.random(5) + 20.,
'precip': pd.Categorical(['snow', 'snow', 'rain', 'none', 'rain']),
'dow': pd.Categorical([4, 4, 4, 3, 1]),
'tod': np.random.random(5) + 10.
})
pd.concat((df[['dow', 'precip']],
pd.get_dummies(df, columns=['dow', 'precip'], drop_first=True)),
axis=1)
dow precip temp tod dow_3 dow_4 precip_rain precip_snow
0 4 snow 20.7019 10.4610 0 1 0 1
1 4 snow 20.0917 10.0174 0 1 0 1
2 4 rain 20.3978 10.5766 0 1 1 0
3 3 none 20.9804 10.0770 1 0 0 0
4 1 rain 20.3121 10.3584 0 0 1 0
在与新数据交互的情况下,您可以使用
df['col'] = df['col'].cat.add_categories(...)
在这里,您将传递一个设置差异的列表。这将添加到生成的
pd.category
对象的“已识别”类别列表中。您可以检查两件事:正如@Grr所述,这是一件好事
因此,我更喜欢管道,因为它们是一种整洁的方式,可以方便地使用网格搜索、避免交叉验证中折叠之间的泄漏等。因此,我通常会使用这样的管道(假设您首先使用precip标签):
df['col'] = df['col'].cat.add_categories(...)
from sklearn.pipeline import Pipeline, FeatureUnion, make_pipeline, make_union
from sklearn.preprocessing import OneHotEncoder
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.linear_model import LinearRegression
class Columns(BaseEstimator, TransformerMixin):
def __init__(self, names=None):
self.names = names
def fit(self, X, y=None, **fit_params):
return self
def transform(self, X):
return X[self.names]
class Normalize(BaseEstimator, TransformerMixin):
def __init__(self, func=None, func_param={}):
self.func = func
self.func_param = func_param
def transform(self, X):
if self.func != None:
return self.func(X, **self.func_param)
else:
return X
def fit(self, X, y=None, **fit_params):
return self
cat_cols = ['precip', 'dow']
num_cols = ['Temp','tod']
pipe = Pipeline([
("features", FeatureUnion([
('numeric', make_pipeline(Columns(names=num_cols),Normalize())),
('categorical', make_pipeline(Columns(names=cat_cols),OneHotEncoder(sparse=False)))
])),
('model', LinearRegression())
])