04Pandas 数据处理基础

数据类型

Pandas 的数据类型主要有以下几种,它们分别是:Series(一维数组),DataFrame(二维数组),Panel(三维数组),Panel4D(四维数组),PanelND(更多维数组)。其中 Series 和 DataFrame 应用的最为广泛,几乎占据了使用频率 90% 以上。
Series
其可以储存整数、浮点数、字符串等类型的数据。Series 基本结构如下:

pandas.Series(data=None, index=None)

data 可以是字典,或者NumPy 里的 ndarray 对象等。index 是数据索引,索引是 Pandas 数据结构中的一大特性,它主要的功能是帮助我们更快速地定位数据。
基于 Python 字典新建一个示例 Series。

%matplotlib inline
import pandas as pd

s = pd.Series({'a': 10, 'b': 20, 'c': 30})
s

该 Series 的数据值是 10, 20, 30,索引为 a, b, c,数据值的类型默认识别为 int64。可以通过 type 来确认 s 的类型。

type(s)

Series 则可以基于 NumPy 中的一维数据转换。

import numpy as np

s = pd.Series(np.random.randn(5))
s

最终得到的 Series 索引默认从 0 开始,而数值类型为 float64。
DataFrame
DataFrame 是 Pandas 中最为常见、最重要且使用频率最高的数据结构。DataFrame 和平常的电子表格或 SQL 表结构相似。你可以把 DataFrame 看成是 Series 的扩展类型,它仿佛是由多个 Series 拼合而成。它和 Series 的直观区别在于,数据不但具有行索引,且具有列索引。

image.png

DataFrame 基本结构如下:

pandas.DataFrame(data=None, index=None, columns=None)

DataFrame 可以由以下多个类型的数据构建:
一维数组、列表、字典或者 Series 字典。
二维或者结构化的 numpy.ndarray。
一个 Series 或者另一个 DataFrame。

使用一个由 Series 组成的字典来构建 DataFrame。

df = pd.DataFrame({'one': pd.Series([1, 2, 3]),
                   'two': pd.Series([4, 5, 6])})
df

当不指定索引时,DataFrame 的索引同样是从 0 开始。我们也可以直接通过一个列表构成的字典来生成 DataFrame。

df = pd.DataFrame({'one': [1, 2, 3],
                   'two': [4, 5, 6]})
df

由带字典的列表生成 DataFrame。

df = pd.DataFrame([{'one': 1, 'two': 4},
                   {'one': 2, 'two': 5},
                   {'one': 3, 'two': 6}])
df

NumPy 的多维数组非常常用,同样可以基于二维数值来构建一个 DataFrame。

pd.DataFrame(np.random.randint(5, size=(2, 4)))

Series 实际上可以被初略看出是只有 1 列数据的 DataFrame。当然,这个说法不严谨,二者的核心区别仍然是 Series 没有列索引。可以观察如下所示由 NumPy 一维随机数组生成的 Series 和 DataFrame。

pd.Series(np.random.randint(5, size=(5,)))
pd.DataFrame(np.random.randint(5, size=(5,)))

数据读取

读取数据 CSV 文件的方法是 pandas.read_csv(),可以直接传入一个相对路径,或者是网络 URL。

df = pd.read_csv("https://labfile.oss.aliyuncs.com/courses/906/los_census.csv")
df

由于 CSV 存储时是一个二维的表格,那么 Pandas 会自动将其读取为 DataFrame 类型。
pd.read_ 前缀开始的方法还可以读取各式各样的数据文件,且支持连接数据库。
因为 Pandas 针对数据操作的全部方法都是基于 Pandas 支持的数据结构设计的。也就是说,只有 Series 或者 DataFrame 才能使用 Pandas 提供的方法和函数进行处理。所以,学习真正数据处理方法之前,我们需要将数据转换生成为 Series 或 DataFrame 类型。

基本操作

DataFrame 结构大致由 3 部分组成,它们分别是列名称、索引和数据。


image.png

有些时候,我们读取的文件很大。如果全部输出预览这些文件,既不美观,又很耗时。Pandas 提供了 head() 和 tail() 方法,它可以帮助我们只预览一小块数据。

