完整数据分析流程:Python中的Pandas如何解决业务问题

news2024/11/15 5:07:40

开篇

作为万金油式的胶水语言,Python几乎无所不能,在数据科学领域的作用更是不可取代。数据分析硬实力中,Python是一个非常值得投入学习的工具。

这其中,数据分析师用得最多的模块非Pandas莫属,如果你已经在接触它了,不妨一起来通过完整的数据分析流程,探索Pandas是如何解决业务问题的。

数据背景

为了能尽量多地使用不同的Pandas函数,我设计了一个古古怪怪但是实际中又很真实的数据,说白了就是比较多不规范的地方,等着我们去清洗。

数据源是改编自一家超市的订单,文末附文件路径。

导入所需模块

import pandas as pd
复制代码

数据导入

Pandas提供了丰富的数据IO接口,其中最常用的是pd.read_excelpd.read_csv函数。

data = pd.read_excel('文件路径.xlsx',
                    sheet_name='分页名称')
data = pd.read_csv('文件路径.csv')
复制代码

从超市数据集中把多页数据分别导入:

orders = pd.read_excel('超市数据集.xlsx', 
                       sheet_name= '订单表')
customers = pd.read_excel('超市数据集.xlsx', 
                       sheet_name= '客户表')
products = pd.read_excel('超市数据集.xlsx', 
                       sheet_name= '产品表')
复制代码

该环节除了导入数据外,还需要对数据有初步的认识,明确有哪些字段,及其定义

这里我们通过 pd.Series.head() 来查看每个数据表格的字段及示例数据

明确业务问题及分析思路

在业务分析实战中,在开始分析之前,需要先明确分析目标,倒推分析方法、分析指标,再倒推出所需数据。

这就是「以终为始」的落地思维。

假设业务需求是通过用户分层运营、形成差异化用户运营策略。数据分析师评估后认为可基于RFM用户价值模型对顾客进行分群,并通过不同族群画像特征制定运营策略,比如重要价值用户属于金字塔顶端人群,需要提供高成本、价值感的会员服务;而一般价值用户属于价格敏感型的忠诚顾客,需要通过折扣刺激消费等。

因此,这里的分析方法则是对存量用户进行RFM模型分群,并通过统计各族群数据特征,为业务提供策略建议。

明确业务需求及分析方法后,我们才能确定去统计顾客的R、F、M、以及用于画像分析的客单价等指标,此时才能进入下一步。

特征工程与数据清洗

数据科学中有句话叫 "Garbage In, Garbage Out",意思是说如果用于分析的数据质量差、存在许多错误,那么即使分析的模型方法再缜密复杂,都不能变出花来,结果仍是不可用的。

所以也就有了数据科家中80%的工作都是在做数据预处理工作的说法。

特征工程主要应用在机器学习算法模型过程,是为使模型效果最佳而进行的系统工程,包括数据预处理(Data PrePorcessing)、特征提取(Feature Extraction)、特征选择(Feature Selection)以及特征构造(Feature Construction)等问题。

直白地说,可以分成两部分:

  • 数据预处理,可以理解成我们常说的数据清洗
  • 特征构造,比如此次构建RFM模型及分组用户画像中,R、F、M、客单价等标签就是其对应的特征。

(当然,RFM非机器学习模型,这里是为了便于理解进行的解释。)

数据清洗

什么是数据清洗? 数据清洗是指找出数据中的「异常值」并「处理」它们,使数据应用层面的结论更贴近真实业务。

异常值:

  • 不规范的数据,如空值、重复数据、无用字段等,需要注意是否存在不合理的值,比如订单数据中存在内部测试订单、有超过200岁年龄的顾客等
  • 特别注意数据格式是否合理,否则会影响表格合并报错、聚合统计报错等问题
  • 不符合业务分析场景的数据,比如要分析2019-2021年的用户行为,则在此时间段之外的行为都不应该被纳入分析

如何处理:

  • 一般情况下,对于异常值,直接剔除即可
  • 但对于数据相对不多,或该特征比较重要的情况下,异常值可以通过用平均值替代等更丰富的方式处理

在了解数据清洗的含义后,我们便可以开始用Pandas来实操该部分内容。

数据类型

先用pd.dtypes来检查数据字段是否合理

发现订单日期、数量是Object(一般即是字符)类型,后面无法用它们进行运算,需要通过pd.Series.astype()pd.Series.apply()方法来修改字符类型

orders['订单日期'] = orders['订单日期'].astype('datetime64')
orders['数量'] = orders['数量'].apply(int)
复制代码

