Pandas: 愿望清单:使get_dummies()可用于培训/测试框架

创建于 2014-11-28  ·  21评论  ·  资料来源: pandas-dev/pandas

在Pandas中拥有get_dummies()确实很棒,但是要对机器学习有用,它必须在火车/测试框架(或使用sklearn术语的“ fit_transform”和“ transform”)中可用。 让我知道是否需要更多解释。

因此,我想这是一个向该熊猫添加该功能的愿望清单错误报告。 如果人们同意,这甚至可以创建一个请求请求,如果这对在Pandas中有帮助的话(并且愿意进行一些指导并进行代码审查,这将是我对该项目的第一贡献)。

Categorical Reshaping Usage Question

最有用的评论

如果要指定_possfully_不可观察的变量,只需要将变量Categorical 。 这可以在创建时或之后完成,请参阅文档

In [5]: df_train = pd.DataFrame({"car":Series(["seat","bmw"]).astype('category',categories=['seat','bmw','mercedes']),"color":["red","green"]})

In [6]: df_train
Out[6]: 
    car  color
0  seat    red
1   bmw  green

In [7]: pd.get_dummies(df_train )
Out[7]: 
   car_seat  car_bmw  car_mercedes  color_green  color_red
0         1        0             0            0          1
1         0        1             0            1          0

最初的问题没有明确说明,因此请关闭。

所有21条评论

以及带有示例帧的输入和输出的伪代码示例如何有用

@ chrish42 ,一个例子会很棒。

FYI scikit-learn具有适合其流水线的OneHotEncoder类。

这样的事情应该工作吗?

import pandas as pd
from sklearn.pipeline import TransformerMixin

class DummyEncoder(TransformerMixin):

    def __init__(self, columns=None):

        self.columns = columns

    def transform(self, X, y=None, **kwargs):

        return pd.get_dummies(X, columns=self.columns)

    def fit(self, X, y=None, **kwargs):

        return self

给予

In [15]: df
Out[15]: 
   A  B  C
0  1  a  a
1  2  b  a

In [16]: DummyEncoder().transform(df)
Out[16]: 
   A  B_a  B_b  C_a
0  1    1    0    1
1  2    0    1    1

注意列的顺序。

@TomAugspurger ,实际上与sklearn处理管道本身的兼容性不是我感兴趣的部分。 我想要的功能是将get_dummes()完成的转换保存到数据集,然后按原样应用所述转换(创建完全相同的列),即使第二个数据集具有第一个值的子集在某些专栏中,等等。这实际上是我所说的“在训练/测试框架中可用”。 这个解释更清楚吗? (我可以添加一个有人认为仍然需要的示例。)

我知道sklearn中的OneHotEncoder类,但是它还有其他限制。

我偶然遇到了与@ chrish42相同的问题,发现get_dummies使我有些头疼。

当前获取假人的局限性示例

让我们假设我们使用以下df_train DataFrame中的数据

`.python
df_train = pandas.DataFrame({“ car”:[“ seat”,“ bmw”],“ color”:[“ red”,“ green”]})
pandas.get_dummies(df_train)

汽车_宝马汽车_座椅颜色_绿色_红色
0 0 1 0 1
1 1 0 1 0


Then we are provided with

``` .python
df_test = pandas.DataFrame({"car":["seat","mercedes"], "color":["red","green"]})
pandas.get_dummies(df_test )

         car_mercedes  car_seat  color_green  color_red
0             0         1            0          1
1             1         0            1          0

由于我从未在df_train中观察到变量“ car”的“ mercedes”值,因此我希望能够获得以下一种热编码:

`.python
汽车_宝马汽车_座椅颜色_绿色_红色
0 0 1 0 1
1 0 0 1 0


Where the column car_mercedes actually never appears.

This could be solved by allowing get_dummies to receive an input dictionary stating the accepted values that we allow for each column.  

Returning to the previous example, we could give as input to get_dummies the following dict of sets

``` .python
accepted_values_per_column = {'car': {'bmw', 'seat'}, 'color': {'green', 'red'}}

我们希望get_dummies返回

`.python
get_dummies(df_test,accepted_values_per_column = accept_values_per_column)

       car_bmw  car_seat  color_green  color_red

0 0 1 0 1
1 0 0 1 0
```

并期望get_dummies(df_test)返回已经返回的内容。

如果要指定_possfully_不可观察的变量,只需要将变量Categorical 。 这可以在创建时或之后完成,请参阅文档

In [5]: df_train = pd.DataFrame({"car":Series(["seat","bmw"]).astype('category',categories=['seat','bmw','mercedes']),"color":["red","green"]})

In [6]: df_train
Out[6]: 
    car  color
0  seat    red
1   bmw  green

