数据透视表

1 apply 自定义函数

Pandas提供了很多数据处理的API,但当提供的API不能满足需求的时候,需要自己编写数据处理函数, 这个时候可以使用apply函数

1 Series的apply方法

sq = df[‘a’].apply(my_sq) 接收的函数my_sq作用在列的每一个元素上,也就是把每个元素传给my_sq函数

ex = df[‘a’].apply(my_exp,e=2),同可以通过apply接收my_exp的参数

2 DataFrame的apply方法

# 修改avg_3函数
def avg_3_apply(col):
    x = col[0]
    y = col[1]
    z = col[2]
    return (x+y+z)/3
df.apply(avg_3_apply)
这个函数作用在整个df上,但是每次接收数据时是一次性把一行或者一列传入给接收的函数,axis参数指定按照行还是列

3 apply 使用案例

接下来使用titanic数据集来介绍apply的用法

分别对数据集的行列统计缺失值以及比例

通过axis参数确定按行还是按列统计

4 向量化函数

@np.vectorize
def vec_avg_2_mod(x,y):
    if(x==20):
        return (np.NaN)
    else:
        return (x+y)/2
        
通过np.vectorize对函数进行装饰,这个函数就可以处理向量的数据

5 lambda函数

df.apply(lambda x: x+1)

2 分组操作

在SQL中我们经常使用 GROUP BY 将某个字段,按不同的取值进行分组, 在pandas中也有groupby函数

1 单变量分组聚合

df.groupby(‘year’).lifeExp.mean()

根据指定的字段/列中的取值,把取值相同的分到一个组,再对其他列进行聚合

Pandas内置的聚合方法

其他库的函数

如果使用其他库中的函数进行聚合,则需要使用agg和 aggregate接收聚合函数

自定义函数

如果想在聚合的时候,使用非Pandas或其他库提供的计算, 可以自定义函数,然后再aggregate中调用它

def my_mean(values):
    '''计算平均值
    '''
    n = len(values) # 获取数据条目数
    sum = 0
    for value in values:
        sum += value
    return(sum/n)
# 调用自定义函数
df.groupby('year').lifeExp.agg(my_mean)

自定义函数可以有多个参数, 第一个参数接受来自DataFrame分组这之后的值, 其余参数可自定义

# 计算全球平均预期寿命的平均值 与分组之后的平均值做差
def my_mean_diff(values,diff_value):
    '''计算平均值和diff_value之差
    '''
    n = len(values)
    sum = 0
    for value in values:
        sum+=value
    mean = sum/n
    return(mean-diff_value)
# 计算整个数据集的平均年龄
global_mean = df.lifeExp.mean()
# 调用自定义函数 计算平均值的差值
df.groupby('year').lifeExp.agg(my_mean_diff,diff_value = global_mean)

同时传入多个函数

使用多个函数进行聚合

# 按年计算lifeExp 的非零个数,平均值和标准差
df.groupby('year').lifeExp.agg([np.count_nonzero,np.mean,np.std])

对不同列同时用不同方法进行聚合

df.groupby('year').agg({'lifeExp':['mean','median','max'],'pop':['median', 'min', 'std'],'gdpPercap':'median'})

聚合之后修改列名和索引

df.groupby('year').agg({'lifeExp':'mean','pop':'median','gdpPercap':'median'}).\
    rename(columns={'lifeExp':'平均寿命','pop':'人口','gdpPercap':'人均Gdp'}).reset_index()

2 转换

transform 转换,需要把DataFrame中的值传递给一个函数, 而后由该函数"转换"数据。

使用transform分组计算z分数

# 计算z-score   x - 平均值/标准差
def my_zscore(x):
    return (x-x.mean())/x.std()
#按年分组 计算z-score
df.groupby('year').lifeExp.transform(my_zscore)

对df进行按照year进行分组,取出lifeExp,分别对每个分组进行计算,得到的是每个分组的zscore

transform分组填充缺失值

def fill_na_mean(x):
    # 求平均
    avg = x.mean()
    # 填充缺失值
    return(x.fillna(avg))
total_bill_group_mean = tips_10.groupby('sex').total_bill.transform(fill_na_mean)
total_bill_group_mean

transform练习

pcnt_loss = weight_loss.groupby(['Name', 'Month'])['Weight'].transform(find_perc_loss)

3 过滤

使用groupby方法还可以过滤数据,调用filter 方法,传入一个返回布尔值的函数,返回False的数据会被过滤掉