另外,对时间类型的处理也可以通过pd.to_datetime进行:

orders['订单日期'] = pd.to_datetime(orders['订单日期'])
复制代码

修改字段名

经验丰富的数据分析师发现字段名字也有问题,订单 Id存在空格不便于后面的引用,需要通过pd.rename()来修改字段名

orders = orders.rename(columns={'订单 Id':'订单ID',
                                '客户 Id':'客户ID',
                                '产品 Id':'产品ID'})
customers = customers.rename(columns={'客户 Id':'客户ID'})
复制代码

多表连接

把字段名以及数据类型处理好后,就可以用pd.merge将多个表格进行连接。

表连接中的on有两种方式,一种是两个表用于连接的字段名是相同的,直接用on即可,如果是不相同,则要用left_on, right_on进行。

data = orders.merge(customers, on='客户ID', how='left')
data = data.merge(products, how='left', 
                  left_on='产品ID', right_on='物料号')
复制代码

剔除多余字段

对于第二种情况,得到的表就会存在两列相同含义但名字不同的字段,需要用pd.drop剔除多余字段。此外,“行 Id”在这里属于无用字段,一并剔除掉。

data.drop(['物料号','行 Id'],axis=1,
                            inplace=True)
复制代码

调整后得到的表结构:

文本处理——剔除不符合业务场景数据

根据业务经验,订单表中可能会存在一些内部测试用的数据,它们会对分析结论产生影响,需要把它们找出来剔除。与业务或运维沟通后,明确测试订单的标识是在“产品名称”列中带“测试”的字样。

因为是文本内容,需要通过pd.Series.str.contains把它们找到并剔除

data = data[~data['产品名称'].str.contains('测试')]
复制代码

时间处理——剔除非分析范围数据

影响消费者的因素具有时间窗口递减的特性,例如你10年前买了顶可可爱爱的帽子,不代表你今天还需要可可爱爱风格的产品,因为10年时间足以让你发生许多改变;但是如果你10天以前才买了田园风的裙子,那么就可以相信你现在还会喜欢田园风产品,因为你偏好的风格在短期内不会有太大改变。

也就是说,在用户行为分析中,行为数据具有一定时效,因此需要结合业务场景明确时间范围后,再用pd.Series.between()来筛选近符合时间范围的订单数据进行RFM建模分析。

data= data[data['订单日期'].between('2019-01-01','2021-08-13')]
复制代码

特征构造

此环节目的在于构造分析模型,也就是RFM模型及分群画像分析所需的特征字段。

数据聚合——顾客消费特征

首先,是RFM模型中顾客的消费特征:

  • R:客户最近一次购买离分析日期 (设为2021-08-14)的距离,用以判断购买用户活跃状态
  • F:客户消费频次
  • M:客户消费金额

这些都是一段时间内消费数据的聚合,所以可以用pd.groupby().agg()实现

consume_df = data.groupby('客户ID').agg(累计消费金额=('销售额',sum), 
                         累计消费件数=('数量',sum),
                         累计消费次数=('订单日期', pd.Series.nunique), 
                         最近消费日期=('订单日期',max)
                        )
复制代码

其中,R值比较特殊,需要借用datetime模块,计算日期之间的距离

from datetime import datetime
consume_df['休眠天数'] = datetime(2021,8,14) - consume_df['最近消费日期']
consume_df['休眠天数'] = consume_df['休眠天数'].map(lambda x:x.days)
复制代码

计算所得顾客累计消费数据统计表:

分箱处理——客单价区间划分

根据前面分析思路所述,完成RFM模型用户分群后,还要统计各族群用户消费画像,这里因篇幅限制仅统计各族群客单价分布特征。

此时,计算完客单价数据后,需要用pd.cut对客单价进行分箱操作,形成价格区间。

consume_df['客单价'] = consume_df['累计消费金额']/consume_df['累计消费次数']
consume_df['客单价区间']  = pd.cut(consume_df['客单价'],bins=5)
复制代码

通过pd.Series.value_counts方法统计客单价区间分布情况:

pd.cut中的bins参数为将客单价划分的区间数,填入5,则平均分为5档。当然,还是那句话,这个在实操中需要与业务明确,或结合业务场景确定。

RFM建模

完成数据清洗及特征构造后,就进入到建模分析环节。

Tukey's Test 离群值检测

根据分析经验,离群值会极大地对统计指标造成影响,产生较大误差,例如把马云放到你们班里,计算得出班级平均资产上百亿。在这里,马云就是离群值,要把它剔除出去。

