今天要分析的一个kernel是一个关于elo的loyalty关于时间序列的关系的研究的kernel。
关于竞赛介绍及基础知识见:
我的上一篇内核分析:https://blog.csdn.net/ssswill/article/details/85217702
这篇kernel来自:
A Closer Look at Date Variables

写在前面:个人认为这篇kernel与比赛关系不大,之所以分析它是因为里面有很多图像可视化的画法,对后面的学习肯定是有帮助的,同时这篇kernel包含了很多对时间变量的处理,也是很常见的一种处理方式,基于这两点原因,我觉得还是做一些分析留作知识储备。
同时,kaggle系列博客会一直更新下去。但是仅适用于新手入门学习使用,在放假时,我会抽出时间写出kaggle很多实用的功能与小提示,例如数据集的创建,本地训练结果的提交等,网上关于这方面的东西还是很少的,我之前也是踩过一些坑。所以希望写出来希望可以帮助一些刚接触kaggle的人。
好了,话不多说,直接开始这篇kernel的学习吧!
我们再来稍微回顾下这个elo推荐竞赛,是给你一些用户的数据,让你来预测用户的忠诚度target。这是一个回归问题。同时,用户信息包含了一些时间序列,例如用户第一次活跃的时间,以及每一次消费的时间。这些肯定很重要,但是有一些时间量我个人认为这些不会影响target,或者影响的比较少。例如不能说一个经常在周二买东西的人忠诚度就会比经常在周三买的人高,也不能说经常早上消费的人忠诚度就要比晚上消费的高。但这都是直观看法,带着这些疑问来走进这篇kernel吧!

import warnings
import datetime
import calendar
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from datetime import time
from dateutil.relativedelta import relativedelta
# to ignore future warnings,忽略warning
warnings.simplefilter(action = 'ignore', category = FutureWarning)
# set size of seaborn plots
sns.set(rc={'figure.figsize':(10, 7)})
## read data
train = pd.read_csv('../input/train.csv', sep = ',')
test = pd.read_csv('../input/test.csv', sep = ',')
merchants = pd.read_csv('../input/merchants.csv', sep = ',')
new_merchant = pd.read_csv('../input/new_merchant_transactions.csv', sep = ',')

这里sep是分隔符的意思。默认分隔符就是逗号,所以不用在意。

train.head()


再来看看merchants(商人信息)与new_merchant(参考日期之后的购物记录)

## prepare data
# this is not a valid approach if you want to build models from the data
#有一些重复列都去掉了。
# drop some redundant columns
dropping = ['merchant_category_id', 'subsector_id', 'category_1', 'city_id', 'state_id','category_2']
for var in dropping:merchants = merchants.drop(var, axis = 1)
# merge merchants with new_merchants
data = pd.merge(merchants, new_merchant, on = 'merchant_id')# merge data with train data
data = pd.merge(data, train, on = 'card_id')

第一个data是融合了merchants, new_merchant的df,可以看到二者有相同的列,所以在上面代码中去掉了一些重复的列,合并后是一个扩展版的用户购物信息。
之后再与train合并。得到了最终研究的数据:


这两张图都是一个dataframe的。
这个df是用户在参考日期之后2个月购物信息的完整版。但是这里没有做history的信息,但是思路是类似的。

The variables in question here are *first_active_month*
and *purchase_time*.
Let's take a brief look at their number of unique valuesand the first five values:

上面这些英文意思就是:虽然表格里信息很多,但是我们现在研究的是时间序列,所以只关注first_active_monthpurchase_time. 两列信息。first_active_month就是这张卡第一次激活或者活跃的时间,purchase_time是这张卡每次购物的时间。所以:来看看这两个量有多少个不同的值与大概信息
所以:
对于每个用户,或者每个卡,他们的first_active_month都只有一个,但是purchase_time可能不是唯一一个,因为每张卡不可能都只购物一次。
好了,理清楚这个了,继续往下走:

print(len(data['first_active_month'].unique()))
#print(data['first_active_month'].nunique())与上句一样意思
data['first_active_month'][:5]
74
0    2013-11
1    2013-11
2    2013-11
3    2013-11
4    2013-11
Name: first_active_month, dtype: object
data['first_active_month'].min()

输出:

'2011-11'

同样的:

print(len(data['purchase_date'].unique()))
data['purchase_date'][:5]
1082077
0    2018-04-11 11:45:08
1    2018-03-26 15:40:28
2    2018-04-20 20:43:36
3    2018-03-26 14:01:49
4    2018-03-31 07:55:33
Name: purchase_date, dtype: object

而一共有len(data)=1223315条消费信息。其中108万条的消费时间不同。怎么说呢。我觉得挺正常的的,因为这个数据是精确到秒的,在同一秒买东西的人本来肯定就不多,但是kernel作者说了:

This shows us that the *purchase_date* variable actually
carrys more information than it's name makes it sound like.
It's not only the date, but also the specific time.
Let's recode this into two variables:

他意思就是这个数据很重要。

# recode purchase_date
data['purchase_time'] = data['purchase_date'].str.split(' ')
data['purchase_date'] = data['purchase_time'].str[0]
data['purchase_time'] = data['purchase_time'].str[1]

上面的购买时间 2018-03-31 07:55:33是以空格分开的,前半段为日期,后半段为具体几点这样。
时间量找到后,就是对他进行处理了:
之后作者说:

Now there are two different strategies to use these time
variables in further models.
1.Recode them to a linear variable where the lowest number is the
day furthest in the past and the highest number the most recent day
2.Recode them to ordered categorical variables
Let's start with number 1:

有两种处理方式,作者先用方式1,就是把日期当成一个个从小到大排列的数。
为了理解下面的重要代码,必须要介绍两个函数:
由字符串格式转化为日期格式(tuple)的函数为: datetime.datetime.strptime()
由日期格式(tuple)转化为字符串格式的函数为: datetime.datetime.strftime()
https://blog.csdn.net/ljh0302/article/details/54882750

def dates_to_numeric(series, kind = 'month'):# get all unique valuesmonths = list(series.unique())# sort themif kind == 'month':date_string = "%Y-%m"elif kind == 'day':date_string = "%Y-%m-%d"# make them a datetime objectdates = [datetime.datetime.strptime(ts, date_string) for ts in months]dates.sort()sorteddates = [datetime.datetime.strftime(ts, date_string) for ts in dates]# generate all month stamps between first and laststart_date = sorteddates[0]end_date = sorteddates[len(sorteddates) - 1]cur_date = start = datetime.datetime.strptime(start_date, date_string).date()end = datetime.datetime.strptime(end_date, date_string).date()months = []while cur_date < end:if kind == 'month':months.append(str(cur_date)[:-3])cur_date += relativedelta(months = 1)elif kind == 'day':months.append(str(cur_date))cur_date += relativedelta(days = 1)# create dict that maps new values to each monthmap_dict = {}keys = range(0, len(months))for i in keys:map_dict[i] = months[i]# reverse dict keys / values for mappingnew_dict = {v: k for k, v in map_dict.items()}return new_dictnew_dict = dates_to_numeric(data['first_active_month'])
data['first_active_month_numeric'] = data['first_active_month'].apply(lambda x: new_dict.get(x))new_dict = dates_to_numeric(data['purchase_date'], kind = 'day')
data['purchase_date_numeric'] = data['purchase_date'].apply(lambda x: new_dict.get(x))# recode timestamp to number of seconds passed since 00:00:00
def timestamp_to_seconds(time):seconds = sum(x * int(t) for x, t in zip([3600, 60, 1], time.split(':'))) return secondsdata['purchase_seconds'] = data['purchase_time'].apply(lambda x: timestamp_to_seconds(x))

