数据建模与分析|NumPy和Pandas的综合应用

本文聚焦数据建模中的数据预处理和基本分析,说明NumPy和Pandas的数据读取、数据分组、数据重编码、分类汇总等数据加工处理功能。
以某市空气质量监测数据为对象,演示对其进行预处理和基本分析过程。

1. 导入相关包

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

2. 利用pandas读取excel数据

使用pandas的.read_excel()方法读取excel文件,获得DataFrame对象。
pandas.read_excel()支持从本地文件系统或URL读取的xls,xlsx,xlsm,xlsb和odf文件扩展名。 支持读取单一sheet或几个sheet。
以下是该函数的全部参数,等于号后面是该参数的缺省值,参数看着很多,但其实我们日常用到的就几个:

pandas.read_excel(
io,
sheet_name=0,
header=0,
names=None,
index_col=None,
usecols=None,
squeeze=False,
dtype=None,
engine=None,
converters=None,
true_values=None,
false_values=None,
skiprows=None,
nrows=None,
na_values=None,
keep_default_na=True,
verbose=False,
parse_dates=False,
date_parser=None,
thousands=None,
comment=None,
skipfooter=0,
convert_float=True,
mangle_dupe_cols=True,
**kwds)

常用参数说明

  • io,支持str, bytes, ExcelFile, xlrd.Book, path object, or file-like object
  • sheet_name(str, int, list, None, default 0)str字符串用于引用的sheet的名称
  • header(int, list of int, default 0)表示用第几行作为表头,默认header=0,即默认第一行为表头
  • names(array-like, default None)表示自定义表头的名称,需要传递数组参数。用于更改原始的表头。
  • index_col(int, list of int, default None)指定列为索引列,默认为None,也就是索引为0的列用作DataFrame的行标签。
  • usecols(int, str, list-like, or callable default None)默认为None,解析所有列。如果为str,则表示Excel列字母和列范围的逗号分隔列表(例如“ A:E”或“ A,C,E:F”)。范围全闭。如果为int,则表示解析到第几列。如果为int列表,则表示解析那几列。
  • squeeze(bool, default False),默认为False。如果设置squeeze=True则表示如果解析的数据只包含一列,则返回一个Series。
  • dtype(Type name or dict of column -> type, default None)列的类型名称或字典,默认为None,也就是不改变数据类型。其作用是指定列的数据类型。
  • engine(str, default None)可以接受的参数有“ xlrd”,“ openpyxl”或“ odf”,用于使用第三方的库去解析excel文件。
  • converters(dict, default None)对指定列的数据进行指定函数的处理,传入参数为列名与函数组成的字典。key 可以是列名或者列的序号,values是函数,可以def函数或者直接lambda都行。
  • true_values(list,default None)将指定的文本转换为True,默认为None
  • false_values(list,default None)将指定的文本转换为False,默认为None,将性别中的女转换为True,男转换为False
  • skiprows(list like)跳过指定的行,skiprows=1 跳过第1行,skiprows=3 跳过前3行,skiprows=[1,3,5] 跳过第1,3,5行,skiprows=lambda x: x % 2 == 0 跳过偶数行
  • nrows(int, default None),默认为None,指定需要读取前多少行,通常用于较大的数据文件中。nrows=3 读取前三行
  • na_values(scalar, str, list-like, or dict, default None),指定某些列的某些值为NaN,na_values=‘–’,指定“–”为NaN
  • keep_default_na(bool, default True),表示导入数据时是否导入空值。默认为True,即自动识别空值并导入
data=pd.read_excel('北京市空气质量数据.xlsx')

3. 使用DataFrame类的replace()方法

在处理数据的时候,很多时候会遇到批量替换的情况,如果一个一个去修改效率过低,也容易出错。
replace的基本结构是:df.replace(to_replace, value) 前面是需要替换的值,后面是替换后的值。
要注意这样的操作并没有改变文档的源数据,要改变源数据需要使用参数:inplace = True
replace方法还可以替换部分内容。
以下利用DataFrame类的replace()将数据框中的0替换为缺失值NaN

data=data.replace(0,np.NaN)

4. 使用Pandas的apply()方法

Pandas的apply()方法是用来调用一个函数(Python method),让此函数对数据对象进行批量处理。Pandas的很多对象都可以使用 apply() 来调用函数,如 Dataframe、Series、分组对象、各种时间序列等。
apply() 使用时,通常放入一个 lambda 函数表达式、或一个函数作为操作运算,官方上给出DataFrame的 apply() 用法:

DataFrame.apply(self, func, axis=0, raw=False, result_type=None, args=(), **kwargs)

