初识Pandas

发布时间:2020-09-29 09:23:30编辑:admin阅读(2718)

    一、简介

    江湖上流传着这么一句话——分析不识潘大师(PANDAS),纵是老手也枉然。
    Pandas是基于Numpy的专业数据分析工具,可以灵活高效的处理各种数据集,也是我们后期分析案例的神器。它提供了两种类型的数据结构,分别是DataFrame和Series,我们可以简单粗暴的把DataFrame理解为Excel里面的一张表,而Series就是表中的某一列,后面学习和用到的所有Pandas骚操作,都是基于这些表和列进行的操作(关于Pandas和Excel的形象关系,这里推荐我的好朋友张俊红写的《对比EXCEL,轻松学习Python数据分析》)。
    这里有一点需要强调,Pandas和Excel、SQL相比,只是调用和处理数据的方式变了,核心都是对源数据进行一系列的处理,在正式处理之前,更重要的是谋定而后动,明确分析的意义,理清分析思路之后再处理和分析数据,往往事半功倍。

     

    环境说明

    操作系统:windows 10

    开发工具:Pycharm 2020.1

    pytho版本:3.7.9

     

    插件

    安装pandas

    pip3 install pandas

     

    二、创建、读取和存储

    创建

    在Pandas中我们想要构造下面这一张表应该如何操作呢?

    1.png

    别忘了,第一步一定是先导入我们的库——import pandas as pd
    构造DataFrame最常用的方式是字典+列表,语句很简单,先是字典外括,然后依次打出每一列标题及其对应的列值(此处一定要用列表),这里列的顺序并不重要:

    df1 = pd.DataFrame({'工资': [5000, 7000, 9000,8500], '绩效分': [60, 84, 98, 91], '备注': ['不及格', '良好', '最佳', '优秀']},
                       index=['老王', '小刘', '小赵', '老龚'])

    1.png

    左边是jupyter notebook中dataframe的样子,如果对应到excel中,他就是右边表格的样子,通过改变columns,index和values的值来控制数据。PS,如果我们在创建时不指定index,系统会自动生成从0开始的索引。

     

    读取

    新建一个文件流量练习数据.csv,将以下内容复制进去

    流量来源    来源明细    访客数    支付转化率    客单价
    一级     -A    35188    9.98%    54.3
    一级     -B    28467    11.27%    99.93
    一级     -C    13747    2.54%    0.08
    一级     -D    5183    2.47%    37.15
    一级     -E    4361    4.31%    91.73

     

    更多时候,我们是把相关文件数据直接读进PANDAS中进行操作,这里介绍两种非常接近的读取方式,一种是CSV格式的文件,一种是EXCEL格式(.xlsx和xls后缀)的文件。
    读取csv文件:

    # !/usr/bin/python3
    # -*- coding: utf-8 -*-
    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价
    0     一级       -A   35188      9.98%   54.30
    1     一级       -B   28467     11.27%   99.93
    2     一级       -C   13747      2.54%    0.08
    3     一级       -D    5183      2.47%   37.15
    4     一级       -E    4361      4.31%   91.73

     

    engine是使用的分析引擎,读取csv文件一般指定python避免中文和编码造成的报错。而读取Excel文件,则是一样的味道:

    需要先安装一个插件

    pip3 install xlrd

     

    新建一个文件,流量练习数据.xlsx,内容和上面的csv一样。

    读取excel

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df3 = pd.read_excel('流量练习数据.xlsx')
    ret = df3.head()
    print(ret)

    执行输出,效果同上

     

    非常easy,其实read_csv和read_excel还有一些参数,比如header、sep、names等,大家可以做额外了解。实践中数据源的格式一般都是比较规整的,更多情况是直接读取。

     

    存储

    注意:保存为excel文件时,需要安装一个插件

    pip3 install openpyxl

     

    存储起来一样非常简单粗暴且相似:

    # !/usr/bin/python3
    # -*- coding: utf-8 -*-
    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df3 = pd.read_excel('流量练习数据.xlsx')
    ret = df3.head()
    print(ret)
    
    df2.to_csv('xxx.csv')
    df3.to_excel('xxx.xlsx')

    执行之后,就可以看到2个文件了。

     

    三、快速认识数据

    这里以我们的案例数据为例,迅速熟悉查看N行,数据格式概览以及基础统计数据。

    查看数据,掐头看尾

    很多时候我们想要对数据内容做一个总览,用df.head()函数直接可以查看默认的前5行,与之对应,df.tail()就可以查看数据尾部的5行数据,这两个参数内可以传入一个数值来控制查看的行数,例如df.head(3)表示查看前3行数据。

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2.head(3)
    print(ret)

    执行输出:

      流量来源 来源明细  访客数 支付转化率  客单价
    0     一级       -A   35188      9.98%   54.30
    1     一级       -B   28467     11.27%   99.93
    2     一级       -C   13747      2.54%    0.08

    后3行

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2.tail(3)
    print(ret)

    执行输出:

      流量来源 来源明细  访客数 支付转化率  客单价
    2     一级       -C   13747      2.54%    0.08
    3     一级       -D    5183      2.47%   37.15
    4     一级       -E    4361      4.31%   91.73

     

    格式查看

    df.info()帮助我们一步摸清各列数据的类型,以及缺失情况:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2.info()
    print(ret)

    执行输出:

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 5 entries, 0 to 4                 一共有5行
    Data columns (total 5 columns):               一共有5列
     #   Column  Non-Null Count  Dtype  
    ---  ------  --------------  -----  
     0   流量来源    5 non-null      object        这列是object类型,有5条数据不为空
     1   来源明细    5 non-null      object 
     2   访客数     5 non-null      int64  
     3   支付转化率   5 non-null      object 
     4   客单价     5 non-null      float64        客单价列有5个数据不为空,是浮点型
    dtypes: float64(1), int64(1), object(3)
    memory usage: 328.0+ bytes
    None

    从上面直接可以知道数据集的行列数,数据集的大小,每一列的数据类型,以及有多少条非空数据。

     

    统计信息概览

    快速计算数值型数据的关键统计指标,像平均数、中位数、标准差等等。

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2.describe()
    print(ret)

    执行输出:

    访客数     客单价
    count      5.000000   5.000000
    mean   17389.200000  56.638000
    std    13887.997235  40.895298
    min     4361.000000   0.080000
    25%     5183.000000  37.150000
    50%    13747.000000  54.300000
    75%    28467.000000  91.730000
    max    35188.000000  99.930000

    我们本来有5列数据,为什么返回结果只有两列?那是因为这个操作只针对数值型的列。其中count是统计每一列的有多少个非空数值,mean、std、min、max对应的分别是该列的均值、标准差、最小值和最大值,25%、50%、75%对应的则是分位数。

     

    四、列的基本处理方式

    这里,我们采用SQL四大法宝的逻辑来简单梳理针对列的基本处理方式——增、删、选、改。

    温馨提示:使用Pandas时,尽量避免用行或者EXCEL操作单元格的思维来处理数据,要逐渐养成一种列向思维,每一列是同宗同源,处理起来是嗖嗖的快。

    增加一列,用df['新列名'] = 新列值的形式,在原数据基础上赋值即可:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['新增的列'] = range(1,len(df2)+1)
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价  新增的列
    0     一级       -A   35188      9.98%   54.30         1
    1     一级       -B   28467     11.27%   99.93         2
    2     一级       -C   13747      2.54%    0.08         3
    3     一级       -D    5183      2.47%   37.15         4
    4     一级       -E    4361      4.31%   91.73         5

     

    我们用drop函数制定删除对应的列,axis = 1表示针对列的操作,inplace为True,则直接在源数据上进行修改,否则源数据会保持原样。

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['新增的列'] = range(1,len(df2)+1)
    df2.drop('新增的列',axis=1,inplace=True)
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价
    0     一级       -A   35188      9.98%   54.30
    1     一级       -B   28467     11.27%   99.93
    2     一级       -C   13747      2.54%    0.08
    3     一级       -D    5183      2.47%   37.15
    4     一级       -E    4361      4.31%   91.73

     

    想要选取某一列怎么办?df['列名']即可:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2['客单价']
    print(ret)

    执行输出:

    0    54.30
    1    99.93
    2     0.08
    3    37.15
    4    91.73

     

    选取多列呢?需要用列表来传递:df[['第一列','第二列','第三列'..]]

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    ret = df2[['流量来源','访客数','支付转化率']]
    print(ret)

    执行输出:

    流量来源  访客数 支付转化率
    0     一级   35188      9.98%
    1     一级   28467     11.27%
    2     一级   13747      2.54%
    3     一级    5183      2.47%
    4     一级    4361      4.31%


    好事多磨,复杂的针对特定条件和行列的筛选、修改,放在后面结合案例细讲,这里只讲一下最简单的更改:df['旧列名'] =  某个值或者某列值,就完成了对原列数值的修改。

    比如,将数据来源,统一改成aliyun

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['来源明细'] = 'aliyun'
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价
    0     一级   aliyun   35188      9.98%   54.30
    1     一级   aliyun   28467     11.27%   99.93
    2     一级   aliyun   13747      2.54%    0.08
    3     一级   aliyun    5183      2.47%   37.15
    4     一级   aliyun    4361      4.31%   91.73


    五、常用数据类型及操作

    字符串

     字符串类型是最常用的格式之一了,Pandas中字符串的操作和原生字符串操作几乎一毛一样,唯一不同的是需要在操作前加上".str"。
    小Z温馨提示:我们最初用df2.info()查看数据类型时,非数值型的列都返回的是object格式,和str类型深层机制上的区别就不展开了,在常规实际应用中,我们可以先理解为object对应的就是str格式,int64对应的就是int格式,float64对应的就是float格式即可。
    在案例数据中,我们发现来源明细那一列,可能是系统导出的历史遗留问题,每一个字符串前面都有一个“-”符号,又丑又无用,所以把他给拿掉:

    一般来说清洗之后的列是要替换掉原来列的:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['来源明细'] = df2['来源明细'].str.replace('-','')
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价
    0     一级        A   35188      9.98%   54.30
    1     一级        B   28467     11.27%   99.93
    2     一级        C   13747      2.54%    0.08
    3     一级        D    5183      2.47%   37.15
    4     一级        E    4361      4.31%   91.73


    数值型

    数值型数据,常见的操作是计算,分为与单个值的运算,长度相等列的运算。
    以案例数据为例,源数据访客数我们是知道的,现在想把所有渠道的访客都加上10000,怎么操作呢?

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['访客数'] = df2['访客数'] + 10000
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价
    0     一级       -A   45188      9.98%   54.30
    1     一级       -B   38467     11.27%   99.93
    2     一级       -C   23747      2.54%    0.08
    3     一级       -D   15183      2.47%   37.15
    4     一级       -E   14361      4.31%   91.73

    需要选中访客数所在列,然后加上10000即可,pandas自动将10000和每一行数值相加,针对单个值的其他运算(减乘除)也是如此。
    列之间的运算语句也非常简洁。源数据是包含了访客数、转化率和客单价,而实际工作中我们对每个渠道贡献的销售额更感兴趣。(销售额 = 访客数 X 转化率 X 客单价)
    对应操作语句:df['销售额'] = df['访客数']  * df['转化率']  * df['客单价']
    但为什么疯狂报错?
    导致报错的原因,是数值型数据和非数值型数据相互计算导致的。PANDAS把带“%”符号的转化率识别成字符串类型,我们需要先拿掉百分号,再将这一列转化为浮点型数据:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['支付转化率'] = df2['支付转化率'].str.replace('%','').astype(float)
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数  支付转化率  客单价
    0     一级       -A   35188        9.98   54.30
    1     一级       -B   28467       11.27   99.93
    2     一级       -C   13747        2.54    0.08
    3     一级       -D    5183        2.47   37.15
    4     一级       -E    4361        4.31   91.73

     

    要注意的是,这样操作,把9.98%变成了9.98,所以我们还需要让支付转化率除以100,来还原百分数的真实数值:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['支付转化率'] = df2['支付转化率'].str.replace('%','').astype(float)
    df2['支付转化率'] = df2['支付转化率'] / 100
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数  支付转化率  客单价
    0     一级       -A   35188      0.0998   54.30
    1     一级       -B   28467      0.1127   99.93
    2     一级       -C   13747      0.0254    0.08
    3     一级       -D    5183      0.0247   37.15
    4     一级       -E    4361      0.0431   91.73

     

    然后,再用三个指标相乘计算销售额:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['支付转化率'] = df2['支付转化率'].str.replace('%','').astype(float)
    df2['支付转化率'] = df2['支付转化率'] / 100
    df2['销售额'] = df2['访客数'] * df2['支付转化率'] * df2['客单价']
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数  支付转化率  客单价         销售额
    0     一级       -A   35188      0.0998   54.30  190688.698320
    1     一级       -B   28467      0.1127   99.93  320598.513837
    2     一级       -C   13747      0.0254    0.08      27.933904
    3     一级       -D    5183      0.0247   37.15    4755.946715
    4     一级       -E    4361      0.0431   91.73   17241.488243


    时间类型

    PANDAS中时间序列相关的水非常深,这里只对日常中最基础的时间格式进行讲解,对时间序列感兴趣的同学可以自行查阅相关资料,深入了解。
    以案例数据为例,我们这些渠道数据,是在2019年8月2日提取的,后面可能涉及到其他日期的渠道数据,所以需要加一列时间予以区分,在EXCEL中常用的时间格式是'2019-8-3'或者'2019/8/3',我们用PANDAS来实现一下:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['日期'] = '2019-8-3'
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价      日期
    0     一级       -A   35188      9.98%   54.30  2019-8-3
    1     一级       -B   28467     11.27%   99.93  2019-8-3
    2     一级       -C   13747      2.54%    0.08  2019-8-3
    3     一级       -D    5183      2.47%   37.15  2019-8-3
    4     一级       -E    4361      4.31%   91.73  2019-8-3


    在实际业务中,一些时候PANDAS会把文件中日期格式的字段读取为字符串格式,这里我们先把字符串'2019-8-3'赋值给新增的日期列,然后用to_datetime()函数将字符串类型转换成时间格式:

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['日期'] = '2019-8-3'
    df2['日期'] = pd.to_datetime(df2['日期'])
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价       日期
    0     一级       -A   35188      9.98%   54.30 2019-08-03
    1     一级       -B   28467     11.27%   99.93 2019-08-03
    2     一级       -C   13747      2.54%    0.08 2019-08-03
    3     一级       -D    5183      2.47%   37.15 2019-08-03
    4     一级       -E    4361      4.31%   91.73 2019-08-03

     

    转换成时间格式(这里是datetime64)之后,我们可以用处理时间的思路高效处理这些数据,比如,我现在想知道提取数据这一天离年末还有多少天('2019-12-31'),直接做减法(该函数接受时间格式的字符串序列,也接受单个字符串):

    import pandas as pd
    pd.set_option('display.unicode.ambiguous_as_wide', True)#设置列名对齐
    pd.set_option('display.unicode.east_asian_width', True)#设置列名对齐
    
    df2 = pd.read_csv('流量练习数据.csv',engine='python')
    df2['日期'] = '2019-8-3'
    df2['日期'] = pd.to_datetime('2019-12-31') - pd.to_datetime(df2['日期'])
    ret = df2.head()
    print(ret)

    执行输出:

    流量来源 来源明细  访客数 支付转化率  客单价     日期
    0     一级       -A   35188      9.98%   54.30 150 days
    1     一级       -B   28467     11.27%   99.93 150 days
    2     一级       -C   13747      2.54%    0.08 150 days
    3     一级       -D    5183      2.47%   37.15 150 days
    4     一级       -E    4361      4.31%   91.73 150 days

     

    是不是非常简单?
    最后我们一起快速回顾下第一篇文章的内容:

    • 第一步,我们先了解PANDAS到底是个什么东西。

    • 第二步,学习如何构建、读入存储数据。

    • 第三步,拿到数据之后,怎么样快速查看数据。

    • 第四步,对数据有了基础了解,就可以进行简单的增删选改了。

    • 第五步,在了解基础操作之后,对Pandas中基础数据类型进行了初步照面。

     

    每一步都是本着小而美(毕竟臭美也算美)和轻量的初心,和大家一起重新认识回顾这些模块,然后在接下来的案例实践中检验、巩固、沉淀这些操作与分析思路。

     

    本文参考链接:

    https://mp.weixin.qq.com/s?__biz=MzU5Mjg2OTQ1MA==&mid=2247484097&idx=1&sn=ad8fabbd84bf67655996026fc0ac5688&chksm=fe1863e4c96feaf200e9398bb7c824e99d3fc01ec965666497ce584466dc93f83dd5d127a46d&scene=21#wechat_redirect


关键字