其实,关于这部分代码,内容量就十分丰富了,我觉得搞懂这个还是很有必要的,因为对于时间序列的处理这部分代码给了很好的范例,所以写到这里,我决定对这部分代码深挖,如果写的比较长,那么剩下的内容会发到另一篇博客。原因还是那句话,太长了我自己都不想看,别说别人了。
ok。先看这个函数名,date_to_numeircal就知道是把时间量转为数字量的。有两个参数,一个是series。可以理解为要喂进去的一个df的一个时间的列。kind就是strptime函数与strftime函数需要的参数。这两个函数都是把时间的字符串与时间量相互转换的函数,需要一个format。这个format就是说你要转的这个时间量是什么格式的,这个format在我们这就是kind参数。具体查看我上面给的链接。

    # get all unique valuesmonths = list(series.unique())

代码段第一句:把series中不重复的量转为一个list。举例:

months = list(data.first_active_month.unique())
months


输出如上图的一个时间列表。
接下来我以kind==month为例。

    dates = [datetime.datetime.strptime(ts, date_string) for ts in months]

这句话就是把上面的时间量string转为元组型时间量。

这也就是strptime函数的用法啦

dates.sort()

列表的排序,排序完:

sorteddates = [datetime.datetime.strftime(ts, date_string) for ts in dates]

排序之后,再用strftime函数转为字符串型时间。

继续分析:

    # generate all month stamps between first and laststart_date = sorteddates[0]end_date = sorteddates[len(sorteddates) - 1]cur_date = start = datetime.datetime.strptime(start_date, date_string).date()end = datetime.datetime.strptime(end_date, date_string).date()
print(cur_date)
print(end)

output:

2011-11-01
2018-01-01

关于时间戳,struct_time元组等知识建议参考:
http://www.runoob.com/python/python-date-time.html

python官网
https://docs.python.org/3/library/datetime.html#time-objects
继续:

    months = []while cur_date < end:if kind == 'month':months.append(str(cur_date)[:-3])cur_date += relativedelta(months = 1)elif kind == 'day':months.append(str(cur_date))cur_date += relativedelta(days = 1)

这个应该不难理解,为什么kind为month时候不取最后三位。而kind为day时候不会这样。因为对于kind=month是为了first_active_month服务的,这一列本来就没精确到一个月的第几天。所以只精确到月。
输出:

这一列打箭头的那个原数据是没有的。

    # create dict that maps new values to each monthmap_dict = {}keys = range(0, len(months))for i in keys:map_dict[i] = months[i]

创建一个用于apply的字典:

代码块的最后一部分:

    # reverse dict keys / values for mappingnew_dict = {v: k for k, v in map_dict.items()}


这个看似复杂的函数被我们解析之后,也就清晰很多了,剩下的就是调用这个函数了:

new_dict = dates_to_numeric(data['first_active_month'])
data['first_active_month_numeric'] = data['first_active_month'].apply(lambda x: new_dict.get(x))new_dict = dates_to_numeric(data['purchase_date'], kind = 'day')
data['purchase_date_numeric'] = data['purchase_date'].apply(lambda x: new_dict.get(x))# recode timestamp to number of seconds passed since 00:00:00
def timestamp_to_seconds(time):seconds = sum(x * int(t) for x, t in zip([3600, 60, 1], time.split(':'))) return secondsdata['purchase_seconds'] = data['purchase_time'].apply(lambda x: timestamp_to_seconds(x))

也就是说。时序量被我们转化为了0,1,2,3这样的数字。最小为0,最大的为len()-1。单位为month,day。至于那个转化为秒的也很好理解。
新增加的三列:

在完成转化后,就可以做图分析规律了!

ax = sns.regplot(x = data['first_active_month_numeric'], y = data['target'], marker = "+",lowess = True, line_kws = {'color': 'black'})
ax.set_title('Relationship of the target variable and linear first active month')
ax.set_xlabel('first active month linear')


可以看到,资历越老的用户,target的正负值的绝对值都越大。值得深思。同时基本关于target轴对称。最下面的那一行就是outlier了,有2207个呢,可见他们基本每个时间段也都有的。
同样的,对于购买时间:

ax = sns.regplot(x = data['purchase_date_numeric'], y = data['target'], marker = "+",lowess = True, line_kws = {'color': 'black'})
ax.set_title('Relationship of the target variable and linear purchase date')
ax.set_xlabel('purchase date linear')