df.head()  # 默认显示前 5 条
df.tail(7)  # 指定显示后 7 条

Pandas 还提供了统计和描述性方法,方便你从宏观的角度去了解数据集。describe() 相当于对数据集进行概览,会输出该数据集每一列数据的计数、最大值、最小值等。

df.describe()

Pandas 基于 NumPy 开发,所以任何时候你都可以通过 .values 将 DataFrame 转换为 NumPy 数组。

df.values

可以同时使用 Pandas 和 NumPy 提供的 API 对同一数据进行操作,并在二者之间进行随意转换。

df.index  # 查看索引
df.columns  # 查看列名
df.shape  # 查看形状

数据选择

在数据预处理过程中,我们往往会对数据集进行切分,只将需要的某些行、列,或者数据块保留下来,输出到下一个流程中去。这也就是所谓的数据选择,或者数据索引。
基于索引数字选择
当我们新建一个 DataFrame 之后,如果未自己指定行索引或者列对应的标签,那么 Pandas 会默认从 0 开始以数字的形式作为行索引,并以数据集的第一行作为列对应的标签。其实,这里的「列」也有数字索引,默认也是从 0 开始,只是未显示出来。
我们首先可以基于数字索引对数据集进行选择。这里用到的 Pandas 中的 .iloc 方法。该方法可以接受的类型有:
整数。例如:5
整数构成的列表或数组。例如:[1, 2, 3]
布尔数组。
可返回索引值的函数或参数。

首先,我们可以选择前 3 行数据。这和 Python 或者 NumPy 里面的切片很相似。

df.iloc[:3]

我们还可以选择特定的一行。

df.iloc[5]

df.iloc[] 的 [[行],[列]] 里面可以同时接受行和列的位置,如果你想要选择 1,3,5 行,可以这样做。

df.iloc[[1, 3, 5]]

我们要选择第 2-4 列。

df.iloc[:, 1:4]

这里选择 2-4 列,输入的却是 1:4。这和 Python 或者 NumPy 里面的切片操作非常相似。既然我们能定位行和列,那么只需要组合起来,我们就可以选择数据集中的任何数据了。
基于标签名称选择
除了根据数字索引选择,还可以直接根据标签对应的名称选择。为 df.loc[]
df.loc[] 可以接受的类型有:
单个标签。例如:2 或 'a',这里的 2 指的是标签而不是索引位置。
列表或数组包含的标签。例如:['A', 'B', 'C']。
切片对象。例如:'A':'E',注意这里和上面切片的不同之处,首尾都包含在内。
布尔数组。
可返回标签的函数或参数。

先选择前 3 行:

df.loc[0:2]

再选择 1,3,5 行:

df.loc[[0, 2, 4]]

然后,选择 2-4 列:

df.loc[:, 'Total Population':'Total Males']

最后,选择 1,3 行和 Median Age 后面的列:

df.loc[[0, 2], 'Median Age':]

数据删减

以 .drop 开头的方法都与数据删减有关。
DataFrame.drop 可以直接去掉数据集中指定的列和行。一般在使用时,我们指定 labels 标签参数,然后再通过 axis 指定按列或按行删除即可。当然,你也可以通过索引参数删除数据,具体查看官方文档。

df.drop(labels=['Median Age', 'Total Males'], axis=1)

DataFrame.drop_duplicates 则通常用于数据去重,即剔除数据集中的重复值。使用方法非常简单,指定去除重复值规则,以及 axis 按列还是按行去除即可。

df.drop_duplicates()

另一个用于数据删减的方法 DataFrame.dropna 也十分常用,其主要的用途是删除缺少值,即数据集中空缺的数据列或行。

df.dropna()

数据填充

在真实的生产环境中,我们需要处理的数据文件往往没有想象中的那么美好。其中,很大几率会遇到的情况就是缺失值。缺失值主要是指数据丢失的现象,也就是数据集中的某一块数据不存在。除此之外、存在但明显不正确的数据也被归为缺失值一类。例如,在一个时间序列数据集中,某一段数据突然发生了时间流错乱,那么这一小块数据就是毫无意义的,可以被归为缺失值。
检测缺失值
Pandas 为了更方便地检测缺失值,将不同类型数据的缺失均采用 NaN 标记。这里的 NaN 代表 Not a Number,它仅仅是作为一个标记。例外是,在时间序列里,时间戳的丢失采用 NaT 标记。
Pandas 中用于检测缺失值主要用到两个方法,分别是:isna()notna(),故名思意就是「是缺失值」和「不是缺失值」。默认会返回布尔值用于判断。