所以,在开始对RFM阈值进行计算之前,有必要先对R、F、M的值进行离群值检测。

这里我们用Turkey's Test 方法,简单来说就是通过分位数之间的运算形成数值区间,将在此区间之外的数据标记为离群值。不清楚的同学可以知乎搜一下,这里不展开讲。

Turkey's Test方法依赖分位数的计算,在Pandas,通过pd.Series.quantile计算分位数

def turkeys_test(fea):
    Q3 = consume_df[fea].quantile(0.75)
    Q1 = consume_df[fea].quantile(0.25)
    max_ = Q3+1.5*(Q3-Q1)
    min_ = Q1-1.5*(Q3-Q1)
    
    if min_<0:
        min_ =0
    
    return max_, min_
复制代码

以上代码实现了Tukey's Test函数,其中Q3就是75分位、Q1就是25分位。而min_ 和 max_则形成合理值区间,在此区间之外的数据,不论太高还是太低还是离群值。

注意,在这里因为存在min_是负数的情况,而消费数据不可能是负数,所以补充了一个把转为0的操作。

接下来,给RFM特征数据表新增字段"是否异常",默认值为0,然后再用Tukey's Test函数把异常数据标记为1,最后只需保留值为0的数据即可。

consume_df['是否异常'] = 0

for fea in rfm_features:
    max_, min_= turkeys_test(fea)
    outlet = consume_df[fea].between(min_,max_)  #bool
    consume_df.loc[~outlet,'是否异常']=1
    
consume_df = consume_df[consume_df['是否异常']==0]
复制代码

聚类与二八原则——RFM阈值计算

现在已经可以确保建模所用的特征是有效的,此时就需要计算各指标阈值,用于RFM建模。阈值的计算一般通过聚类算法进行,但这里不涉及机器学习算法。从本质上讲,聚类结果通常是符合二八原则的,也就是说重要客群应该只占20%,所以我们可以计算80分位数来近似作为RFM模型阈值。

M_threshold = consume_df['累计消费金额'].quantile(0.8)
F_threshold=consume_df['累计消费次数'].quantile(0.8)
R_threshold = consume_df['休眠天数'].quantile(0.2)
复制代码

RFM模型计算

得到RFM阈值后,即可将顾客的RFM特征进行计算,超过阈值的则为1,低于阈值的则为0,其中R值计算逻辑相反,因为R值是休眠天数,数值越大反而代表越不活跃。

consume_df['R'] = consume_df['休眠天数'].map(lambda x:1 if x<R_threshold else 0)
consume_df['F'] = consume_df['累计消费次数'].map(lambda x:1 if x>F_threshold else 0)
consume_df['M'] = consume_df['累计消费金额'].map(lambda x:1 if x>M_threshold else 0)
复制代码

对顾客RFM特征划分1和0,即高与低后,即可进行分群计算:

consume_df['RFM'] = consume_df['R'].apply(str)+'-' + consume_df['F'].apply(str)+'-'+ consume_df['M'].apply(str)

rfm_dict = {
    '1-1-1':'重要价值用户',
    '1-0-1':'重要发展用户',
    '0-1-1':'重要保持用户',
    '0-0-1':'重要挽留用户',
    '1-1-0':'一般价值用户',
    '1-0-0':'一般发展用户',
    '0-1-0':'一般保持用户',
    '0-0-0':'一般挽留用户'
}
consume_df['RFM人群'] = consume_df['RFM'].map(lambda x:rfm_dict[x])
复制代码

至此,已完成RFM建模及用户分群计算。

分群画像

完成模型分群后,就要对各族群分别统计人数及客单价分布。

人数占比

最简单的一个画像分析,则是用pd.Series.value_counts对各族群进行人数统计,分析相对占比大小。

rfm_analysis = pd.DataFrame(consume_df['RFM人群'].value_counts()).rename(columns={'RFM人群':'人数'})
rfm_analysis['人群占比'] = (rfm_analysis['人数']/rfm_analysis['人数'].sum()).map(lambda x:'%.2f%%'%(x*100))
复制代码

透视表

各族群客单价分布涉及多维度分析,可以通过Pandas透视功能pd.pivot_table实现

代码中,聚合函数aggfunc我用了pd.Series.nunique方法,是对值进行去重计数的意思,在这里就是对客户ID进行去重计数,统计各价位段的顾客数。