参数为:

        func:函数或 lambda 表达式,应用于每行或者每列
        axis:{0 or ‘index’, 1 or ‘columns’}, 默认为0
                0 or ‘index’: 表示函数处理的是每一列
                1 or ‘columns’: 表示函数处理的是每一行
        raw:bool 类型,默认为 False;
                False ,表示把每一行或列作为 Series 传入函数中;
                True,表示接受的是 ndarray 数据类型;
        result_type:{‘expand’, ‘reduce’, ‘broadcast’, None}, default None
        These only act when axis=1 (columns):
        ‘expand’ : 列表式的结果将被转化为列。
        ‘reduce’ : 如果可能的话,返回一个 Series,而不是展开类似列表的结果。这与 expand 相反。
        ‘broadcast’ : 结果将被广播到 DataFrame 的原始形状,原始索引和列将被保留。
        args: func 的位置参数

        **kwargs:要作为关键字参数传递给 func 的其他关键字参数,1.3.0 开始支持

        返回值:
        Series 或者 DataFrame:沿数据的给定轴应用 func 的结果

以下利用.apply()方法以及匿名函数,基于“日期”变量得到每个样本观测的年份和月份。

data['年']=data['日期'].apply(lambda x:x.year)
month=data['日期'].apply(lambda x:x.month)

建立一个关于月份和季度的字典quarter_month。利用Python函数map(),依据字典quarter_month,将序列month中的1,2,3等月份映射(对应)到相应的季度上。

quarter_month={'1':'一季度','2':'一季度','3':'一季度',
               '4':'二季度','5':'二季度','6':'二季度',
               '7':'三季度','8':'三季度','9':'三季度',
              '10':'四季度','11':'四季度','12':'四季度'}
data['季度']=month.map(lambda x:quarter_month[str(x)])

5. 使用Pandas的cut()方法

数据分析中,将连续的、非常大的比例或高度偏斜的数值数据分成离散的区间会更容易。 当值被划分为有意义的类别时,这有助于执行描述性统计。例如,我们可以将确切的年龄划分为幼儿、儿童、成人和老年人。
Pandas 内置的 cut() 函数是将数值数据转换为分类数据的好方法。

pandas.cut(x, bins, right=True, labels=None, retbins=False,
precision=3, include_lowest=False, duplicates=‘raise’,
ordered=True)

参数:

x : 是我们要传入和切分的一维数组,可以是列表,也可以是dataFrame的一列
bins : 代表切片的方式,可以自定义传入列表[a,b,c],表示按照a-b,b-c的区间来切分,也可以是数值n,直接指定分为n组
right : True/False,为True时,表示分组区间是包含右边,不包含左边,即(]; False,代表[)
labels : 标签参数,比如[低、中、高]
retbins : True/False, True返回bin的具体范围值,当bins是单个数值时很有用。(因为bin是数字的话, 划分组具体数值我们是不知道的)
precision : 存储和显示 bin 标签的精度。默认为3
include_lowest : True/False, 第一个区间是否应该是左包含的
duplicates : raise/drop, 如果bin列表里有重复,报错/直接删除至保留一个
ordered : 标签是否有序。 适用于返回的类型 Categorical和Series(使用Categorical dtype)。 如果为 True,则将对生成的分类进行排序。 如果为 False,则生成的分类将是无序的(必须提供标签)

以下示例中生成一个后续用于对AQI分组的列表bins。它描述了AQI和空气质量等级的数值对应关系。然后利用Pandas的cut()方法对AQI进行分组。

bins=[0,50,100,150,200,300,1000]
data['等级']=pd.cut(data['AQI'],bins,labels=['一级优','二级良','三级轻度污染','四级中度污染','五级重度污染','六级严重污染'])
print('对AQI的分组结果:\n{0}'.format(data[['日期','AQI','等级','季度']]))
对AQI的分组结果:
             日期    AQI      等级   季度
0    2014-01-01   81.0     二级良  一季度
1    2014-01-02  145.0  三级轻度污染  一季度
2    2014-01-03   74.0     二级良  一季度
3    2014-01-04  149.0  三级轻度污染  一季度
4    2014-01-05  119.0  三级轻度污染  一季度
...         ...    ...     ...  ...
2150 2019-11-22  183.0  四级中度污染  四季度
2151 2019-11-23  175.0  四级中度污染  四季度
2152 2019-11-24   30.0     一级优  四季度
2153 2019-11-25   40.0     一级优  四季度
2154 2019-11-26   73.0     二级良  四季度

[2155 rows x 4 columns]

6. 使用DataFrame的groupby()方法