df = pd.DataFrame(np.random.rand(9, 5), columns=list('ABCDE'))
# 插入 T 列,并打上时间戳
df.insert(value=pd.Timestamp('2017-10-1'), loc=0, column='Time')
# 将 1, 3, 5 列的 1,3,5,7 行置为缺失值
df.iloc[[1, 3, 5, 7], [0, 2, 4]] = np.nan
# 将 2, 4, 6 列的 2,4,6,8 行置为缺失值
df.iloc[[2, 4, 6, 8], [1, 3, 5]] = np.nan
df

然后,通过 isna()notna() 中的一个即可确定数据集中的缺失值。

df.isna()

面对缺失值一般就是填充和剔除两项操作。填充和清除都是两个极端。如果你感觉有必要保留缺失值所在的列或行,那么就需要对缺失值进行填充。如果没有必要保留,就可以选择清除缺失值。
我们可以用相同的标量值替换 NaN,比如用 0。

df.fillna(0)

除了直接填充值,我们还可以通过参数,将缺失值前面或者后面的值填充给相应的缺失值。例如使用缺失值前面的值进行填充:

df.fillna(method='pad')

或者是后面的值:

df.fillna(method='bfill')

如果存在连续的缺失值是怎样的情况呢?试一试。首先,我们将数据集的第 2,4 ,6 列的第 3,5 行也置为缺失值。

df.iloc[[3, 5], [1, 3, 5]] = np.nan

然后来正向填充:

df.fillna(method='pad')

可以看到,连续缺失值也是按照前序数值进行填充的,并且完全填充。这里,我们可以通过 limit= 参数设置连续填充的限制数量。

df.fillna(method='pad', limit=1)  # 最多填充一项

除了上面的填充方式,还可以通过 Pandas 自带的求平均值方法等来填充特定列或行。

df.fillna(df.mean()['C':'E'])

插值填充
插值是数值分析中一种方法。简而言之,就是借助于一个函数(线性或非线性),再根据已知数据去求解未知数据的值。插值在数据领域非常常见,它的好处在于,可以尽量去还原数据本身的样子。
我们可以通过 interpolate() 方法完成线性插值。当然,其他一些插值算法可以阅读官方文档了解。

# 生成一个 DataFrame
df = pd.DataFrame({'A': [1.1, 2.2, np.nan, 4.5, 5.7, 6.9],
                   'B': [.21, np.nan, np.nan, 3.1, 11.7, 13.2]})
df

对于上面存在的缺失值,如果通过前后值,或者平均值来填充是不太能反映出趋势的。这时候,插值最好使。我们用默认的线性插值试一试。

df_interpolate = df.interpolate()
df_interpolate

下图展示了插值后的数据,明显看出插值结果符合数据的变化趋势。如果按照前后数据顺序填充,则无法做到这一点。

image.png

对于 interpolate() 支持的插值算法,也就是 method=。下面给出几条选择的建议:
如果你的数据增长速率越来越快,可以选择 method='quadratic'二次插值。
如果数据集呈现出累计分布的样子,推荐选择 method='pchip'。
如果需要填补缺省值,以平滑绘图为目标,推荐选择 method='akima'。

数据可视化

当我们的数据是以 DataFrame 格式呈现时,可以直接使用 Pandas 提供的 DataFrame.plot 方法调用 Matplotlib 接口绘制常见的图形。
例如,我们使用上面插值后的数据 df_interpolate 绘制线形图。

df_interpolate.plot()

其他样式的图形也很简单,指定 kind= 参数即可。

df_interpolate.plot(kind='bar')

其他用法

* 数据计算*,例如:DataFrame.add 等。
* 数据聚合*,例如:DataFrame.groupby 等。
* 统计分析*,例如:DataFrame.abs 等。
* 时间序列*,例如:DataFrame.shift 等。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容