In [7]: pd.get_dummies(df_train )
Out[7]: 
   car_seat  car_bmw  car_mercedes  color_green  color_red
0         1        0             0            0          1
1         0        1             0            1          0

最初的问题没有明确说明,因此请关闭。

而当您采用另一种方法时,从编码回到分类,您将使用Categorical.from_codes。

一点点不请自来的建议。 如果您根本不关心分类系数的准确估计,请删除编码列之一,否则截距将具有多重共线性(如果有)。

2015年10月5日,05:34,Jeff Reback [email protected]写道:

如果要指定可能未观察到的变量,只需要将变量分类。 这可以在创建时或之后完成,请参阅文档

在[5]中:df_train = pd.DataFrame({“ car”:Series([“ seat”,“ bmw”])。astype('category',categories = ['seat','bmw','mercedes'] ),“ color”:[“ red”,“ green”]})

在[6]中:df_train
出[6]:
汽车颜色
0座红色
1宝马绿色

在[7]中:pd.get_dummies(df_train)
出[7]:
汽车_座椅汽车_宝马汽车_奔驰颜色_绿色_红色
0 1 0 0 0 1
1 0 1 0 1 0
最初的问题没有明确说明,因此请关闭。

-
直接回复此电子邮件或在GitHub上查看。

@TomAugspurger @jreback我想我最近也遇到了同样的问题,我想举个例子

train_a = pd.DataFrame({“ IsBadBuy”:[0,1,0],“ Make”:['Toyota','Mazda','BMW']})

IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0

test_a = pd.DataFrame({“ Make”:['Toyota','BMW']})
打印pd.get_dummies(test_a,columns = ['Make'])

Make_BMW Make_Toyota
0 0 1
1 1 0

理想情况下,此处应保留Make_Mazda列,因为ML算法将期望具有相同数量的功能,并且我们在测试中获得的值将是训练中的值的子集。

使用分类。 它将扩展为正确的列数。 如果您有兴趣,我就此进行了讨论https://m.youtube.com/watch?v=KLPtEBokqQ0

    _____________________________

来自:阿杰·萨克森纳(Ajay Saxena) [email protected]
发送:2017年1月12日,星期四18:31
主题:回复:[pandas-dev / pandas]愿望清单:使get_dummies()可用于火车/测试框架(#8918)
发送至:pandas-dev / pandas [email protected]
抄送:Tom Augspurger [email protected] ,提及提及@ noreply.github.com

@jreback我想我最近也遇到了同样的问题,我想举个例子

train_a = pd.DataFrame({“ IsBadBuy”:[0,1,0],“ Make”:['Toyota','Mazda','BMW']})

IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0

test_a = pd.DataFrame({“ Make”:['Toyota','BMW']})
打印pd.get_dummies(test_a,columns = ['Make'])

Make_BMW Make_Toyota
0 0 1
1 1 0

理想情况下,此处应保留Make_Mazda列,因为ML算法将期望具有相同数量的功能,并且我们在测试中获得的值将是训练中的值的子集。

-
您收到此邮件是因为有人提到您。
直接回复此电子邮件,在GitHub上查看,或使该线程静音。

谢谢@TomAugspurger

通过@TomAugspurger给出的PyData芝加哥2016会谈是真的做得很好。 他做了出色的工作,说明了不应解决此问题/请求的所有原因。 恕我直言,他的类DummyEncoder或一些合理的等价物都应包含在Pandas中。 是的,我可以转到他的github并复制/模拟他的课程,但是只在库中提供支持会更好。

我认为有必要在数据建模的早期就建立一个库
可以与熊猫和scikit-learn配合使用。
但是熊猫并不依赖于scikit-learn,反之亦然。 我觉得有
在两者之上都建有另一个图书馆的空间。

在2017年5月10日星期三下午6:13,Brian Wylie [email protected]
写道:

@TomAugspurger发表的PyData Chicago 2016演讲
https://github.com/TomAugspurger确实做得很好。 他做了一个
出色的工作,说明了此问题/请求应引起的所有原因
不关门。 恕我直言,要么他的类DummyEncoder要么合理
相应的内容应包含在熊猫专有中。 是的,我可以去他的github
并复制/模仿他的课程,但是拥有它会更好
在库中受支持。

顺便说一句,我认为@TomAugspurger https://github.com/TomAugspurger可能是我的
新的最喜欢的PyData大师。 我要追捕他的一切
完成/正在尝试吸收它..不要以令人毛骨悚然/跟踪的方式..你
只是以一种通常不会令人毛骨悚然的普通方式知道。 :)

-
您收到此邮件是因为有人提到您。
直接回复此电子邮件,在GitHub上查看
https://github.com/pandas-dev/pandas/issues/8918#issuecomment-300638388
或使线程静音
https://github.com/notifications/unsubscribe-auth/ABQHIpTqgHSE7iFVF9Pp4_YoKB9DPLcEks5r4kSrgaJpZM4DB6Hb

