美文网首页Python学习python-数据分析Python
利用 Pandas 进行简单数据分析流程

利用 Pandas 进行简单数据分析流程

作者: 禹洋 | 来源:发表于2017-09-12 18:50 被阅读554次

    本文来自于 猴子数据分析社群的通关作业,因为课程是用 R 语言教的,我是用 Python 实现了一遍,所以参考的文档也都列了出来,总结的也挺不容易的,欢迎同学吐槽。

    文章主要简单实现了一遍初级的数据分析过程,首先是利用 pandas 读取 excel 文件,之后简单的通过去空值等过程简单处理了数据内容,最后计算了了几个常用的业绩指标。

    文章算是实现了一个最初级的数据分析过程,比起啃一本完整的教材还是不能实践,不如今早开始将知识投入到使用过程中,形成宏观知识架构方便后续补充学习,同时还能熟悉知识点和知识点之间的协作过程。

    1. 读取 excel

    # coding=utf-8
    
    import pandas as pd
    import numpy as np
    
    import matplotlib.pyplot as plt
    
    file_name = "../源代码和数据/朝阳医院2016年销售数据.xlsx"
    
    xls_file = pd.ExcelFile(file_name, dtype='object') # 统一先按照str读入,之后转换
    
    table = xls_file.parse('Sheet1', dtype='object')
    
    # file_name = "../源代码和数据/朝阳医院2016年销售数据.xlsx"
    # table = pd.read_excel(file_name, sheeetname = 'Sheet1', dtype='object')
    
    print type(xls_file)
    print type(table)
    

    <class 'pandas.io.excel.ExcelFile'>
    <class 'pandas.core.frame.DataFrame'>

    table.head()
    

    元数据好像没有空值,所以我自己加了两行

    2. 数据预处理

    2.1 查看基本信息

    print table.shape
    print table.index
    print table.columns
    

    (6579, 7)
    RangeIndex(start=0, stop=6579, step=1)
    Index([u'购药时间', u'社保卡号', u'商品编码', u'商品名称', u'销售数量', u'应收金额', u'实收金额'], dtype='object')

    print table.info()
    

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 6579 entries, 0 to 6578
    Data columns (total 7 columns):
    购药时间 6577 non-null object
    社保卡号 6578 non-null object
    商品编码 6577 non-null object
    商品名称 6578 non-null object
    销售数量 6577 non-null object
    应收金额 6577 non-null object
    实收金额 6577 non-null object
    dtypes: object(7)
    memory usage: 359.9+ KB
    None

    print table.count()
    

    购药时间 6577
    社保卡号 6578
    商品编码 6577
    商品名称 6578
    销售数量 6577
    应收金额 6577
    实收金额 6577
    dtype: int64

    2.2 列重命名

    pandas 的 rename 方法 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rename.html

    col = {u'购药时间':'time',\
    u'社保卡号':'cardno',\
    u'商品编码':'drugId',\
    u'商品名称':'drugName',\
    u'销售数量':'saleNumber',\
    u'应收金额':'virtualmoney',\
    u'实收金额':'actualmoney'}
    
    table.rename(columns = col, inplace = True)
    
    table.head()
    

    2.3 删除缺失值

    pandas 的 dropna 方法 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html?highlight=dropna#pandas.DataFrame.dropna|

    dropna1 = table.dropna()
    dropna2 = table.dropna(how = 'all') # 参数设定是,所有值为 NA 才删除掉
    
    dropna1.head()
    
    dropna2.head()
    

    2.4 处理日期

    # 定义一个把 time 行中日期和星期分开的函数,分别返回日期和星期构成的 list
    def split_datetime_weekday(t_w_column):
    
    datetime_list = [x.split()[0] for x in t_w_column ] # 列表推导式的简写
    weekday_list = [x.split()[1] for x in t_w_column]
    
    return datetime_list, weekday_list
    
    
    datetime_list, weekday_list = split_datetime_weekday(dropna1.loc[:,'time'])
    dropna1.loc[:,'datetime'] = pd.to_datetime(datetime_list)
    # 这里直接用了一个 .to_datetime 方法,将所有数据的改成了 datetime64 的类型
    dropna1.loc[:, 'weekday'] = weekday_list
    
    dropna1.info()
    

    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 6577 entries, 2 to 6578
    Data columns (total 9 columns):
    time 6577 non-null object
    cardno 6577 non-null object
    drugId 6577 non-null object
    drugName 6577 non-null object
    saleNumber 6577 non-null object
    virtualmoney 6577 non-null object
    actualmoney 6577 non-null object
    datetime 6577 non-null datetime64[ns]
    weekday 6577 non-null object
    dtypes: datetime64ns, object(8)
    memory usage: 513.8+ KB

    2.5 数据类型转换

    dropna1.loc[:,'saleNumber'] = dropna1['saleNumber'].astype('float64')
    dropna1.loc[:,'virtualmoney'] = dropna1['virtualmoney'].astype('float64')
    dropna1.loc[:,'actualmoney'] = dropna1['actualmoney'].astype('float64')
    
    • 之前的改变数据类型的方式有报错,还是改成了文档推荐的赋值方式,两种区别也简要写了一下,详细可以阅读官方文档

    1. 是先索引第一层级[colom1],返回了 Dataframe 的对象,然后对这个对象再次索引 [column2],所以可以看做是一种连续两次的线性操作
    2. loc 索引则是利用了一个组合的索引,pandas 可以把这个返回对象当做一个整体处理,同时速度上也比第一种快。
    dropna1.info()
    

    <class 'pandas.core.frame.DataFrame'>
    Int64Index: 6577 entries, 2 to 6578
    Data columns (total 9 columns):
    time 6577 non-null object
    cardno 6577 non-null object
    drugId 6577 non-null object
    drugName 6577 non-null object
    saleNumber 6577 non-null float64
    virtualmoney 6577 non-null float64
    actualmoney 6577 non-null float64
    datetime 6577 non-null datetime64[ns]
    weekday 6577 non-null object
    dtypes: datetime64ns, float64(3), object(5)
    memory usage: 513.8+ KB

    2.6 排序

    dropna1.sort_values("time").head(3)
    

    3 简单数据分析

    本节是对一些指标的分析,我自己也加了一些可视化的内容,可视化不是重点,只是简单画了一下,并没有做美化,甚至连标签都没改。。

    • 月均消费次数
    • 月均消费金额
    • 客单价
    • 消费趋势

    3.1 月均消费次数

    要点:

    • 同一个日期和同一个社保卡号的多个消费记录算作一次消费,
    • 可以将单独两列抽出来单独分析,先去重复,然后再计数
    • 这个分析可以画一个每个月的消费次数的折线图

    data_consume_unique 是将 datetime cardno 去重后复制出来的新的 Dataframe

    data_consume_unique = dropna1.drop_duplicates(subset=['datetime', 'cardno']).copy(deep = True)
    
    consume_time_date_ser = pd.Series(list(data_consume_unique['cardno']), index = data_consume_unique['datetime'])
    
    # 排序之后将日期结尾 减去 日期开头,计算总天数
    date_interval = consume_time_date_ser.sort_index().index[-1]-consume_time_date_ser.sort_index().index[0]
    # 利用总天使,计算总月数,其中 timedelta 数据类型的 attribute 参见官方文档
    # 这里用到了 days,提取出了总天数
    month_count = date_interval.days/30 + 1 # 我觉得这个月份应该是要 + 1 的,猴子老师课程里面没加
    
    month_consume = consume_time_date_ser.count()/month_count
    print month_consume
    

    771

    • 通过时间序列的 month 分组,之后用 .count() 来计算组内总和,也就是每月消费次数
    month_time = consume_time_date_ser.groupby(consume_time_date_ser.index.month).count()
    plt.plot(month_time.index, month_time)
    plt.show()
    

    3.2 月均消费金额

    • 月均消费金额 = 总消费金额 / 月份数
    • 这里可以画一个每月消费总额的柱状图
    total_money = dropna1['actualmoney'].sum()
    month_money = total_money / month_count
    print month_money # 43518.6085714
    

    43518.6085714

    • 构建以实收金额 actualmoney 的时间序列 data_consume_actual
    data_consume_actual = pd.Series(list(dropna1['actualmoney']), index = list(dropna1['datetime']))
    
    • 通过 month 分组,对组内数据进行求和,求和结果为每月的实收金额总和
    month_consume = data_consume_actual.groupby(data_consume_actual.index.month).sum()
    plt.plot(month_consume.index, month_consume)
    plt.show()
    

    3.3 客单价

    • 客单价(per customer transaction)是指商场(超市)每一个顾客平均购买商品的金额,客单价也即是平均交易金额。
    consume_num = len(dropna1['cardno'].unique())
    print consume_num # 所有不重复医保卡号码,总数量
    pct = total_money / consume_num
    print pct # 客单价
    

    2426
    125.568944765

    3.4 消费趋势

    • 分组也是根据 week 进行的分组,之后求和,类似于上面按照月的来求和
    • 画出随着 week 变化与 实收金额 actualmoney 的变化趋势
    week_consume = data_consume_actual.groupby(data_consume_actual.index.week).sum()
    plt.plot(week_consume.index, week_consume)
    plt.show()
    

    这个图还是有点问题的,因为开头几天还归属2015年的周数计算,所以信息中有53周的数据,折线也就直接拉到53周了。

    与网友相关的关于切片,复制之类的讨论:

    欢迎关注我的微信公众号 :practice_yuyang,不定期更新数据分析学习心得,学习过程。

    相关文章

      网友评论

        本文标题:利用 Pandas 进行简单数据分析流程

        本文链接:https://www.haomeiwen.com/subject/rkaxittx.html