这个图,,规律就更难看出来了。同时,其实理性分析,这些图是有问题的,因为你无法保证这些横坐标也就是purchase day来自的客户是否一致,他们肯定很多都是不相同的,但是又有的是相同的。
最后,关于这个sns.regplot函数。还是有必要学习下的。
参考:
https://blog.csdn.net/wuwan5296/article/details/78698125
regplot()和lmplot()都是seaborn的函数,都可以绘制线性回归曲线。这两个函数非常相似,甚至共有一些核心功能。
在最简单的调用中,两个函数都会画出双变量的散点图,然后以y~x拟合回归方程和预测值95%置信区间并将其画出

sns.regplot(x="total_bill", y="tip", data=tips);

或者:

sns.lmplot(x="total_bill", y="tip", data=tips);

二者区别很小:

实际上官方手册这里解释的并不直观。两者区别在于sns.regplot(x=tips[‘total_bill’],y=tips[‘tip’])可以运行,data=~这个参数不必要。
但是sns.lmplot(x=tips[‘total_bill’], y=tips[‘tip’], data=tips)就必须传入data=~参数
seaborn官网:
http://seaborn.pydata.org/generated/seaborn.regplot.html

一些regplot画的图:
(实际上他就是在散点图的基础上近似画出一条直线(也可以是曲线))来拟合两个变量的关系,例如这样:

或者这样:

但是,为啥我们在这里值画出了散点图并没有一条拟合的线呢,其实不是没画,target=0那条线就是。。。
散点图长这样:

plt.scatter(x = data['first_active_month_numeric'], y = data['target'], marker = "+",)


所以作者在这里也说:

These plot show no relationship between the metric versions of the three date variables and the target variable. By using the lowess smoother instead of a linear regression we also made sure there is no nonlinear relationship between the two variables.

作者说用了lowess参数确定了不仅是线性关系没有,非线性关系也没有。。。
这里提及到regplot的一个参数:lowess = True
从官网我们知道:

用statsmodels来拟合,感觉更高级了,赶集来看看statsmodles是啥:
http://www.statsmodels.org/stable/index.html
statsmodels是一个有很多统计模型的python库,能完成很多统计测试,数据探索以及可视化。它也包含一些经典的统计方法,比如贝叶斯方法和一个机器学习的模型。
statsmodels中的模型包括:
线性模型(linear models),广义线性模型(generalized linear models),鲁棒线性模型(robust linear models)
线性混合效应模型(Linear mixed effects models)
方差分析(ANOVA)方法(Analysis of variance (ANOVA) methods)
时间序列处理(Time series processes)和状态空间模型(state space models)
广义矩估计方法(Generalized method of moments)
来自:
https://blog.csdn.net/wuzlun/article/details/80305111
这么多模型也无法拟合,所以作者认为二者无关,那么这篇kernel就完了吗,显然没。kernel还有一部分内容,请见我下一篇博客吧,比较着急的可以直接看kernel。