这是我们中的一些人尝试的一些解决方案,可能对这里的某些人有所帮助。 具有拟合/转换功能的虚拟变量。

https://github.com/joeddav/get_smarties

反馈和贡献会有所帮助!

这似乎与#14017有关

我创建了一个解决方案,它可能会对这个问题有帮助。 训练测试框架中的一个Hot Encoding分类变量。 它还可以处理数据集太大而无法放入机器内存的情况。

https://github.com/yashu-seth/dummyPy

您还可以在这里找到一个小教程。

@TomAugspurger此代码无效。 当我转换生产单记录数据时,它只为我提供一个热编码列,用于显示当前的单个值。
我想念什么?

导入pyodbc
进口泡菜
从sklearn.linear_model导入LogisticRegression
从sklearn.linear_model导入LinearRegression

将numpy导入为np
将熊猫作为pd导入
从sklearn.pipeline导入TransformerMixin
从sklearn.pipeline导入make_pipeline

DummyEncoder(TransformerMixin)类:
def fit(自我,X,y =无):
self.index_ = X.index
self.columns_ = X.columns
self.cat_columns_ = X.select_dtypes(include = ['category'])。columns
self.non_cat_columns_ = X.columns.drop(self.cat_columns_)

    self.cat_map_ = {col: X[col].cat for col in self.cat_columns_}

    left = len(self.non_cat_columns_)
    self.cat_blocks_ = {}
    for col in self.cat_columns_:
        right = left + len(X[col].cat.categories)
        self.cat_blocks_[col], left = slice(left, right), right
    return self

def transform(self, X, y=None):
    return np.asarray(pd.get_dummies(X))

def inverse_transform(self, X):
    non_cat = pd.DataFrame(X[:, :len(self.non_Cat_columns_)],
                             columns=self.non_cat_columns_)
    cats = []
    for col, cat in self.cat_map_.items():
        slice_ = self.cat_blocks_[col]
        codes = X[:, slice_].argmax(1)
        series = pd.Series(pd.Categorical.from_codes(
                codes, cat.categories, ordered=cat.ordered
        ), name=col)
        cats.append(series)
    df = pd.concat([non_cat] + cats, axis=1)[self.columns_]
    return df

从SQL导入数据到Pandas Dataframe

cnxn = pyodbc.connect('DRIVER = {SQL Server}; SERVER = {XXXXX}; DATABASE = {ML_Learn_Taxi}; UID = {XXXX}; PWD = {XXXX}')
sql =“”“
SELECT top 1 CONVERT(int,[order_key])order_key
,CONVERT(int,[service_date_key])service_date_key
,[order_source_desc]
,1作为'return_flag'
来自[ML_Return_Customer]。[dbo]。[return_customers_test_set]
在哪里[order_source_desc] ='在线'
联盟
SELECT top 2 CONVERT(int,[order_key])
,CONVERT(int,[service_date_key])
,[order_source_desc]
,2
来自[ML_Return_Customer]。[dbo]。[return_customers_test_set]
WHERE [order_source_desc] ='呼入电话'
联盟
SELECT top 1 CONVERT(int,[order_key])
,CONVERT(int,[service_date_key])
,[order_source_desc]
,1
来自[ML_Return_Customer]。[dbo]。[return_customers_test_set]
WHERE [order_source_desc] ='呼出电话'
“”

prod_sql =“”“
SELECT top 1 CONVERT(int,[order_key])order_key
,CONVERT(int,[service_date_key])service_date_key
,[order_source_desc]
,1作为'return_flag'
来自[ML_Return_Customer]。[dbo]。[return_customers_test_set]
在哪里[order_source_desc] ='在线'
“”

InputDataSet = pd.read_sql(sql,cnxn)
ProdDataSet = pd.read_sql(prod_sql,cnxn)

print(“ * * * *数据

* * * * *“)
打印(InputDataSet)

print(“ * *类别列信息

* * “)
列= ['order_source_desc']
InputDataSet [columns] = InputDataSet [columns] .apply(lambda x:x.astype('category'))

InputDataSet.info()

print(“ *线性回归

* * “)

X = InputDataSet.drop('return_flag',axis = 1)
y = InputDataSet ['return_flag']

A = ProdDataSet.drop('return_flag',axis = 1)
B = ProdDataSet ['return_flag']

enc = DummyEncoder()
enc.fit(X)

雨= enc.transform(X)

产品= enc.transform(A)

打印(产品)

输出: * * * *数据

* * * *
order_key service_date_key order_source_desc return_flag
0 10087937 20151214在线1
1 10088174 20151201呼入电话2
2 10088553 20151217呼入电话2
3663478 20160806呼出电话1
*类别列信息* *