tips_filtered = tips.groupby('size').filter(lambda x: x['size'].count()>30)

###4 DataFrameGroupBy对象

# 调用groupby 创建分组对象
grouped = tips_10.groupby('sex')

如果想查看计算过的分组,可以借助groups属性实现

可以直接对分组结果进行aggregate,transform计算了

通过get_group选择分组,female = grouped.get_group(‘Female’)

遍历分组

for sex_group in grouped:
    print(sex_group)

多分组

group_avg = tips_10.groupby([‘sex’,‘time’]).mean()

也可以在分组的时候通过as_index = False参数(默认是True),效果与调用reset_index()一样

3 数据透视表

1 Pandas 透视表概述

在使用Excel做数据分析时,透视表是很常用的功能,Pandas也提供了透视表功能,对应的API为pivot_table

pivot_table参数中最重要的四个参数 values,index,columns,aggfunc,下面通过案例介绍pivot_tabe的使用

2 零售会员数据分析案例

业务背景介绍,需要考虑清楚

数据分析要达成的目标

案例中用到的数据

分析会员运营的基本情况

3 会员存量、增量分析

解析注册时间得到注册年月

custom_info.loc[:,'注册年月'] = custom_info['注册时间'].apply(lambda x : x.strftime('%Y-%m'))

分组统计

month_count = custom_info.groupby('注册年月')[['会员卡号']].count()
dataframe.pivot_table()
custom_info.pivot_table(index = '注册年月',values = '会员卡号',aggfunc = 'count')

计算存量 cumsum 对某一列 做累积求和 1 1+2 1+2+3 1+2+3+4 …

可视化,需要去除第一个月数据,第一个月数据是之前所有会员数量的累积

因为增量和存量值的数量级差异大,
month_count['月增量'].plot(figsize = (20,8),color='red',secondary_y = True)
month_count['存量'].plot.bar(figsize = (20,8),color='gray',xlabel = '年月',legend = True,ylabel = '存量')

4 增量等级分布

会员增量存量不能真实反映会员运营的质量,需要对会员的增量存量数据做进一步拆解

month_degree_count =custom_info.groupby(['注册年月','会员等级'])[['会员卡号']].count()
member_rating = custom_info.pivot_table(index = '注册年月',columns='会员等级',values='会员卡号',aggfunc = 'count') 把长数据转成宽数据

pandas绘制图表

fig, ax1 = plt.subplots(figsize=(20,8),dpi=100)#构建坐标系
ax2 = ax1.twinx()#构建双胞胎坐标系
member_rating[['白银会员','黄金会员']].plot.bar(ax = ax1,rot=0,grid = True,xlabel='年月',ylabel = '白银黄金',legend=True)
member_rating[['铂金会员','钻石会员']].plot(ax = ax2,color = ['red','gray'],ylabel='铂金钻石')
ax2.legend(loc='upper left')
plt.title("会员增量等级分布",fontsize=20)

5 增量等级占比分析

#按行求和
member_rating.loc[:,'总计'] = member_rating.sum(axis = 'columns')
#计算白银和黄金会员等级占比 铂金钻石会员数量太少暂不计算
member_rating.loc[:,'白银会员占比'] = member_rating['白银会员'].div(member_rating['总计'])
member_rating.loc[:,'黄金会员占比'] = member_rating['黄金会员'].div(member_rating['总计'])
member_rating

画图 折线图
member_rating[['白银会员占比','黄金会员占比']].plot(color=['r','g'],ylabel='占比',figsize=(16,8),grid=True)
plt.title("会员等级占比分析",fontsize=20)

color 可以通过'red' 'green' 也可以是颜色符号

6 整体等级分布

思路:按照会员等级分组,计算每组的会员数量,用每组会员数量/全部会员数量

ratio = custom_info.pivot_table(index = '会员等级',values = '会员卡号',aggfunc = 'count')

画图

# autopct 显示数据标签,并指定保留小数位数
ratio.loc[['白银会员','钻石会员','黄金会员','铂金会员'],'占比'].plot.pie(figsize=(16,8),autopct='%.1f%%',fontsize=16)

7 线上线下增量分析

#按会员来源进行分组 使用groupby实现
from_data = custom_info.groupby(['注册年月','会员来源'])[['会员卡号']].count()
from_data = from_data.unstack()
from_data.columns = ['电商入口', '线下扫码']
from_data = from_data[1:]
from_data


