专栏首页MeteoAI数据处理利器pandas入门

数据处理利器pandas入门

想入门 Pandas,那么首先需要了解Pandas中的数据结构。因为Pandas中数据操作依赖于数据结构对象。Pandas中最常用的数据结构是 Series DataFrame。这里可以将 Series和 DataFrame分别看作一维数组和二维数组。

Series

Series是一维标签数组,其可以存储任何数据类型,包括整数,浮点数,字符串等等。所谓标签数组,这里的标签即是指Series的索引。

import pandas as pd

s=pd.Series([5,4,3,2,1], index=['a', 'c', 'e', 3, 1])

⚠️ 创建时给定了一个列表: [5,4,3,2,1],并且通过 index 参数用于指定索引。如果仅给定列表,不指定index参数,默认索引为从0开始的数字。注意:索引标签为字符串和整数的混合类型。记住不要使用浮点数作为索引,并且尽量避免使用混合类型索引

除了使用传入列表或numpy数组之外,也可以通过字典的方式创建:

s=pd.Series({'a':5, 'b':4, 'c':3, 'd':2, 'e':1})

DataFrame

DataFrame是一种表格型数据结构,可以看作是具有行列标签的二维数组。每列可以是不同类型的数据,比如数值,字符串,逻辑值等。

DataFrame的创建有多种方式,比较常用的是通过字典的方式创建,此外,还可以给定数组,通过指定columns和index参数创建:

d1=pd.DataFrame({'one':[1,3,5], 'two':[2,4,6]})  # 不指定索引,默认仍从0开始。
d2=pd.DataFrame([[1,2],[3,4],[5,6]], columns=['one', 'two'], index=['a', 'b', 'c'])