和sql中的分组类似,pandas中的groupby函数也是先将df按照某个字段进行拆分,将相同属性分为一组;然后对拆分后的各组执行相应的转换操作;最后输出汇总转换后的各组结果。 以下代码示例功能:

  • 利用数据框的groupby()方法,计算各季度AQI和PM2.5的平均值。
  • 计算几个季度AQI和PM2.5的基本描述统计量(均值,标准差,最小值,四分位数,最大值)。
  • 定义了一个名为top的用户自定义函数:对给定数据框,按指定列(默认AQI列)值的降序排序,返回排在前n(默认10)条数据。
  • 调用用户自定义函数top,对data数据框中,按AQI值的降序排序并返回前5条数据,即AQI最高的5天的数据。
  • 首先对数据按季度分组,依次对分组数据调用用户自定义函数top,得到各季度AQI最高的3天数据。
  • 利用Pandas函数crosstab()对数据按季度和空气质量等级交叉分组,并给出各个组的样本量。
print('各季度AQI和PM2.5的均值:\n{0}'.format(data.loc[:,['AQI','PM2.5']].groupby(data['季度']).mean()))
各季度AQI和PM2.5的均值:
            AQI      PM2.5
季度                        
一季度  109.327778  77.225926
三季度   98.911071  49.528131
二季度  109.369004  55.149723
四季度  109.612403  77.195736
print('各季度AQI和PM2.5的描述统计量:\n',data.groupby(data['季度'])[['AQI','PM2.5']].apply(lambda x:x.describe()))
各季度AQI和PM2.5的描述统计量:
                   AQI       PM2.5
季度                               
一季度 count  540.000000  540.000000
    mean   109.327778   77.225926
    std     80.405408   73.133857
    min     26.000000    4.000000
    25%     48.000000   24.000000
    50%     80.000000   53.000000
    75%    145.000000  109.250000
    max    470.000000  454.000000
三季度 count  551.000000  551.000000
    mean    98.911071   49.528131
    std     45.484516   35.394897
    min     28.000000    3.000000
    25%     60.000000   23.000000
    50%     95.000000   41.000000
    75%    130.500000   67.000000
    max    252.000000  202.000000
二季度 count  542.000000  541.000000
    mean   109.369004   55.149723
    std     49.608042   35.918345
    min     35.000000    5.000000
    25%     71.000000   27.000000
    50%     99.000000   47.000000
    75%    140.750000   73.000000
    max    500.000000  229.000000
四季度 count  516.000000  516.000000
    mean   109.612403   77.195736
    std     84.192134   76.651794
    min     21.000000    4.000000
    25%     55.000000   25.000000
    50%     78.000000   51.000000
    75%    137.250000  101.500000
    max    485.000000  477.000000
def top(df,n=10,column='AQI'):
    return df.sort_values(by=column,ascending=False)[:n]
print('空气质量最差的5天:\n',top(data,n=5)[['日期','AQI','PM2.5','等级']])
print('各季度空气质量最差的3天:\n',data.groupby(data['季度']).apply(lambda x:top(x,n=3)[['日期','AQI','PM2.5','等级']]))
print('各季度空气质量情况:\n',pd.crosstab(data['等级'],data['季度'],margins=True,margins_name='总计',normalize=False))
空气质量最差的5天:
              日期    AQI  PM2.5      等级
1218 2017-05-04  500.0    NaN  六级严重污染
723  2015-12-25  485.0  477.0  六级严重污染
699  2015-12-01  476.0  464.0  六级严重污染
1095 2017-01-01  470.0  454.0  六级严重污染
698  2015-11-30  450.0  343.0  六级严重污染
各季度空气质量最差的3天:
                  日期    AQI  PM2.5      等级
季度                                       
一季度 1095 2017-01-01  470.0  454.0  六级严重污染
    45   2014-02-15  428.0  393.0  六级严重污染
    55   2014-02-25  403.0  354.0  六级严重污染
三季度 186  2014-07-06  252.0  202.0  五级重度污染
    211  2014-07-31  245.0  195.0  五级重度污染
    183  2014-07-03  240.0  190.0  五级重度污染
二季度 1218 2017-05-04  500.0    NaN  六级严重污染
    1219 2017-05-05  342.0  181.0  六级严重污染
    103  2014-04-14  279.0  229.0  五级重度污染
四季度 723  2015-12-25  485.0  477.0  六级严重污染
    699  2015-12-01  476.0  464.0  六级严重污染
    698  2015-11-30  450.0  343.0  六级严重污染
各季度空气质量情况:
 季度      一季度  三季度  二季度  四季度    总计
