如何对列的子集进行热编码?

时间:2018-01-19 19:37:23

标签: 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

此处,dowprecip是分类,其他是连续的。

有没有办法可以为这些列创建OneHotEncoder?我不想使用pd.get_dummies,因为除非每个dowprecip都在新数据中,否则不会将数据放入正确的格式。

3 个答案:

答案 0 :(得分:3)

您可以查看的两件事:sklearn-pandas以及@Grr pipelines提到的这件事intro

所以我更喜欢管道,因为它们是一种整洁的方式,允许使用像网格搜索这样的东西,避免交叉验证中的折叠之间的泄漏等。所以我通常最终得到这样的管道(假设你有沉淀LabelEncoded first):

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

答案 1 :(得分:2)

简短的回答是肯定的,但有一些警告。

首先,您无法直接在precip功能上使用OneHotEncoder。您需要使用LabelEncoder将这些标签编码为整数。

其次,如果您只想对这些功能进行编码,则可以将适当的值传递给n_valuescategorical_features参数。

示例:

我假设dow是一周中的某一天,它将有七个值,而降水将有(雨,雨夹雪,雪和混合)作为值。

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

好的,但是你必须要么改变你的数据或创建副本,事情会变得有点混乱。更有条理的方法是使用Pipeline

from sklearn.preprocessing import FunctionTransformer
from sklearn.pipeline import FeatureUnion, Pipeline

def get_precip(X):
    le = LabelEncoder()
    le.fit(['rain', 'sleet', 'snow', 'mix'])
    return le.transform(X.precip).reshape(-1,1)

def get_dow(X):
    return X.dow.values.reshape(-1,1)

def get_rest(X):
    return X.drop(['precip', 'dow'], axis=1)

precip_trans = FunctionTransformer(get_precip, validate=False)
dow_trans = FunctionTransformer(get_dow, validate=False)
rest_trans = FunctionTransformer(get_rest, validate=False)
union = FeatureUnion([('precip', precip_trans), ('dow', dow_trans), ('rest', rest_trans)])
ohe = OneHotEncoder(n_values=[4,7], categorical_features=[0,1])
pipe = Pipeline([('union', union), ('one_hot', ohe)])
X = pipe.fit_transform(df)
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中,会有一个CategoricalEncoder,这会使这种事情变得更加容易。

答案 2 :(得分:1)

  

我不想使用 xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun error: command '/usr/bin/clang' failed with exit status 1 Command "/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 -u -c "import setuptools, tokenize;__file__='/private/var/folders/lp/jxxpxhsn17l_mvy8wsg953m80000gn/T/pip-build-qr4i977k/kivy/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /var/folders/lp/jxxpxhsn17l_mvy8wsg953m80000gn/T/pip-j52ad4nr-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /private/var/folders/lp/jxxpxhsn17l_mvy8wsg953m80000gn/T/pip-build-qr4i977k/kivy/ ,因为它不会将数据放入   正确的格式,除非每个道具和降水都在新数据中。

假设你想要编码但又保留这两列 - 你确定这对你不起作用吗?

pd.get_dummies

如果您要与包含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

您传递设定差异列表的位置。这增加了"被识别的"生成的df['col'] = df['col'].cat.add_categories(...) 对象的类别。