pd.pivot_table(consume_df.reset_index(),    # DataFrame
        values='客户ID',    # 值
        index='RFM人群',    # 分类汇总依据
        columns='客单价区间',    # 列
        aggfunc=pd.Series.nunique,    # 聚合函数
        fill_value=0,    # 对缺失值的填充
        margins=True,    # 是否启用总计行/列
        dropna=False,    # 删除缺失
        margins_name='All'   # 总计行/列的名称
       ).sort_values(by='All',ascending=False)
复制代码

这样就得到了每个族群在不同价位段上的分布,配合其他维度的画像分析可以进一步形成营销策略。

逆透视表

最后,做个骚操作,就是透视后的表属于多维度表格,但我们要导入到PowerBI等工具进行可视化分析时,需要用pd.melt将它们逆透视成一维表。

pivot_table.melt(id_vars='RFM人群',
                 value_vars=['(124.359, 3871.2]', '(3871.2, 7599.4]',
                             '(7599.4, 11327.6]', '(11327.6, 15055.8]',
                             '(15055.8, 18784.0]']).sort_values(by=['RFM人群','variable'],ascending=False)
复制代码

这样字段名为"人群"、"指标"、"值"的表格,可以一行就把信息呈现的表格就是一维表。而前面各族群人数统计中,需要一行一列来定位信息的就是二维表。

结尾

至此,我们已经通过Pandas建立了RFM模型及分组人群画像分析,完成了业务分析需求。

受限于篇幅,本文仅对数据分析过程中Pandas高频使用的函数方法进行了演示,同样重要的还有整个分析过程。如果其中对某些函数不熟悉,鼓励同学多利用知乎或搜索引擎补充学习。同时也欢迎加饼干哥哥微信讨论。

更多Pandas函数使用说明,可查询中文文档

本文算是数据分析流程的基础篇,计划会再整理一份进阶篇,涉及机器学习流程、以及更多特征工程内容,同样会以业务落地实战的方式进行介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187755.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c#入门-异步方法

异步方法 如果一个操作会返回Task&#xff0c;那么用这个操作续接后续操作&#xff0c;也会得到Task。 也就是说Task具有传染性&#xff0c;最终拼凑出来的Task非常复杂。 使用异步方法&#xff0c;可以简化Task的拼凑。 async修饰 异步方法需要添加async修饰符。并且通常方…

【前端】Vue项目:旅游App-(15)home:网络请求house数据、动态并组件化展示house列表信息

文章目录目标过程与代码content组件请求数据&#xff1a;houseListrequeststore控制台输出动态加载更多列表数据house-item组件阶段1&#xff1a;数据传送阶段2&#xff1a;对着目标写样式house-item-v9house-item-v9&#xff1a;debughouse-item-v3阶段3&#xff1a;总体效果效…

Android ANR触发机制(二)

上一篇文章看了Service的ANR触发流程&#xff0c;现在看一下其他三种ANR触发流程。 1.BroadcastReceiver触发ANR BroadcastReceiver超时是位于ActivityManager线程中的BroadcastQueue.BroadcastHandler收到BROADCAST_TIMEOUT_MSG消息时触发。 广播队列分为foreground队列和b…

基于Java+SpringBoot+Vue前后端分离学生管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《Spring家族及…

2023年二月份图形化二级打卡试题

活动时间 从2023年 2月1日至1月21日&#xff0c;每天一道编程题。 本次打卡的规则如下&#xff1a; &#xff08;1&#xff09;小朋友每天利用10~15分钟做一道编程题&#xff0c;遇到问题就来群内讨论&#xff0c;我来给大家答疑。 &#xff08;2&#xff09;小朋友做完题目后&…

数组中和为0的三个数

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意: 答案中不可以包含重复的三元组。 示例 1: 输入: num…

了解SLI、SLO和SLA

了解SLI、SLO和SLA 概念解释 服务水平指标(SLI) SLI代表目前服务的状态&#xff0c;例如可以是最基本的接口成功率、p99响应时间&#xff0c;也可以是一些业务指标&#xff0c;例如用户投诉率之类的。是可量化&#xff0c;是可确定的。 服务水平目标(SLO) SLO是目标&#x…

【树】哈夫曼树和哈夫曼编码

哈夫曼&#xff08;Huffman&#xff09;树&#xff0c;又称最优树&#xff0c;是一类带权路径长度最短的树。最优二叉树&#xff08;哈夫曼树&#xff09;路径&#xff1a;从树中一个结点到另一个结点之间的分支构成这两个结点之间的路。路径长度:路径上的分支数目&#xff1b;…

mysql分组排序取组内第一的数据行获取分组后,组内排名第一或最后的数据行。