等级                              
一级优     145   96   38  108   387
二级良     170  209  240  230   849
三级轻度污染   99  164  152   64   479
四级中度污染   57   72   96   33   258
五级重度污染   48   10   14   58   130
六级严重污染   21    0    2   23    46
总计      540  551  542  516  2149

7. 使用Pandas的get_dummies方法

get_dummies 是 pandas 实现one hot encode的方式。one-hot的基本思想:将离散型特征的每一种特征取值都看成一种状态,若指定离散特征中有N个不相同的取值,那么我们就可以将该特征抽象成N种不同的状态,one-hot编码保证了每一个取值只会使得一种状态处于“激活态”,也就是说这N种状态中只有一个状态位值为1,其他状态位都是0。以下利用Pandas的get_dummies得到分类型变量“等级”的哑变量。

pd.get_dummies(data['等级'])
一级优二级良三级轻度污染四级中度污染五级重度污染六级严重污染
0010000
1001000
2010000
3001000
4001000
.....................
2150000100
2151000100
2152100000
2153100000
2154010000

2155 rows × 6 columns

8. 使用DataFrame的join方法

join操作是关系型数据库中最核心没有之一的操作,实际中最容易出问题,经常需要优化的点也是join操作。如果我们将dataframe类比为一张表,自然也会涉及到join操作,而且非常非常常见。
利用数据框的join()方法,将原始数据和哑变量数据,按行索引进行横向合并。

data.join(pd.get_dummies(data['等级']))
日期AQI质量等级PM2.5PM10SO2CONO2O3季度等级一级优二级良三级轻度污染四级中度污染五级重度污染六级严重污染
02014-01-0181.045.0111.028.01.562.052.02014一季度二级良010000
12014-01-02145.0轻度污染111.0168.069.03.493.014.02014一季度三级轻度污染001000
22014-01-0374.047.098.029.01.352.056.02014一季度二级良010000
32014-01-04149.0轻度污染114.0147.040.02.875.014.02014一季度三级轻度污染001000
42014-01-05119.0轻度污染91.0117.036.02.367.044.02014一季度三级轻度污染001000
.........................................................
21502019-11-22183.0中度污染138.0181.09.02.494.05.02019四季度四级中度污染000100
21512019-11-23175.0中度污染132.0137.06.01.669.034.02019四季度四级中度污染000100
21522019-11-2430.07.030.03.00.211.058.02019四季度一级优100000
21532019-11-2540.013.030.03.00.432.029.02019四季度一级优100000
21542019-11-2673.038.072.06.00.858.014.02019四季度二级良010000

2155 rows × 18 columns

9. 使用DataFrame的take方法

与NumPy的ndarrays相似,pandas的 Index, Series,和DataFrame 也提供take()方法。他可以沿着某个维度,按照给定的索引取回所有的元素。这个给定的索引必须要是一个由整数组成的列表或者ndarray,用以指明在索引中的位置。take也可以接受负整数,作为相对于结尾的相对位置。
最后:

  • 利用Pandas函数random.randint()在指定范围内随机抽取指定个数(这里是10)的随机数。
  • 利用Pandas函数random.permutation是对数据随机打乱重排。之后再抽取前10个样本观测。
  • 利用数据框的take()方法,基于指定随机数获得数据集的一个子集。
  • 利用数据框访问的方式,抽取满足指定条件(质量等级等于优)行的数据
np.random.seed(123)
sampler=np.random.randint(0,len(data),10)
print(sampler)
sampler=np.random.permutation(len(data))[:10]
print(sampler)
data.take(sampler)
data.loc[data['质量等级']=='优',:]
[1346 1122 1766 2154 1147 1593 1761   96   47   73]
[1883  326   43 1627 1750 1440  993 1469 1892  865]
日期AQI质量等级PM2.5PM10SO2CONO2O3季度等级
72014-01-0827.015.025.013.00.521.053.02014一季度一级优
82014-01-0946.027.046.019.00.835.053.02014一季度一级优
112014-01-1247.027.047.027.00.739.059.02014一季度一级优
192014-01-2035.08.035.06.00.315.065.02014一季度一级优
202014-01-2126.018.025.027.00.734.050.02014一季度一级优
.......................................
21222019-10-2530.08.020.02.00.424.055.02019四季度一级优
21312019-11-0348.033.048.03.00.634.033.02019四季度一级优
21352019-11-0747.024.047.03.00.537.044.02019四季度一级优
21522019-11-2430.07.030.03.00.211.058.02019四季度一级优
21532019-11-2540.013.030.03.00.432.029.02019四季度一级优

387 rows × 12 columns

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皖山文武

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值