# 透视表实现
custom_info.pivot_table(index = ['注册年月'],columns='会员来源',values ='会员卡号',aggfunc = 'count')

8 地区店均会员数量

计算每个地区,平均会员数量

使用查看门店信息表,把这个表和用户信息表合并

custom_info1 = pd.merge(custom_info,store_info[['店铺代码','地区编码']],left_on='所属店铺编码',right_on='店铺代码')

#统计不同地区的会员数量 注意只统计线下,不统计电商渠道 GBL6D01为电商
district = custom_info1[custom_info1['地区编码']!='GBL6D01'].groupby('地区编码')[['会员卡号']].count()

district['店铺数'] = custom_info1[['地区编码','所属店铺编码']].drop_duplicates().groupby('地区编码')['所属店铺编码'].count()

district.loc[:,'每店平均会员数']=round(district['会员数量'].div(district['店铺数']))
#计算总体平均数
district.loc[:,'总平均会员数']=district['会员数量'].sum()/district['店铺数'].sum()
#排序

district['每店平均会员数'].plot.bar(figsize=(20,8),color='r',legend = True,grid=True)
district['总平均会员数'].plot(figsize=(20,8),color='g',legend = True,grid=True)

9 各地区会销比

会销比 = 会员消费的金额 / 全部客户消费的金额

会销比 = 会员消费的订单数 / 全部销售订单数

通过会销比可以衡量会员的整体质量

为会员消费报表添加年月列

custom_consume.loc[:,'年月']=pd.to_datetime(custom_consume['订单日期']).apply(lambda x:datetime.strftime(x,'%Y%m')).astype(np.int)

为会员消费报表添加地区编码,目的是可以按照地区分组统计消费情况

# margins参数 每行每列求和
member_orders=custom_consume[custom_consume['地区编码']!='GBL6D01'].pivot_table(values = '消费数量',index='地区编码',columns='年月',aggfunc=sum,margins=True)

country_sales=all_orders.pivot_table(values = '全部订单数',index='地区代码',columns='年月',aggfunc=sum,margins=True)

计算各地区会销比

result=member_orders/country_sales
result.applymap(lambda x: format(x,".2%"))

applymap 和apply类似,

10 会员连带率分析

连带率是指销售的件数和交易的次数相除后的数值,反映的是顾客平均单次消费的产品件数

连带率的计算

  • 连带率 = 消费数量 / 订单数量

统计订单的数量:需要对"订单号"去重,并且只要"下单"的数据,"退单"的不要

order_data=custom_consume.query(" 订单类型=='下单' & 地区编码!='GBL6D01'")
#去重  统计订单量需要去重  后面统计消费数量和消费金额不需要去重
order_count=order_data[['年月','地区编码','订单号']].drop_duplicates()
order_count=order_count.pivot_table(index = '地区编码',columns='年月',values='订单号',aggfunc='count')

统计商品数量

consume_count=order_data.pivot_table(values = '消费数量',index='地区编码',columns='年月',aggfunc=sum)

result=consume_count/order_count
#小数二位显示
result=result.applymap(lambda x:format(x,'.2f'))
result

11 会员复购率分析

复购率的概念和复购率分析的作用

复购率:指会员对该品牌产品或者服务的重复购买次数,重复购买率越多,则反应出会员对品牌的忠诚度就越高,反之则越低。

由于一个会员同一天消费多次也算一次消费,所以会员消费次数按一天一次计算 因此需要对"会员卡号"和"时间"进行去重

order_data=custom_consume.query("订单类型=='下单'")
#因为需要用到地区编号和年月  所以选择 订单日期  卡号   年月   地区编码  四个字段一起去重
order_data=order_data[['订单日期','卡号','年月','地区编码']].drop_duplicates()
consume_count = order_data.pivot_table(index =['地区编码','卡号'],values='订单日期',aggfunc='count').reset_index()
consume_count.rename(columns={'订单日期':'消费次数'},inplace=True)
consume_count

判断是否复购

统计每个地区的购买人数和复购人数

depart_data=consume_count.pivot_table(index = ['地区编码'],values=['消费次数','是否复购'],aggfunc={'消费次数':'count','是否复购':'sum'})

depart_data.loc[:,'复购率']=depart_data['复购人数']/depart_data['购买人数']


统计2018年01月~2018年12月复购率和2018年02月~2019年01月复购率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值