简单的介绍了Series和DataFrame这两种数据结构之后,我们以全国空气质量历史数据(http://beijingair.sinaapp.com)为例,通过实际的数据处理来介绍一下常用的操作。

数据为逗号分隔的csv格式数据,数据存储如下:

数据存储形式

数据存储以逗号作为分隔符,列为: date, hour, type, 1001A, 1002A…,date和hour为时间信息列,type为对应的要素,其余的列均为站点名称。

读取数据
data = pd.read_csv('china_sites_20170101.csv', sep=',')

由于文件中存储了多行多列数据,因此,完全读取之后 data 为 DataFrame 类型。

探索性分析

查看DataFrame数据信息

data.shape 
data.ndim  # 获取数据的维度信息
data.index  # 获取索引
data.columns #获取列名

查看数据行列对象信息

data.info() 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 285 entries, 0 to 284
Columns: 1500 entries, date to 2846A
dtypes: float64(1497), int64(2), object(1)
memory usage: 3.3+ MB

上述数据中包含285行,1500列,其中type列为object,date和hour列为int64类型,其余列均为float64类型。memory表明数据总共占用了约3.3M内存。

数据统计信息

获取每一列的统计相关数据,count表示一列的行数,mean表示均值,std为标准差,minmax表示最小值和最大值,25%50%75%分别表示1/4位数,中位数和3/4位数。

data.describe()

⚠️ describte 仅统计数值型列的统计数据,对于object列,会直接忽略。 这里还要注意一点:由于type列对应了不同的空气质量要素,而不同的空气质量要素具有不同的取值范围,因此在使用describe查看统计信息时,应针对不同的要素进行,这样才有具体意义,才能看出每个要素的值分布,以及确定是否存在异常值。

简单的数据查看

head 方法可以查看整个数据集的前几行信息,默认是前5行,但可以指定参数选择,与 head 对应的是 tail 可以查看对应的从末尾开始的默认5行数据。这两个方法类似linux中的 head 和 tail 命令。

data.head()
data.tail()

数据选择

简单的了解了上述信息之后,我们对不同的空气质量要素进行操作时就要涉及到数据的选择。

⚠️ Pandas官方提示:以下切片形式操作在简单的交互式数据分析时是非常友好的,但是如果应用于生产环境尽量使用优化后的一些方法:.at.iat.loc.iloc.ix等。

Pandas主要有两种数据查询选择操作:

  • 基于标签的查询
  • 基于整数的位置索引查询

Pandas在选择列时,无需使用 date[:, columns] 的形式,先使用 : 选择所有行,再指定 columns 列名称。选择1001A站点的数据。

data[['date', 'hour', 'type', '1001A']]  # 获取四列所有行数据,仍为DataFrame
data[0:5] # 选择所有列前5行数据,仅包括索引0-4行

超纲题:由于数据中包含了时间信息列(date和hour),为了方便操作,我们可以使用以下命令将时间列设置为索引。

date_index = pd.to_datetime(data.date.apply(lambda x: str(x)) + data.hour.apply(lambda x: '%02d'%x), format='%Y%m%d%H')
data.index = date_index
# data.drop(['date', 'hour], axis=1, inplace=True)  ## 删除 date和hour列,inplace选项直接针对原DataFrame操作

⚠️ 'date' 和'hour'都是整数,需要将这两列转换成字符串之后连接起来,连接的时候注意 date 形式是 '%Y%m%d',而 hour 转换的时候要转换成 '0d'的形式,防止数字为0-9时为单字符,然后使用 pd.to_datetime 函数转换,需要指定 format 参数,否则转换会出错。

  • 基于标签的查询 .loc .loc 主要基于标签进行数据选择,此外还可以使用逻辑数组。当所选择的项不存在时会诱发异常。
    • 单个标签
    data.loc[:, '1001A'] # 返回Series 注意 : 行索引,如果仅给定 data.loc['1001A'] 会出错
    • 标签数组
    data.loc[:, ['1001A', '1006A', '2706A']]
    • 标签切片对象
    data.loc['2017-01-01 00:00:00':'2017-01-01 06:00:00', '1001A':'1005A']  # 针对行和列均进行切片
    # data.loc[0:5, '1001A':'1005A] # 会出错

    ⚠️ 由于行索引已经转换为时间,因此此处不能使用 整数 索引。因为 .loc 只能用于行列标签索引,整数位置索引需要使用 .iloc

    针对时间索引,可以直接使用时间的方式来查询,对于包含时间信息的数据检索来说非常方便

    • 逻辑数组
data.loc[data['type'] == 'AQI']  # 选择所有站点的AQI数据
  • 可调用函数 即可以传入函数作给 .loc ,但函数返回结果应是有效的索引,比如标签或者逻辑数组
def test(data, column, name):
    return data[columns] = name

data.loc[test(data, 'type', 'AQI')]
  • 基于整数的位置索引查询 .iloc .iloc 主要是基于整数的位置索引,也可以使用逻辑数组的方式。如果索引越界会诱发IndexError错误,但切片索引允许索引越界。
    • 单个整数
    data.iloc[0]  # 返回第1行的所有列,结果为Series
    
    • 整数数组
    data.iloc[[0,2,4,6,8], [0,1,2,3]]
    • 整数切片
    data.iloc[0:10, 0:4]
    
    • 逻辑数组
    data.iloc[(data.type == 'AQI').values]  # 获取所有站点的AQI数据 

    ⚠️ 由于 data.type == 'AQI' 返回的是 Series,我们只需要获取其中的值,因此指定 .values 属性。又超纲了==。

    • 可调用函数 传入可调用函数给 .iloc,函数返回值应为:单个整数,整数数组,数组切片或者逻辑数组。

上述两种数据选择虽是基于DataFrame,但Series也支持同样的操作,以1001A 站点的AQI数据为例:

s = data.loc[data.type == 'AQI']['1001A']

由于Series只有一列,因此只需要对行进行索引操作即可,也支持基于标签和整数的位置索引方式。

s.loc['2017-01-01 06:00:00':'2017-01-01 12:00:00']
s.iloc[2:10]

重建索引

通过观察1001A站点的Series数据可以发现:某些时刻的数据缺失。对于时间序列数据而言,数据的缺失可能会导致分析时出现问题。因为,我们需要补齐所有时刻。

from datetime import datetime

date_new = pd.date_range(datetime(2017, 1, 1, 0), datetime(2017, 1, 1, 23), freq='1h')

data.reindex(date_new)  # 重新索引

缺失值

补齐所有时刻之后,我们可以查看一下数据的缺失情况:

data.isnull() # 返回逻辑DataFrame,缺失值为True,否则为False
# data.isnull().sum()  # 统计每个站点每个要素的总的缺失数

data.isnull().sum() 利用了逻辑运算时:True被视为1,False被视为0的方式。与 data.isnull() 相反的是 data.notnull() ,是缺失值为False,否则为True。如果想丢弃缺失值,可使用 .dropna 方法,即 data.dropna()

但对于时间序列而言,一般不选择直接丢弃缺失时刻,否则可能造成时间缺失,破坏连续性。因此,可以选择补齐数据。

data.fillna() # fillna 使用给定值和方法进行数据填补
data.interpolate() # interpolate 可以通过线性插值等方法通过插值补齐数据

统计计算

Pandas中Series和DataFrame均包含一些常用的统计计算方法,比如:

data.mean()  # 计算平均值
data.sum()   # 求和
data.std()   # 计算标准差
data.median() # 获取中位数

上述数据是2017年1月1日全国所有观测站观测的常规要素逐小时数据,上面几个统计命令均是对每个站点每个要素进行计算。此外,也可以对单个站点分时刻计算,比如:

data['1001A'].resample('6h').mean() # 针对1001A站点,进行每6小时求平均

.resample 是重采样方法,其返回一个对象,然后对此对象执行 .mean 求均值方法。 .mean 也可以换为 .sum.std 等方法。对于时间跨度比较长的数据,也可以求逐日平均,逐月平均等等DataFrame.resmaple('1d').mean(), DataFrame.resample('2m').mean()

对行或列应用函数: .apply

上面在创建时间索引时便利用了.apply 方法,对date 和 hour列分别进行了数据类型的转换,然后将两个字符串进行了连接,转换为时间。

pd.to_datetime(data.date.apply(lambda x: str(x)) + data.hour.apply(lambda x: '%02d'%x), format='%Y%m%d%H')

字符串函数

Series中提供了大量的字符串函数,可以对字符串类型的数据进行常规操作。比如想替换字符串,或者转换字符串大小写等等。

data.type.str.replace('PM2.5', 'PM2_5') # 或 data.type.replace('PM2.5', 'PM2_5')
data.type.str.lower()

轴转换

目前的数据存储形式是:站点作为列,每个站点的空气质量要素通过 type 列单独给定。有时候这种存储形式并不方便,我们想要为以下形式:

即获取每个站点时,可以直接获取当前站点的所有要素数据,而且时间索引也按照单个时刻排列,索引不会出现重复值,而之前的存储形式索引会出现重复。索引重复会使得某些操作出错。

我们可以通过 .pivot_table 进行转换:

data.pivot_table(index=data.index, columns=['type'])

索引仍为 data 的原索引,但对 type 列进行旋转。旋转完成之后返回的DataFrame的列为 MultiIndex。而关于 MultiIndex 的查询操作属于高级主题。

对于 MultiIndex 的操作,同样可以使用.loc 方法,并借助 .IndexSlice 进行索引。

索引切片: 可以理解成 idx 将 MultiIndex 视为一个新的 DataFrame,然后将上层索引视为行,下层索引视为列,以此来进行数据的查询。

idx = pd.IndexSlice

sub=data.loc[:, idx['1001A', ['AQI', 'PM10', 'PM2.5']]]

data.loc[:, idx['1001A', ['AQI', 'PM10', 'PM2.5']]]: 表示 data 中的所有行,idx['1001A', ['AQI', 'PM10', 'PM2.5']] 表示 data 中的指定列,如果将 idx 看作新的 DataFrame,那么'1001A'则是 idx 中的行,['AQI', 'PM10', 'PM2.5'] 则是 idx 中的列。

上述操作返回的列仍然是 MultiIndex,因为此时只有一个站点了,我们可以使用 .xs 方法将列从MultiIndex转换为Index

sub.xs('1001A', axis=1)

简单绘图

Python可视化工具概览 中我们提到过数据处理和可视化一条龙服务的Pandas,Pandas不仅可以进行数据处理工作,而且其还封装了一些绘图方法。首先导入 matplotlibseaborn,这是为了能够较好的显示图形比例。

import matplotlib.pyplot as plt
import seaborn as sns

sns.set_context('talk', font_scale=1.3)

这里我们选择单个站点数据进行画图:

sub = data.loc[:, idx['1001A', :]].xs('1001A', axis=1)

fig, ax = plt.subplots(figsize=(16, 9))
sub.plot.box(ax=ax)

箱线图

上图可以看出:不同的要素其值所在范围是不同的,在探索性分析时应分开分析。

除了箱线图之外,Pandas还可以绘制折线图,条形图,饼图,密度分布等。这在数据分析时是比较方便的,但在图形美化或其他图形绘制还需要借助其他工具,比如统计绘图Seaborn更胜一筹。看这里 >>> Python简单高效的可视化神器——Seaborn

后面会继续介绍关于pandas的更多技巧和高级操作。

数据: https://pan.baidu.com/s/1whja5oxfMniOGZP3WrBC_A

- End -

本文由MeteoAI原创首发,未经允许禁止转载!

本文分享自微信公众号 - MeteoAI(meteoai),作者:bugsuse

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用Python处理NetCDF格式文件

    NetCDF(Network Common Data Form)是一种科学二进制数据格式,由UCAR负责开发和维护netCDF软件,主要用于存储多维科学数据。在...

    zhangqibot
  • Metpy新版功能下载TLnP图设置

    用于天气绘图的Metpy包更新(0.8版本)了,他们要逐渐抛弃Python2.X,转到Python>=3.6的版本上。所以,之前(越2018年6月以前,0.7版...

    zhangqibot
  • Grib数据一键可视化

    GUI工具在进行数据处理和可视化方面相较于脚本语言的明显优势就是能够交互式的快速进行数据处理和可视化。

    zhangqibot
  • [半zz]迅雷笔试题

    用户1130771
  • 小顶堆Java实现

    参考文章: 漫谈经典排序算法:一、从简单选择排序到堆排序的深度解析 http://blog.csdn.net/touch_2011/article/detai...

    囚兔
  • SAP Spartacus里使用Observable访问Component数据

    在自定义Component的constructor里,无法直接访问通过构造函数参数注入的data数据:

    Jerry Wang
  • 【go】剑指offer:常见排序算法

    冒泡排序是比较简单的排序算法,它的关键思想是移动指针不断的进行两两比较,将最大的数字不断的进行更换位置,直至到最后,即完成一趟比较,都会寻找到最大的数字,且最大...

    陌无崖
  • go实现利用最大堆寻找最小k个数

    昨天分享了寻找最小k个数的算法是,那么有没有更为迅速的方法呢?今天就来分享关于如何使用最大堆进行解决。

    陌无崖
  • 通过空气质量指数AQI学习统计分析并进行预测(上)

    AQI(空气质量指数),用来衡量空气清洁或者污染的程度。值越小,表示空气质量越好。近年来,因为环境问题,空气质量也越来越受到人们的重视。

    朱小五
  • 使用 Python 实现几种常见的排序算法

    冒泡排序是最为基础的排序算法,其核心思想就是相邻元素两两比较,把较大的元素放到后面,在一轮比较完成之后,最大的元素就位于最后一个位置了,就好像是气泡,慢慢的浮出...

    周萝卜

扫码关注云+社区

领取腾讯云代金券