共计 10698 个字符,预计需要花费 27 分钟才能阅读完成。
上一篇咱们理解了 NumPy 的基本功能,本篇引入一个新的 python 数据处理库——pandas。
NumPy 更适宜解决对立的数值数组数据。Pandas 是基于 NumPy 数组构建的,专门解决表格和混淆数据。接下来,让咱们来理解一下 pandas 的根本应用吧。
首先让咱们导入 pandas 库:
import pandas as pd
import numpy as np # 后续也会应用到 numpy,在此先导入进来
3.1 pandas 的数据结构
pandas 有两个根本的数据结构:Series 和 DataFrame。
3.1.1 Series
咱们能够把 Series 了解为带有索引的一维 np 数组。让咱们创立进去比照一下:
in: obj = pd.Series([4, 7, -5, 3]) # 能够将一个 list 转换为 Series
obj
out: 0 4
1 7
2 -5
3 3
dtype: int64
in: np_obj = np.array([4, 7, -5, 3])
np_obj
out: array([4, 7, -5, 3])
能够看到,用 pd.Series() 创立的 Series 比 np.array() 创立的 ndarray 多了索引值——0, 1, 2, 3。
Series 的两个属性也能够在此印证这个事实:
in: obj.values # Series 的值:的确是个 np 数组
out: array([4, 7, -5, 3], dtype=int64)
in: obj.index # Series 的索引(index)out: RangeIndex(start=0, stop=4, step=1)
如果不想要 pandas 主动生成的索引,也能够指定:
in: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
obj2
out: d 4
b 7
a -5
c 3
dtype: int64
如何从 Series 当选取出一个值或一组值呢?
in: obj2['a']
out: -5
in: obj2[['a', 'b']] # 取出一组值时,留神方括号的应用
out: a -5
b 7
dtype: int64 # 取出一组值时,取出的也是一个 Series
Series 如何运算呢?它能够像 NumPy 那样运算。
obj2[obj2 > 2] # 用布尔值索引选取
obj2 * 2 # 元素级乘法运算
np.exp(obj2)
Series 有索引也有值,就像字典的“键 - 值”一样。Series 的一些用法也像字典一样:
in: "a" in obj2 # 像是在查看某个值是否属于字典的键
out: True
方才在创立 Series 时,咱们是将一个 list 转换为 Series。其实,也能够将一个 dict 转换为 Series(此时,字典的键就是 Series 的索引):
in: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
obj3
out: Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
在曾经有索引的状况下,如果再指定索引,会产生什么呢?
in: states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
obj4
out: California NaN # 原索引被新索引代替了,新索引中的 California 找不到对应的原索引,因而赋空值 NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64 # 新索引中没有 Utah 了,此处能够看到也没有呈现 Utah 的数据
咱们在上一个代码块中看到了缺失值的存在。咱们在解决数据时经常碰到有缺失数据的状况。那么如何检测数据中是否存在缺失数据呢?
in: pd.isnull(obj4) # 和上面成果一样
obj4.isnull() # 和下面成果一样
out: California True
Ohio False
Oregon False
Texas False
dtype: bool
in: pd.notnull(obj4) # 也能够检测非空值
out: California False
Ohio True
Oregon True
Texas True
dtype: bool
最初,再介绍一个 Series 的重要性能:依据运算的索引标签主动对齐数据。
in: obj3 + obj4 # 两个 Series 的索引存在不同,而加法运算主动将能对应上的索引值相加
out: California NaN # 而对应不上的值间接赋空值
Ohio 70000.0
Oregon 32000.0
Texas 142000.0
Utah NaN # 对应不上,赋空值,不管其是否在某一个 Series 中有值
dtype: float64
3.1.2 DataFrame
DataFrame 是一个表格型数据结构,既有行索引也有列索引。一列的值类型是雷同的,但不同列能够有不同的值类型。
首先让咱们创立一个 DataFrame。
in: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]} # 建设一个值为等长 list 的字典
frame = pd.DataFrame(data) # 将上述字典转为 DataFrame
frame
out: state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2 # 能够看到这个 DataFrame 应用了字典的键作为列索引,行索引是主动创立的
咱们时常会解决很大数据量的 DataFrame,当想查看这个表格构造时,并不想将整个表格都输入。咱们能够用 head() 查看一个 DataFrame 的前几行:
in: frame.head()
out: state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9 # 默认输入前 5 行
in: frame.head(3) # 能够设置输入的行数
out: state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
那如何取出一列呢?
in: frame['state'] # 像取字典的值那样就能够,咱们取出了一个 Series
frame.state # 这样也能够,成果和上一行是一样的,因为 DataFrame 有一个 name 属性
out: 0 Ohio
1 Ohio
2 Ohio
3 Nevada
4 Nevada
5 Nevada
Name: state, dtype: object
在创立 DataFrame 时,咱们还能够指定列(字段)的排列程序,让表格按咱们想要的顺序排列:
in: pd.DataFrame(data, columns=['year', 'state', 'pop'])
out: year state pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9
5 2003 Nevada 3.2
但如果咱们指定了匹配不上原数据的字段名,那么会产生缺失值:
in: frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five', 'six'])
frame2
out: year state pop debt # 能够看到 debt 列都是缺失值
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 NaN
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN
six 2003 Nevada 3.2 NaN
缺失值的这列数据该如何解决呢?
in: frame2['debt'] = 12 # 能够间接赋一个整数,这会被播送到整列
out: year state pop debt
one 2000 Ohio 1.5 12
two 2001 Ohio 1.7 12
three 2002 Ohio 3.6 12
four 2001 Nevada 2.4 12
five 2002 Nevada 2.9 12
six 2003 Nevada 3.2 12
in: frame2['debt'] = np.arange(6.) # 也能够退出一个与表格长度等长的序列
out: year state pop debt
one 2000 Ohio 1.5 0.0
two 2001 Ohio 1.7 1.0
three 2002 Ohio 3.6 2.0
four 2001 Nevada 2.4 3.0
five 2002 Nevada 2.9 4.0
six 2003 Nevada 3.2 5.0
in: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val # 如果将一个带有能匹配上的索引的 Series 赋值给缺失值列的话
frame2
out: year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
six 2003 Nevada 3.2 NaN # 能够看到匹配上索引的赋值了,没匹配上的仍是缺失值
如果咱们不想要 debt 这列了,如何删除呢?
in: del frame2['debt']
frame2.columns # 来查看一下还有哪几列
out: Index(['year', 'state', 'pop'], dtype='object')
3.2 pandas 基本功能
3.2.1 插入新数据:应用“从新索引”
有时咱们心愿往 Series 或 DataFrame 中插入新数据,这能够用从新索引的形式实现。对于 Series 而言:
in: obj = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj
out: 0 blue
2 purple
4 yellow
dtype: object
in: obj.reindex(range(6)) # 咱们通过扭转并笼罩原来的索引,达到插入新行的目标
out: 0 blue
1 NaN
2 purple
3 NaN
4 yellow
5 NaN
dtype: object
in: obj.reindex(range(6),method='ffill') # 指定 method 参数,还能够实现诸如插值解决的操作
out: 0 blue
1 blue # 不再是空值了,而是依照前一个值来填充
2 purple
3 purple
4 yellow
5 yellow
dtype: object
DataFrame 有两个索引,因而咱们能够通过从新索引向表格中插入行和列。
in: frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
index=['a', 'c', 'd'],
columns=['Ohio', 'Texas', 'California'])
frame
out: Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
in: frame2 = frame.reindex(['a', 'b', 'c', 'd']) # 默认从新索引行,用一个 list 表述新的索引序列。frame2
out: Ohio Texas California # 能够看到匹配上索引的行还是原来的数据,没匹配上的赋空值
a 0.0 1.0 2.0
b NaN NaN NaN
c 3.0 4.0 5.0
d 6.0 7.0 8.0
in: states = ['Texas', 'Utah', 'California']
frame2.reindex(columns=states) # 指明 columns 参数,即可从新索引列
out: Texas Utah California # 原数据中,没匹配索引的列被删除了
a 1.0 NaN 2.0
b NaN NaN NaN
c 4.0 NaN 5.0
d 7.0 NaN 8.0
3.2.2 抛弃指定轴上的项
咱们能够指定索引,来抛弃指定轴上的项。
对 Series 来说,只有一个索引,能够这么做:
in: obj = pd.Series(np.arange(5.))
obj.drop([1, 3])
out: 0 0.0
2 2.0
4 4.0
dtype: float64
对于 DataFrame 来说,索引有两个,drop() 默认对行删除。留神,drop() 的删除是一个视图,并不是间接在原数据上操作的。如果想间接删除的话,须要应用 del。
in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
data.drop('Ohio')
out: one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
in: data.drop(['one', 'two'], axis=1) # 指定 axis=1 能够对列进行删除
out: three four
Ohio 2 3
Colorado 6 7
Utah 10 11
New York 14 15
在实际操作中,我通常设置横轴的索引,而是用默认主动创立的序号索引(0, 1, 2, …)。
这样的话,drop() 后,index 就会有完好。
in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
columns=['one', 'two', 'three', 'four'])
data = data.drop(index=(data.loc[(data['one']>5) & (data['one']<10)]).index)
data
out: one two three four
0 0 1 2 3
1 4 5 6 7
3 12 13 14 15 # 缺失了 index = 2 的行
这时,咱们须要从新设置 index:
in: data = data.reset_index(drop=True) # 指定 drop=True 能够不保留原来的 index
out: one two three four
0 0 1 2 3
1 4 5 6 7
2 12 13 14 15
3.2.3 选取 Series 中的一些数据
能够像字典那样,写出键,就能够选取:
in: obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
obj
out: a 0.0
b 1.0
c 2.0
d 3.0
dtype: float64
in: obj['b']
obj[1] # 即便咱们设置了 index 的名称,依然能够用默认的数字 index 进行索引,和上一行产生同样的成果
out: 1.0
in: obj[0:2] # 能够利用切片选取间断的几个值
out: a 0.0
b 1.0
dtype: float64
in: obj[[0, 2]] # 也能够选取不间断的几个值
out: a 0.0
c 2.0
dtype: float64
in: obj[obj<2] # 布尔值也能够索引,像 ndarray 一样
out: a 0.0
b 1.0
dtype: float64
这里用切片选取时,有个有意思的特点:用一般的 python 切片失去的数据是不蕴含末端的,但用咱们设置的 index 标签来切片,就会蕴含末端数据。
in: obj['a':'c']
out: a 0.0
b 1.0
c 2.0
dtype: float64 # 能够比照下面的 obj[0:2]
3.2.4 选取 DataFrame 中的一些数据
能够间接用相似下面的办法选取:
in: data
out: one two three four
0 0 1 2 3
1 4 5 6 7
2 12 13 14 15
in: data[['one', 'three']] # 选取指定的两列数据
out: one three
0 0 2
1 4 6
2 12 14
in: data[:2] # 利用切片按行选取
out: one two three four
0 0 1 2 3
1 4 5 6 7
罕用的选取办法是用布尔值选取,以达到按条件选取的目标:
in: data['three'] > 5 # 这样能够返回一个布尔值序列
out: 0 False
1 True
2 True
Name: three, dtype: bool
in: data[data['three'] > 5] # 用这样的布尔值选取,咱们就能够实现按条件选取(选出 three 列中值 > 5 的行)out: one two three four
1 4 5 6 7
2 12 13 14 15
此外,另外一种常见的选取形式是通过轴标签(loc)或整数索引(iloc)来选取:
in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
data
out: one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
in: data.loc['Utah', ['one', 'four']] # 指定行和列
data.iloc[2,[0,3]] # 和上式达到雷同成果
out: one 8
four 11
Name: Utah, dtype: int32
in: data.loc[:'Utah', 'two'] # loc 和 iloc 也能够用切片索引
out: Ohio 1
Colorado 5
Utah 9
Name: two, dtype: int32
in: data.iloc[:, :3][data.three > 5] # 还能够加条件,通过在最初加一个方括号蕴含的布尔值序列的形式
out: one two three
Colorado 4 5 6
Utah 8 9 10
New York 12 13 14
3.2.5 算数运算和数据对齐
pandas 的一个重要个性是,它反对对两个索引不同的对象做运算,并进行数据对齐——运算时,索引匹配上的值会进行运算,索引不匹配的值会间接赋值为空。
in: s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
s1 + s2
out: a 5.2
c 1.1
d NaN
e 0.0
f NaN
g NaN # 即便 s2 中有值,但 s1 中不存在这个索引,运算后该索引的值仍为空
dtype: float64
DataFrame 有两个索引,数据对齐会同时产生在行和列上。
in: df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)),
columns=list('bcd'),
index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
df1 + df2
out: b c d e
Colorado NaN NaN NaN NaN
Ohio 3.0 NaN 6.0 NaN
Oregon NaN NaN NaN NaN
Texas 9.0 NaN 12.0 NaN
Utah NaN NaN NaN NaN
in: df1.add(df2, fill_value=0) # 如果不想要空值,能够应用 add(),并指明 fill_value=0
out: b c d e
Colorado 6.0 7.0 8.0 NaN # 能够看到还是存在空值,这是因为当两个表中都不存在值时不能填充
Ohio 3.0 1.0 6.0 5.0
Oregon 9.0 NaN 10.0 11.0
Texas 9.0 4.0 12.0 8.0
Utah 0.0 NaN 1.0 2.0
如果是 DataFrame 和 Series 进行运算,运算会被逐行播送:
in: frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = frame.iloc[0]
frame
series
out: b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
b 0.0
d 1.0
e 2.0
in: frame - series # 表格从第一行开始减 series,始终向下播送,减到最初一行
out: b d e
Utah 0.0 0.0 0.0
Ohio 3.0 3.0 3.0
Texas 6.0 6.0 6.0
Oregon 9.0 9.0 9.0
3.2.6 函数利用
numpy 的 ufuncs(元素级数组办法)也可用于操作 pandas 对象。而 pandas 对象也内置了许多罕用的统计办法,能够间接调用。
in: frame = pd.DataFrame(np.random.randn(4, 3),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
frame
out: b d e
Utah -0.661018 0.130761 0.508856
Ohio 0.174303 -1.288930 -0.384396
Texas -0.523870 -0.657847 -0.822806
Oregon 0.969613 0.894881 -0.623135
in: np.abs(frame)
frame.abs() # DataFrame 曾经内置了 abs() 办法,该行和上一行会产生雷同的成果
out: Utah 0.661018 0.130761 0.508856
Ohio 0.174303 1.288930 0.384396
Texas 0.523870 0.657847 0.822806
Oregon 0.969613 0.894881 0.623135
简单的计算能够应用 lambda 函数,并用 apply() 将函数利用到由各列或行所造成的一维数组上。
in: frame.apply(lambda x: x.max() - x.min()) # 对每列进行函数运算
out: b 1.630631
d 2.183811
e 1.331663
dtype: float64
in: frame.apply(lambda x: x.max() - x.min(), axis=1) # 匹配列,对每行进行函数运算
out: Utah 1.169874
Ohio 1.463233
Texas 0.298937
Oregon 1.592748
dtype: float64
3.2.7 排序
对于 DataFrame 来说,排序能够按行索引排,也能够按列索引排。
in: frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['three', 'one'],
columns=['d', 'a', 'b', 'c'])
frame
out: d a b c
three 0 1 2 3
one 4 5 6 7
in: frame.sort_index() # 按行排
out: d a b c
one 4 5 6 7
three 0 1 2 3
in: frame.sort_index(axis=1, ascending=False) # 按列排,降序排
out: d c b a
three 0 3 2 1
one 4 7 6 5
此外,还能够按值排序:
in: frame.sort_values(by='a',ascending=False) # 也能够按值排列
out: d a b c
one 4 5 6 7
three 0 1 2 3
in: me.sort_values(by=['a','b']) # 按多个列的值来排
out: d a b c
three 0 1 2 3
one 4 5 6 7
5.3 描述性统计
先创立一个 DataFrame 用于举例:
in: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5],[np.nan, np.nan], [0.75, -1.3]],
index=['a', 'b', 'c', 'd'],
columns=['one', 'two'])
df
out: one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3
描述性统计的方向默认是以列为单位,统计行数据的:
in: df.sum()
out: one 9.25
two -5.80
dtype: float64
in: df.mean(axis=1) # 也能够按行统计
out: a 1.400 # 包含一个空值时,空值被跳过了
b 1.300
c NaN # 都是空值时,返回的也是空值
d -0.275
dtype: float64
能够间接应用 describe() 返回描述性统计后果:
in: df.describe()
out: one two
count 3.000000 2.000000
mean 3.083333 -2.900000
std 3.493685 2.262742
min 0.750000 -4.500000
25% 1.075000 -3.700000
50% 1.400000 -2.900000
75% 4.250000 -2.100000
max 7.100000 -1.300000
还能够计算相关系数:
in: df.corr() # 默认为 pearson 相关系数
out: one two
one 1.0 -1.0
two -1.0 1.0
还有波及到惟一值、值计数以及成员资格的统计:
in: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
obj
out: 0 c
1 a
2 d
3 a
4 a
5 b
6 b
7 c
8 c
dtype: object
in: obj.unique() # 返回一个惟一值数组
out: array(['c', 'a', 'd', 'b'], dtype=object)
in: obj.value_counts() # 计算一个值呈现的频率
out: a 3
c 3
b 2
d 1
dtype: int64
in: obj.isin(['b', 'c']) # 是否在 [] 中
out: 0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
注:转载请注明出处。
本文属于《利用 Python 进行数据分析》读书笔记系列:
- 利用 Python 进行数据分析 —— 1 数据结构、函数和文件
- 利用 Python 进行数据分析 —— 2 NumPy 根底