1. pandas
1.1 导入相关库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
1.2 读取数据
df = pd.read_csv('E:\学习\DataAnalyst-gbk1.csv',encoding='gbk')
1.3 添加一列数据
df['avg'] = (df.top+df.bottom)/2
1.4 绘制折线图
df.avg.plot(figsize=(100,6))
曲线是根据companyId绘制的,但由于公司较多,曲线看不出什么信息。所以我们根据平均工资的不同绘制不同平均工资的公司有多少。
df.avg.value_counts().sort_index().plot()
df.avg.value_counts() 得到的是不同平均工资的公司的数量,索引是平均工资,这样直接绘制得到的图没有规律,所以我们要先将平均工资进行排序,然后再绘制。 可以看到大部分的工资都集中在9-30k之间。
1.5 柱形图
df.avg.value_counts().sort_index().plot(kind='bar')
绘制结果比较密集 可使用透视表进行绘制,透视表就可从不同维度进行划分:
df.pivot_table(index='city',columns='education',values='avg',aggfunc='count').plot(kind='bar',stacked=True)
绘制不同城市里对学历的招聘要求的公司数量。可以看到背景的公司最多,其次是上海;招聘要求本科占绝大部分比率。
df.pivot_table(index='city',columns='education',values='avg',aggfunc='count').plot(kind='barh',stacked=True)
kind = ‘barh’,图像方向改变。
1.6 直方图
针对1.5的柱形图数量太多的问题,可使用直方图划分区间来绘制。
df.avg.value_counts().sort_index().plot.hist(bins=20)
df.groupby('education').apply(lambda x:x.avg).unstack().T
df.groupby('education').apply(lambda x:x.avg).unstack().T.plot.hist(alpha=0.5,stacked=True,bins=20)
alpha是透明度。
1.7 箱线图
df.groupby('education').apply(lambda x:x.avg).unstack().T.plot.box()
df.boxplot(column='avg',by='education')
1.8 密度图
df.groupby('education').apply(lambda x:x.avg).unstack().T.plot.kde()
df.avg.plot.kde()
1.9 面积图
df.groupby('education').apply(lambda x:x.avg).unstack().T.plot.area()
df.pivot_table(index='avg',columns='education',aggfunc='count',values='companyId').plot.area()
1.10 散点图
df.groupby('companyId').aggregate(['mean','count','max']).avg.plot.scatter(x='mean',y='count')
matrix = df.groupby('companyId').aggregate(['mean','count','max']).avg
pd.plotting.scatter_matrix(matrix)
1.11 饼图
df.city.value_counts().plot.pie(figsize=(6,6))
plt.pie(df.city.value_counts(),labels=df.city.value_counts().index)
2. matplotlib
2.1 导入相关库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
2.2 读取txt数据
columns = ['user_id','order_dt','order_products','order_amount']
df = pd.read_table('E:\学习\七周成为数据分析师_课件\第七周\CDNOW_master.txt',names = columns,sep='\s+')
sep='\s+' 匹配任意的空格符,任意一个或者多个
2.3 数据处理
df.describe()
大部分订单只消费了少量商品,中位数是2,(平均2.4),有一定极值干扰。 用户消费金额比较稳定,平均消费35元,中位数在25 元,有一定极值干扰,使得均值增大。
将日期转换为datetime格式:
df['order_dt']=pd.to_datetime(df.order_dt,format='%Y%m%d')
会分析月销售量,增加一列month。
df['month']=df.order_dt.values.astype('datetime64[M]')
2.4 进行用户消费趋势的分析(按月)
每月的消费总金额 每月的消费次数 每月的产品购买量 每月的消费人数
group_month = df.groupby('month')
order_month_amount = group_month.order_amount.sum()
order_month_amount.head()
%matplotlib inline
plt.style.use('ggplot')
order_month_amount.plot()
对月进行分组,由上图可知,消费金额在前三个月达到最高峰,后续消费额较为稳定,有轻微下降趋势
- 每月的消费次数
对月进行分组,然后统计用户数,计算得到每月的用户数量。
group_month.user_id.count().plot()
前三个月消费订单数在10000笔左右,后续月份的平均消费人数则在2500人
group_month.order_products.sum().plot()
df.groupby(['month']).user_id.apply(lambda x:len(x.drop_duplicates())).plot()
df.groupby(['month','user_id']).count().reset_index().groupby(['month']).count().plot()
每月消费人数低于每月消费次数,但差异不大 前三个月每月的消费人数在8000-10000之间,后续月份,平均消费人数在2000人不到
2.5 用户个体消费分析
用户消费金额、消费次数的描述统计 用户消费金额和消费的散点图 用户消费金额的分布图 用户消费次数的分布图 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
grouped_user = df.groupby('user_id')
grouped_user.sum().describe()
用户平均购买了7张CD,但是中位值只有3,说明小部分用户购买了大量的CD 用户平均消费106元,中位值有43,判断同上,有极值干扰
grouped_user.sum().plot.scatter(x='order_amount',y='order_products')
grouped_user.sum().query('order_amount<6000').plot.scatter(x='order_amount',y='order_products')
grouped_user.sum().query('order_amount<1000').order_amount.plot.hist(bins=400)
从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断。可以使用过滤操作排除异常
grouped_user.sum().query('order_products<100').order_products.plot.hist(bins=50)
使用切比雪夫定理过滤掉异常值,计算95%的数据的分布情况。
- 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
user_cumsum = grouped_user.sum().sort_values('order_amount',ascending=True).apply(lambda x:x.cumsum()/x.sum())
user_cumsum
user_cumsum.reset_index().order_amount.plot()
按用户消费金额进行升序排列,由图可知50%的用户仅贡献了15%的消费额度。而排名前5000的用户就贡献了60%的消费额。
2.6 用户消费行为
- 用户第一次消费(首购)
grouped_user.order_dt.min().value_counts().plot()
用户第一次购买分布,集中在前三个月 其中,在2月11日至2月25日有一次剧烈的波动
- 用户最后一次消费
grouped_user.max().order_dt.value_counts().plot()
用户最后一次购买的分布比第一次分布广 大部分最后一次购买,集中在前三个月,说明有很多用户购买了一次后就不再进行购买 随着时间的递增,最后一次购买数也在递增,消费呈现流失上升的状况
2.7 新老客消费比
多少用户仅消费了一次?
user_life=grouped_user.order_dt.agg(['max','min'])
(user_life['max']==user_life['min']).value_counts()
有12054个人只消费了一次
每月新客占比?
grouped_month_user = df.groupby(by=['month','user_id']).count().order_dt
计算每月用户的购买次数。
new_ = (grouped_month_user>1).reset_index().groupby('order_dt').count()
计算购买次数小于1 次的人数,也就是老客
sum_ = grouped_month_user.reset_index().month.count()
计算每月的购买人数
new_rate = new_.month[0:1]/sum_
求其比值,也就是新客比例: 0.829881
2.8 用户分层
RFM
rfm = df.pivot_table(index='user_id',
values = ['order_dt','order_products','order_amount'],
aggfunc={'order_dt':'max',
'order_products':'sum',
'order_amount':'sum'})
rfm['R'] = -(rfm.order_dt-rfm.order_dt.max())/np.timedelta64(1,'D')
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
def rfm_func(x):
level = x.apply(lambda x:'1' if x>= 0 else '0')
label = level.R + level.F + level.M
d = {
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要挽留客户',
'001':'重要发展客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般挽留客户',
'000':'一般发展客户'
}
result = d[label]
return result
rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.loc[rfm.label == '重要价值客户','color']='g'
rfm.loc[~(rfm.label == '重要价值客户'),'color']='r'
rfm.plot.scatter('F','R',c=rfm.color)
rfm.groupby('label').sum()
从RFM分层可知,大部分用户为重要保持客户,但是这是由于极值的影响,所以RFM的划分标准应该以业务为准。 尽量用小部分的用户覆盖大部分的额度 不要为了数据好看划分等级
新、老、活跃、回流、流失
pivot_counts = df.pivot_table(index='user_id',
columns='month',
values='order_dt',
aggfunc='count').fillna(0)
pivot_counts
df_purchase = pivot_counts.applymap(lambda x:1 if x>0 else 0)
def active_status(data):
status = []
for i in range(18):
if data[i] == 0:
if len(status)>0:
if status[i-1] == 'unreg':
status.append('unreg')
else:
status.append('unactive')
else:
status.append('unreg')
else:
if len(status)==0:
status.append('new')
else:
if status[i-1] == 'unactive':
status.append('return')
elif status[i-1] == 'unreg':
status.append('new')
else:
status.append('active')
return status
purchase_status = df_purchase.apply(active_status,axis=1)
purchase_status_ct = purchase_status.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_status_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
2.9 用户购买周期(按订单)
用户消费周期描述 用户消费周期分布
order_diff = grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
x.order_dt 购买日期,x.order_dt.shift() 购买日期向下移动一位。按用户减就是计算用户两次购买的日期差。 共有46089人购买超过两次,
(order_diff/np.timedelta64(1,'D')).hist(bins=20)
订单周期呈指数分布
用户的平均购买周期是68天
绝大部分用户的购买周期都低于100天
(user_life['max']-user_life['min']).describe()
((user_life['max']-user_life['min'])/np.timedelta64(1,'D')).hist(bins=20)
用户的生命周期受只购买一次的用户影响比较厉害(可以排除)
用户均消费134天,中位数仅0天
u_1 = ((user_life['max']-user_life['min']).reset_index()[0]/ np.timedelta64(1,'D'))
u_1[u_1>0].hist(bins=40)
2.10 复购率和回购率分析
复购率 自然月内,购买多次的用户占比
purchase_r = pivot_counts.applymap(lambda x:1 if x>1 else np.NaN if x==0 else 0)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(10,4))
复购率稳定在20%左右,前三个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率降低
回购率 曾经购买一次的顾客在某一时期内再次购买的占比
def purchase_back (data) :
status =[]
for i in range(17):
if data[i] == 1:
if data[i+1] == 1:
status.append(1)
if data[i+1]== 0:
status.append(0)
else:
status.append(np.NaN)
status.append(np.NaN)
return status
purchase_b = df_purchase.apply(purchase_back,axis=1)
purchase_r
3. seaborn
导入库
import seaborn as sns
- 分布
distplot概率分布图
sns.distplot(df.order_amount,kde=False,hist=True)
kde=True
kdeplot概率密度图
sns.kdeplot(df.order_amount)
jointplot联合密度图
grouped_user = df.groupby('user_id').sum()
grouped_user.head()
sns.jointplot(grouped_user.order_products,grouped_user.order_amount,kind='reg')
RFM 模型
df['oeder_dt'] = pd.to_datetime(df.order_dt,format="%Y%m%d")
rfm = df.pivot_table(index = 'user_id',
values = ['order_dt','order_products','order_amount'],
aggfunc={'order_dt':'max',
'order_products':'sum',
'order_amount':'sum'})
rfm
rfm['R'] = -(rfm.order_dt-rfm.order_dt.max())
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
rfm.head()
sns.jointplot(rfm.M,rfm.F,kind='reg')
pairplot多变量图
sns.pairplot(rfm[['R','F','M']])
2. 分类 boxplots箱线图
plt.figure(figsize=(10,5))
sns.boxplot(x='类型',y='口味',data=df)
df2 = df.query("(城市=='上海')|(城市=='北京')")
plt.figure(figsize=(20,5))
sns.boxplot(x='类型',y='口味',hue='城市',data=df2)
violinplots提琴图
plt.figure(figsize=(20,5))
sns.violinplot(x='类型',y='口味',hue='城市',data=df2)
plt.figure(figsize=(20,5))
sns.violinplot(x='类型',y='口味',hue='城市',data=df2,palette='muted',split=True)
barplot柱形图 factorplot因子图
sns.factorplot(x='类型',y='口味',hue = '城市',data = df2,size=10)
sns.factorplot(x='类型',y='口味',hue = '城市',kind='box',data = df2,size=10)
sns.factorplot(x='类型',y='口味',col = '城市',kind='box',data = df2,size=6,aspect=4)
3. 线性 lmplot 回归图
sns.lmplot(x='口味',y='环境',data=df2)
sns.lmplot(x='口味',y='点评',data=df2.query('点评<2000'),hue='城市')
sns.lmplot(x='口味',y='环境',data=df2.query('点评<2000'),col='城市')
heatmap
pt = df.pivot_table(index='城市',columns='类型',
values='口味',aggfunc='mean')
plt.figure(figsize=(10,10))
sns.heatmap(pt,annot=True)
|