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())
])