前言&#xff1a; group by函数后取到的是分组中的第一条数据&#xff0c;但是我们有时候需要取出各分组的最新一条&#xff0c;该怎么实现呢&#xff1f; 本文提供两种实现方式。 一、准备数据 DROP TABLE IF EXISTS tb_dept; CREATE TABLE tb_dept (id bigint(20) UNSIG…

chat聊天系统消息消费时遇到的问题及优化思路

前言 之前有段工作经历涉及到了chat相关&#xff0c;而消息的发送 -> 存储 -> 消费是由不同的团队负责的&#xff0c;因此消息如何再多个团队之间流通、以及通过什么介质传递都是需要考虑的问题。 之前我负责过一些消息消费的相关工作&#xff0c;消息发送团队将消息推…

【Linux】简介磁盘|inode|动静态库

目录一.简介磁盘1.磁盘的物理结构&#xff1a;2.磁盘存储方式&#xff1a;3.磁盘的逻辑抽象&#xff1a;二.inode&&文件系统1.inode文件属性&#xff08;inode&#xff09;内容&#xff08;data block&#xff09;为什么删除一个文件相比于写一个文件要快得多&#xff…

若依配置教程(二)集成积木报表JimuReport

积木报表配置官网 在搭建好若依环境成功运行以后&#xff0c;我们先在这个系统中加一个小功能&#xff1a;JimuReport积木报表&#xff0c;以下步骤&#xff0c;我们按照官网教程&#xff0c;详细配置一下&#xff1a; 1.在ruoyi-admin文件夹下的pom.xml加入jar包依赖&#x…

MLP多层感知机理解

目录 .1简介 .2例子 2.1模型 2.2 实例 2.2.1 问题描述 2.2.2 数学过程 .3 代码 3.1 问题描述 3.2 代码 references&#xff1a; .1简介 多层感知机是全连接的 可以把低维的向量映射到高维度 MLP整个模型就是这样子的&#xff0c;上面说的这个三层的MLP用公式总结起来…

C 语言零基础入门教程(二十)

C 预处理器 C 预处理器不是编译器的组成部分&#xff0c;但是它是编译过程中一个单独的步骤。简言之&#xff0c;C 预处理器只不过是一个文本替换工具而已&#xff0c;它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器&#xff08;C Preprocessor&#x…

练手好福利!20个Python实战项目含源代码【2023最新】

高效学习源代码的步骤&#xff1a;1.运行程序&#xff0c;观察表现2.运行源码&#xff0c;断点调试&#xff0c;从头跟一边源码的执行流程&#xff0c;注意函数堆栈3.画类图、流程图&#xff0c;先把遇到的重要类记录下来&#xff0c;表明各个类的关系4.记录问题&#xff0c;把…

Unity XR

一、几个Unity XR Interaction Toolkit学习地址 1.B站视频 https://www.bilibili.com/video/BV11q4y1b74z/?spm_id_from333.999.0.0&vd_source8125d294022d2e63a58dfd228a7fcf63 https://www.bilibili.com/video/BV13b4y177J4/?spm_id_from333.999.0.0&vd_source8…

【对象的比较】java代码实现,详解对象的比较,Comparable接口和Comparator比较器

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#xff0c;&#x1f49e;&#x1f49e;&#x1f49e;今天的我们要学习的知识点是java对象的比较&#xff0c;不是大家现实生活中对象的比较&#xff0c;是java中new一个对象的那个对象&#xff0c;对象的比较到底是什么意思呢&…

24.网络编程(二)

目录 三.TCP通信 3.1 TCP协议特点 3.2 TCP协议通信场景 3.3 TCP通信模型演示 3.4 Socket 3.5 ServerSocket 3.6 注意事项 3.7 案例 3.7.1 TCP通信—单发单收 3.7.2 TCP通信—多发多收 3.7.3 TCP通信—同时接收多个客户端的消息。 3.7.4 TCP通信—使用线程池优化&am…

工业相机和镜头

工业相机和镜头镜头型号数据电源接口定焦镜头的调焦景深景深大小光圈相机、镜头选取参考镜头型号、数据电源接口、定焦镜头的调焦、景深、景深大小、光圈、相机、镜头选取 镜头型号 C&#xff0c;CS系列&#xff1a;相机镜头的C、CS接口非常相似&#xff0c;它们的接口直径、螺…

检索业务:基本数据渲染和排错

采用标签显示商品的数据 <div class"rig_tab"><div th:each"product:${result.getProducts()}"><div class"ico"><i class"iconfont icon-weiguanzhu"></i><a href"/static/search/#">…