Kaggle:Elo顾客忠诚度预测问题
1. 问题分析
Elo是巴西最大的支付品牌之一,与商家建立了合作伙伴关系,以便为持卡人提供促销或折扣。但这些促销活动是否适用于消费者或商家?客户是否喜欢他们的体验?在此次竞赛中,将通过揭示客户忠诚度中的信号,开发算法来识别并为消费者提供最相关的促销或折扣机会。
1.1 提供的数据文件:
我们先来看一下提供的数据文件:
import os
print(os.listdir("../input"))
data_Dictionary.xlsx :各文件内各列数据的描述文件,有助于我们更好的理解数据信息。
historical_transactions: 每个card_id的消费历史,最多3个月的历史交易,共有2千9百多万条。
new_merchant_transactions:测评期的消费数据,每个card_id在新商店的消费,近2百万条
merchants:商户的信息数据
train:训练集
test: 验证集
sample_submission:提交数据样本
1.2 具体任务:
根据历史数据,侧重特征工程处理,预测每个card_id的忠诚度分数
2. 数据预处理与分析
2.1 train 和 test文件
train_data=pd.read_csv('../input/train.csv', sep=',',header=0)
test_data=pd.read_csv('../input/test.csv', sep=',',header=0)
train_data.info()
test_data.info()
从上图可以看出 train set 含有201917个数据样本,test set 含有123623个数据样本。test set 与train set 的区别在于没有target这也此次任务需要预测。
针对每个card_id 有 first_active_month,feature_1, feature_2, feature_3 这类特征,target是每个card_id 的忠诚度分数。
2.2 historical_transactions 和 new_transactions文件
先将historical_transactions 和 new_transactions文件 导入:
history_data=pd.read_csv('../input/historical_transactions.csv', sep=',',header=0)
new_data = pd.read_csv('../input/new_merchant_transactions.csv',sep=',',header=0)
history_data.info()
new_data.info()
从上图可以看出historical_transactions 和 new_transactions文件中各有14维信息,与train和test集的关联点在card_id。
3. 特征工程构建
3.1 train 和test集
3.1.1 Convert time as features
针对train 和test集上的 first_active_month 这一信息,将时间特征提取出来:‘year’,‘month’,‘elapsed_time’,‘quarter’,‘weekofyear’,‘dayofyear’,‘weekend’。
# In[] 先将train 中target这一列提出来
train_target=np.array(train_data['target'])
# In[]
# Convert time as features
for data in [train_data,test_data]:
data.fillna(0)
data['first_active_month'] = pd.to_datetime(data['first_active_month'])
data['year'] = data['first_active_month'].dt.year
data['month'] = data['first_active_month'].dt.month
#first_active_month_max=data['first_active_month'].dt.date.max()
data['elapsed_time'] = (datetime.date(2018, 2, 1) - data['first_active_month'].dt.date).dt.days
data['dayofweek'] = data['first_active_month'].dt.dayofweek
data['weekofyear'] = data['first_active_month'].dt.weekofyear
data['dayofyear'] = data['first_active_month'].dt.dayofyear
data['quarter'] = data['first_active_month'].dt.quarter
#data['is_month_start'] = data['first_active_month'].dt.is_month_start
data['weekend'] = (data.first_active_month.dt.weekday >=5).astype(int)
train_data.info()
test_data.info()
3.2 historical_transactions 和 new_transactions文件
3.2.1 处理缺省值,并one-hot表达
针对 historical_transactions 和 new_transactions文件,
-
处理’category_2’,'category_3’中的缺省值,并将其以one-hot形式表达,
** data = pd.get_dummies(data, columns=[‘cat2’, ‘cat3’]) ** -
将’authorized_flag’, 'category_1’中的特征字符Y/N表示,转为0/1表示:
** data[sub_cate] = data[sub_cate].apply(lambda x: 1 if x == ‘Y’ else 0)**
def category_convert(data):
#data.fillna(0)
data['category_2']=data['category_2'].fillna(data['category_2'].mode()[0])
data['category_3']=data['category_3'].fillna(data['category_3'].mode()[0])
data['merchant_id']=data['merchant_id'].fillna("None")
print("There are ",data.isnull().sum().sum(), 'missing data remains in df.')
data['cat2'] = data['category_2']
data['cat3'] = data['category_3']
data = pd.get_dummies(data, columns=['cat2', 'cat3']) #one hot 的形式
for sub_cate in ['authorized_flag', 'category_1']:
data[sub_cate] = data[sub_cate].apply(lambda x: 1 if x == 'Y' else 0)
return data
history_data=category_convert(history_data)
new_data=category_convert(new_data)
# In[]
history_data.info()
new_data.info()
从上图可以看出,数据多了8 columns,‘category_2’ 的值有五类(1,2,3,4,5),将其one-hot 后 产生了5 columns。‘category_3’ 的值有三类(A,B,C),将其one-hot 后 产生了3 columns。此外, 将’authorized_flag’, 'category_1’中的特征字符Y/N表示,转为0/1表示,数据类型由object 变成了int64。
3.2.2 从’purchase_date’提取时间信息, 以及
# Code from: Chau Ngoc Huynh - "My first kernel (3.699)" & Mitsuru Fujiwara - "Simple LightGBM without blending
def Feature_Engineering(data):
# devide time
data['purchase_date'] = pd.to_datetime(data['purchase_date'])
data['month_diff'] = ((datetime.datetime.today() - data['purchase_date']).dt.days)//30
data['month_diff'] += data['month_lag']
data['purchase_year'] = data['purchase_date'].dt.year
data['purchase_month'] = data['purchase_date'].dt.month
data['weekofyear'] = data['purchase_date'].dt.weekofyear
data['dayofyear'] = data['purchase_date'].dt.dayofyear
data['dayofweek'] = data['purchase_date'].dt.dayofweek
data['weekend'] = (data.purchase_date.dt.weekday >=5).astype(int)
#data['hour'] = data['purchase_date'].dt.hour
#data['day']=data['purchase_date'].dt.day
data['quarter'] = data['purchase_date'].dt.quarter
data['purchase_amount_new'] = np.round(data['purchase_amount'] / 0.00150265118 + 497.06,8)
#data['duration'] = data['purchase_amount']*data['month_diff']
#data['amount_month_ratio'] = data['purchase_amount']/data['month_diff']
#data['price']=data['purchase_amount']/data['installments']
data['Christmas_Day_2017']=(pd.to_datetime('2017-12-25')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
#Mothers Day: May 14 2017
data['Mothers_Day_2017']=(pd.to_datetime('2017-06-04')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
data['fathers_day_2017']=(pd.to_datetime('2017-08-13')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
data['Children_day_2017']=(pd.to_datetime('2017-10-12')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
data['Valentine_Day_2017']=(pd.to_datetime('2017-06-12')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
data['Black_Friday_2017']=(pd.to_datetime('2017-11-24') - data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
data['Mothers_Day_2018']=(pd.to_datetime('2018-05-13')-data['purchase_date']).dt.days.apply(lambda x: x if x > 0 and x < 100 else 0)
return data
history_data = Feature_Engineering(history_data)
new_data = Feature_Engineering(new_data)
history_data.info()
new_data.info()