RangeIndex:4个条目(0到3)
数据列(共4列):
order_key 4非空int64
service_date_key 4非空int64
order_source_desc 4非空类别
return_flag 4非null int64
dtypes:category(1),int64(3)
内存使用量:284.0字节
*线性回归* * *
[[10087937 20151214 1]]

因此,我认为该线程有点混乱,因此我将在这里尝试总结一个简单的解决方案,以及如何实现这一点。 我将在一个专栏中进行演示,但是您可以将其概括为许多。

因此,在“适合”通话中,您只需执行以下操作:

categories = sorted(training_data.iloc[:, column_index].value_counts(dropna=True).index)

您将categories到拟合期间要学习的状态。

然后在“转换”中执行:

from pandas.api import types as pandas_types

categorical_data = testing_data.iloc[:, [column_index]].astype(
    pandas_types.CategoricalDtype(categories=categories),
)
one_hot_encoded = pandas.get_dummies(categorical_data)

并且它将始终在相同的值映射中进行一键编码。 如果在训练期间不存在某些分类值,则在测试期间将其视为NaN。 如果在测试期间看不到某个值,则不会为其设置任何列。

这是非常好的。 我只是希望每个想要这样做的人都不必重新发现它。 ;-)

@mitar建议的方法是一个很好的简短示例。 对于这个问题的更长时间的探索,这里有一个可能有用/有用的笔记本: https :

在Kaggle XGBoost教程的练习中看到了下面的代码。 这可以解决问题。

X_train = pd.get_dummies(X_train)
X_valid = pd.get_dummies(X_valid)
X_test = pd.get_dummies(X_test)
X_train, X_valid = X_train.align(X_valid, join='left', axis=1)
X_train, X_test = X_train.align(X_test, join='left', axis=1)

我也多次遇到相同的问题。 我在下面写了一堂课(从这次讨论中汲取了想法),这对我来说使事情变得更容易。

import pandas
from sklearn.preprocessing import LabelEncoder

class CategoryEncoder:
    '''
    labelEncoding : boolean -> True If the categorical columns are to be label encoded
    oneHotEncoding : boolean -> True If the categorical columns are to be one hot encoded (using pandas.get_dummies method)
    dropFirst : boolean -> True if first column is to be dropped (usually to avoid multi-collinearity) post one hot encoding
                           Doesn't matter if oneHotEncoding = False

    df : pandas.DataFrame() -> dataframe object that needs to be encoded
    catCols : list -> list of the categorical columns that need to be encoded
    '''
    def __init__(self,labelEncoding=True,oneHotEncoding=False,dropFirst=False):
        self.labelEncoding = labelEncoding
        self.oneHotEncoding = oneHotEncoding
        self.dropFirst = dropFirst
        self.labelEncoder = {}
        self.oneHotEncoder = {}

    def fit(self,df,catCols=[]):
        df1 = df.copy()
        if self.labelEncoding:
            for col in catCols:
                labelEncoder = LabelEncoder()
                labelEncoder.fit(df1.loc[:,col].astype(str))
                df1.loc[:,col] = labelEncoder.transform(df1.loc[:,col])
                self.labelEncoder[col] = labelEncoder.classes_

        if self.oneHotEncoding:
            for col in catCols:
                cats = sorted(df1.loc[:,col].value_counts(dropna=True).index)
                self.oneHotEncoder[col] = cats

    def transform(self,df,catCols=[]):
        df1 = df.copy()
        if self.labelEncoding:
            for col in catCols:
                labelEncoder = self.labelEncoder[col]
                labelEncoder = {v:i for i,v in enumerate(labelEncoder.tolist())}
                print(labelEncoder)
                df1.loc[:,col] = df1.loc[:,col].map(labelEncoder)

        if self.oneHotEncoding:
            for col in catCols:
                oneHotEncoder = self.oneHotEncoder[col]
                df1.loc[:,col] = df1.loc[:,col].astype(pandas.CategoricalDtype(categories=oneHotEncoder))
            df1 = pandas.get_dummies(df1,columns=catCols,drop_first=self.dropFirst)

        return df1

易于初始化和使用编码器实例。

enc1 = CategoryEncoder(True,False)     # Will label encode but not one-hot encode
enc2 = CategoryEncoder(False,True,True)     # Will one-hot encode but not label encode
enc3 = CategoryEncoder(True,True,True)     # Will label encode first and then one-hot encode

# List of categorical columns you want to encode
categorical_columns = ['col_1', 'col_2']

enc1.fit(train_df, categorical_columns)
enc1.transform(test_df, categorical_columns) # Returns the dataframe encoded columns

注意:这将不会处理任何异常,例如,传递数据框中不可用的列名

此页面是否有帮助?
0 / 5 - 0 等级