kaggle竞赛系列3----python数据挖掘时间序列时间量分析(以elo竞赛为例)相关推荐

  1. python数据挖掘(1.亲和性分析)

    python数据挖掘(1.亲和性分析) 数据源(python数据挖掘文件下的chapter1) 亲和性分析 亲和性分析根据样本之间的相似度,确定他们关系的亲疏. 下面我们说一个非常常见的应用场景,顾客 ...

  2. Kaggle金牌得主的Python数据挖掘框架,机器学习基本流程都讲清楚了

    作者 | 刘早起 来源 | 早起Python 导语:很多同学在学习机器学习时往往掉进了不停看书.刷视频的,但缺少实际项目训练的坑,有时想去练习却又找不到一个足够完整的教程,本项目翻译自kaggle入门 ...

  3. 来自Kaggle金牌得主的Python数据挖掘框架,一文学会机器学习基本流程!

    导读 很多同学在学习机器学习时往往掉进了不停看书.刷视频的,但缺少实际项目训练的坑,有时想去练习却又找不到一个足够完整的教程,本项目翻译自kaggle入门项目Titanic金牌获得者的Kernel,该 ...

  4. python 土拨鼠库_傻傻分不清楚系列|Python中各种时间处理方法(上)

    相信大多数数据分析师在入手Python的时候,在学习到time库与datetime库时,都会对两个库里面长得很像,又相互有关联的各种类和方法感到非常窝心.当接触到pandas处理时间序列的方法时,再次 ...

  5. 【python数据挖掘课程】二十三.时间序列金融数据预测及Pandas库详解

    这是<Python数据挖掘课程>系列文章,也是我上课内容及书籍中的一个案例.本文主要讲述时间序列算法原理,Pandas扩展包基本用法以及Python调用statsmodels库的时间序列算 ...

  6. python数据挖掘案例系列教程——python实现搜索引擎

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 今天我们使用python实现一个网站搜索引擎.主要包含两个部分.网站数据库的生成.搜索引擎.其中搜索引擎部分我们使用单词频度算法.单词 ...

  7. python数据挖掘系列教程——PySpider框架应用全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python数据挖掘系列教程--PySpider框架应用全解. PySpider介绍 pyspider上手更简单,操作更加简便,因为它增加了 ...

  8. python亲和性分析_数据挖掘入门系列教程(一)之亲和性分析

    数据挖掘入门系列教程(一)之亲和性分析 教程系列简介 该教程为入门教程,为博主学习数据挖掘的学习路径步骤.教程为入门教程,从最简单的开始.使用的编程语言为Python3.8.1,使用JupyterNo ...

  9. 时间序列分析 | Python实现时间序列统计分析与建模

    时间序列分析 | Python实现时间序列统计分析与建模 目录 时间序列分析 | Python实现时间序列统计分析与建模 基本介绍 数据准备 程序设计 学习总结 参考资料 基本介绍 本文介绍时间序列P ...

最新文章

  1. 2022-2028年中国免疫诊断行业市场前瞻与投资战略规划分析报告
  2. 小龟小车A2学习笔记
  3. Tomcat配置Web虚拟目录
  4. 不懂物理,何以谈科技?
  5. vector的逆序输出(神奇的vector)
  6. 阿里云服务器ECS挑选什么样的网站环境
  7. PTA c语言 求幂级数展开的部分和
  8. ubuntu 安装 swoole 和mac 安装swoole 扩展
  9. python工作技巧_4个基本的 Python 技巧让你的工作流程自动化
  10. 0基础学python要多久-怎么自学python,大概要多久?
  11. Spark 共享变量详解
  12. 【项目管理】《挑战埃及》沙盘介绍
  13. jmeter beanshell 之常用的代码
  14. windows对计算机硬件有要求吗,win10对硬件有什么要求_win10硬件配置有哪些要求
  15. QNX系统和凝思系统分别系统时间设置RTC时间方法
  16. Lenovo system x3650 M5 Win2016U盘安装过程
  17. 《逆袭大学——传给IT学子正能量》一审稿目录
  18. Newline —— CRLF、LF、CR回车和换行
  19. flex中dataGrid的编辑功能
  20. 海天蚝油《挑战不可能》听算神童挑战极限20笔9位数闪电心算

热门文章

  1. 论文解读+代码复现【AIDD】贝叶斯、决策树、随机森林+2种机器学习模型在癌症治疗药物发现中的应用
  2. 【问题已解决】无法定位程序输入点于XXX动态链接库***.dll上
  3. QQ浏览器极速内核关闭“您即将提交的信息不安全”提示
  4. Linux修改open files数
  5. 重游非故地——WD泰国硬盘工厂概览
  6. 网站显示该内容被禁止访问的解决办法
  7. [转] 送给优柔寡断和胡思乱想的朋友们---17条人生哲理
  8. 2021-08-01-DJ-012 Django 路由的解析方式 path,repath
  9. 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源...
  10. 2022 CCPC补题(更新中...)