将日期拆分为新列的自定义转换器



我正在遵循github上sklearn_pandas README上的sklearn_paandas遍历,并试图修改DateEncode()自定义转换器示例以做两件额外的事情:

  • 将字符串类型的列转换为datetime,同时将日期格式作为参数
  • 在吐出新列时附加原始列名。例如:如果输入列:Date1,则输出:Date1_year、Date1_month、Date_1 day

以下是我的尝试(对sklearn管道有相当初步的了解):

import pandas as pd
import numpy as np
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn_pandas import DataFrameMapper
class DateEncoder(TransformerMixin):
'''
Specify date format using python strftime formats
'''
def __init__(self, date_format='%Y-%m-%d'):
self.date_format = date_format
def fit(self, X, y=None):
self.dt = pd.to_datetime(X, format=self.date_format)
return self
def transform(self, X):
dt = X.dt
return pd.concat([dt.year, dt.month, dt.day], axis=1)

data = pd.DataFrame({'dates1': ['2001-12-20','2002-10-21','2003-08-22','2004-08-23', 
'2004-07-20','2007-12-21','2006-12-22','2003-04-23'],   
'dates2'  : ['2012-12-20','2009-10-21','2016-08-22','2017-08-23', 
'2014-07-20','2011-12-21','2014-12-22','2015-04-23']})
DATE_COLS = ['dates1', 'dates2']
Mapper = DataFrameMapper([(i, DateEncoder(date_format='%Y-%m-%d')) for i in DATE_COLS], input_df=True, df_out=True)
test = Mapper.fit_transform(data)

但在运行时,我得到以下错误:

AttributeError: Can only use .dt accessor with datetimelike values

为什么我会出现这个错误,以及如何修复它?此外,如果您能帮助将上述列名重命名为原始列(Date1_year、Date1_month、Date_1 day),我们将不胜感激!

我知道这已经很晚了,但如果您仍然对使用自定义转换器重命名列的方法感兴趣。。。

我使用了将方法get_feature_names添加到具有ColumnTransformer的管道内的自定义转换器的方法(概述)。然后,您可以使用.named_steps属性访问管道的步骤,然后访问get_feature_names,然后获得column_names,它最终保存要使用的自定义列名的名称。通过这种方式,您可以检索列名,类似于本SO文章中的方法。

我不得不用管道来运行它,因为当我试图将其作为一个独立的自定义转换器时,它出现了严重的错误(所以我不会在这里发布那个不完整的尝试)——尽管你可能运气更好。

这是显示管道的原始代码

import pandas as pd
from sklearn.base import TransformerMixin
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

data2 = pd.DataFrame(
{"dates1": ["2001-12-20", "2002-10-21", "2003-08-22", "2004-08-23",
"2004-07-20", "2007-12-21", "2006-12-22", "2003-04-23"
], "dates2": ["2012-12-20", "2009-10-21", "2016-08-22", "2017-08-23",
"2014-07-20", "2011-12-21", "2014-12-22", "2015-04-23"]})
DATE_COLS = ['dates1', 'dates2']
pipeline = Pipeline([
('transform', ColumnTransformer([
('datetimes', Pipeline([
('formatter', DateFormatter()), ('encoder', DateEncoder()),
]), DATE_COLS),
])),
])
data3 = pd.DataFrame(pipeline.fit_transform(data2))
data3_names = (
pipeline.named_steps['transform']
.named_transformers_['datetimes']
.named_steps['encoder']
.get_feature_names()
)
data3.columns = data3_names
print(data2)
print(data3)

输出为

dates1      dates2
0  2001-12-20  2012-12-20
1  2002-10-21  2009-10-21
2  2003-08-22  2016-08-22
3  2004-08-23  2017-08-23
4  2004-07-20  2014-07-20
5  2007-12-21  2011-12-21
6  2006-12-22  2014-12-22
7  2003-04-23  2015-04-23
dates1_year  dates1_month  dates1_day  dates2_year  dates2_month  dates2_day
0         2001            12          20         2012            12          20
1         2002            10          21         2009            10          21
2         2003             8          22         2016             8          22
3         2004             8          23         2017             8          23
4         2004             7          20         2014             7          20
5         2007            12          21         2011            12          21
6         2006            12          22         2014            12          22
7         2003             4          23         2015             4          23

自定义变压器在这里(跳过DateFormatter,因为它与您的相同)

class DateEncoder(TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X):
dfs = []
self.column_names = []
for column in X:
dt = X[column].dt
# Assign custom column names
newcolumnnames = [column+'_'+col for col in ['year', 'month', 'day']]
df_dt = pd.concat([dt.year, dt.month, dt.day], axis=1)
# Append DF to list to assemble list of DFs
dfs.append(df_dt)
# Append single DF's column names to blank list
self.column_names.append(newcolumnnames)
# Horizontally concatenate list of DFs
dfs_dt = pd.concat(dfs, axis=1)
return dfs_dt
def get_feature_names(self):
# Flatten list of column names
self.column_names = [c for sublist in self.column_names for c in sublist]
return self.column_names

DateEncoder的基本原理

pandas列上的循环允许从每个日期时间列中提取日期时间属性。在同一个循环中,将构造自定义列名。然后将它们添加到self.column_names下的空白列表中,该列表在方法get_feature_names中返回(尽管在分配给数据帧之前必须对其进行展平)。

对于这种特殊情况,您可能会跳过sklearn_pandas

详细信息

sklearn = 0.20.0
pandas = 0.23.4
numpy = 1.15.2
python = 2.7.15rc1

我能够将数据格式转换和日期拆分器分解为两个独立的转换器,并且它起到了作用。

import pandas as pd
from sklearn.base import TransformerMixin
from sklearn_pandas import DataFrameMapper

data2 = pd.DataFrame({'dates1': ['2001-12-20','2002-10-21','2003-08-22','2004-08-23', 
'2004-07-20','2007-12-21','2006-12-22','2003-04-23'],   
'dates2'  : ['2012-12-20','2009-10-21','2016-08-22','2017-08-23', 
'2014-07-20','2011-12-21','2014-12-22','2015-04-23']})
class DateFormatter(TransformerMixin):
def fit(self, X, y=None):
# stateless transformer
return self
def transform(self, X):
# assumes X is a DataFrame
Xdate = X.apply(pd.to_datetime)
return Xdate

class DateEncoder(TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X):
dt = X.dt
return pd.concat([dt.year, dt.month, dt.day], axis=1)

DATE_COLS = ['dates1', 'dates2']
datemult = DataFrameMapper(
[ (i,[DateFormatter(),DateEncoder()]) for i in DATE_COLS     ] 
, input_df=True, df_out=True)
df = datemult.fit_transform(data2)

该代码输出:

Out[4]: 
dates1_0  dates1_1  dates1_2  dates2_0  dates2_1  dates2_2
0      2001        12        20      2012        12        20
1      2002        10        21      2009        10        21
2      2003         8        22      2016         8        22
3      2004         8        23      2017         8        23
4      2004         7        20      2014         7        20
5      2007        12        21      2011        12        21
6      2006        12        22      2014        12        22
7      2003         4        23      2015         4        23

然而,我仍在寻找一种方法来重命名新列,同时应用DateEncoder()转换器。例如:dates_1_0->dates_1_yeardates_2_2->dates_2_month。我很乐意选择它作为解决方案。

相关内容

  • 没有找到相关文章

最新更新