Pandas是一个开源的Python分析结构化数据的扩展程序库,基础是Numpy。可以从各种文件格式如CSV、JSON、SQL、Excel等导入数据,灵活高效地处理各种数据集,广泛应用在各种数据分析领域。
官网:pandas.pydata.org
源代码:github pandas
import numpy as np
import pandas as pd
1 Pandas对象基础
1.1 一维对象:Series
一维对象Series面向向量,其索引即为标签。可通过pd.Series()
创建Series对象
1.1.1 Series对象初始化
- 字典创建法:直接将Python字典转化为Series对象
dict_v = {'a': 0, 'b': 0.25, 'c': 0.5, 'd': 0.75, 'e': 1}
sr = pd.Series(dict_v)
print(sr)
a 0.00
b 0.25
c 0.50
d 0.75
e 1.00
dtype: float64
- 数组创建法:传入指定的列表、数组或张量,设置函数的参数:值
values
、标签index
。其中标签可省略,默认为从0开始的编号。
v = [1.5, 3, 4.5, 6, 7.5]
k = ['a', 'b', 'c', 'd', 'e']
sr = pd.Series(v, index=k)
print(sr)
a 1.5
b 3.0
c 4.5
d 6.0
e 7.5
dtype: float64
1.1.2 Series对象的属性
Series对象有两个属性:值values
、标签index
。
无论是用列表、NumPy数组还是PyTorch张量来创建对象,最终的值均为NumPy数组。因此调用values
即可将Pandas的Series对象退化为NumPy数组。
v = np.array([53, 64, 72, 82])
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series(v, index=k)
print(sr, '\n')
print(sr.values) # 查看values属性
print(sr.index) # 查看index属性
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
[53 64 72 82]
Index(['1 号', '2 号', '3 号', '4 号'], dtype='object')
1.2 二维对象:DataFrame
二维对象DataFrame面向矩阵,其不仅有行标签 ,还有列标签。可通过pd.DataFrame()
创建DataFrame对象
1.2.1 DataFrame对象初始化
- 字典创建法:基于多个Series对象,每一个Series就是一列数据。传入一个Python字典,其每个键值对为列标签与该列的Series对象。
v1 = [53, 64, 72, 82]
v2 = ['女', '男', '男', '女']
i = ['1 号', '2 号', '3 号', '4 号']
sr1 = pd.Series(v1, index=i)
sr2 = pd.Series(v2, index=i)
df = pd.DataFrame({'年龄': sr1, '性别': sr2})
print(df)
年龄 性别
1 号 53 女
2 号 64 男
3 号 72 男
4 号 82 女
若sr1和sr2的
index
不完全一致,则二维对象会取两者的并集,因此该对象就会产生一定数量的缺失值(NaN
)
- 数组创建法:传入指定的列表、数组或张量,设置函数的参数:值
values
、行标签index
、列标签columns
。其中行、列标签可省略,默认为从0开始的编号。
v = np.array([[53, '女'], [64, '男'], [72, '男'], [82, '女']]) # 数字自动转为字符串
i = ['1 号', '2 号', '3 号', '4 号']
c = ['年龄', '性别']
df = pd.DataFrame(v, index=i, columns=c)
print(df)
年龄 性别
1 号 53 女
2 号 64 男
3 号 72 男
4 号 82 女
1.2.2 DataFrame对象的属性
DataFrame对象有三个属性:值values
、行标签index
、列标签columns
。
与一维的Series对象同理,调用values
属性即可将Pandas的DataFrame对象退化为NumPy数组。
v = np.array([[53, '女'], [64, '男'], [72, '男'], [82, '女']]) # 数字自动转为字符串
i = ['1 号', '2 号', '3 号', '4 号']
c = ['年龄', '性别']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
arr = df.values
print(arr)
print(df.index)
print(df.columns, '\n')
arr = arr[:, 0].astype(int) # 提取0号列,并转化为整数型数组
print(arr)
年龄 性别
1 号 53 女
2 号 64 男
3 号 72 男
4 号 82 女
[['53' '女']
['64' '男']
['72' '男']
['82' '女']]
Index(['1 号', '2 号', '3 号', '4 号'], dtype='object')
Index(['年龄', '性别'], dtype='object')
[53 64 72 82]
2 对象的索引
Pandas的索引机制与Python列表、NumPy数组基本一致,存在以下两种索引:
- 显式索引
.loc[]
:使用Pandas对象提供的标签索引,与其他索引的区别为访问切片时包含右端点 - 隐式索引
.iloc[]
:使用数组本身自带的从0开始的索引
与NumPy数组一样,切片仅是视图,若想创建新变量,使用.copy()
方法即可。
2.1 一维对象的索引
索引一维对象时,可以省略loc
和iloc
,这样形式上就与NumPy数组一致。
v = [53, 64, 72, 82]
k = ['1号', '2号', '3号', '4号']
sr = pd.Series(v, index=k)
print(sr, '\n')
print(sr.loc['3号'], '\n') # sr.iloc[2]
print(sr.loc[['1号', '3号']], '\n') # sr.iloc[[[0, 2]]
print(sr.loc['1号':'3号']) # sr.iloc[0:3]
1号 53
2号 64
3号 72
4号 82
dtype: int64
72
1号 53
3号 72
dtype: int64
1号 53
2号 64
3号 72
dtype: int64
2.2 二维对象的索引
在NumPy数组中,花式索引输出的是一个向量。但在Pandas二维对象中,考虑到其行列标签的信息不能丢失,输出的是矩阵。
i = ['1号', '2号', '3号', '4号']
v1 = [53, 64, 72, 82]
v2 = ['女', '男', '男', '女']
sr1 = pd.Series(v1, index=i)
sr2 = pd.Series(v2, index=i)
df = pd.DataFrame({'年龄': sr1, '性别': sr2})
print(df, '\n')
print(df.loc['1号', '年龄'], '\n') # df.iloc[0, 0]
print(df.loc[['1号', '3号'], ['性别', '年龄']], '\n') # df.iloc[[0, 2], [1, 0]]
print(df.loc['1号':'3号', '年龄'], '\n') # df.iloc[0:3, 0]
print(df.loc['3号', :], '\n') # 提取行;df.iloc[2, :];可省略冒号
print(df.loc[:, '年龄']) # 提取列;df.iloc[:, 0];可省略冒号与loc/iloc
年龄 性别
1号 53 女
2号 64 男
3号 72 男
4号 82 女
53
性别 年龄
1号 女 53
3号 男 72
1号 53
2号 64
3号 72
Name: 年龄, dtype: int64
年龄 72
性别 男
Name: 3号, dtype: object
1号 53
2号 64
3号 72
4号 82
Name: 年龄, dtype: int64
3 对象的变形
3.1 转置:.T
调用T
获取转置后的对象,用于处理某些行是特征、列是个体的畸形原始数据。
v = [[53, 64, 72, 82], ['女', '男', '男', '女']]
i = ['年龄', '性别']
c = ['1号', '2号', '3号', '4号']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
df = df.T
print(df)
1号 2号 3号 4号
年龄 53 64 72 82
性别 女 男 男 女
年龄 性别
1号 53 女
2号 64 男
3号 72 男
4号 82 女
3.2 翻转
利用切片机制对对象进行左右翻转.iloc[:, ::-1]
与上下翻转.iloc[::-1, :]
i = ['1号', '2号', '3号', '4号']
v1 = [53, 64, 72, 82]
v2 = ['女', '男', '男', '女']
sr1 = pd.Series(v1, index=i)
sr2 = pd.Series(v2, index=i)
df = pd.DataFrame({'年龄': sr1, '性别': sr2})
print(df, '\n')
print(df.iloc[:, ::-1], '\n') # 左右翻转
print(df.iloc[::-1, :]) # 上下翻转
年龄 性别
1号 53 女
2号 64 男
3号 72 男
4号 82 女
性别 年龄
1号 女 53
2号 男 64
3号 男 72
4号 女 82
年龄 性别
4号 82 女
3号 72 男
2号 64 男
1号 53 女
3.3 重塑
类似PyThon字典,可以直接利用[]
运算符,将Series并入DataFrame,或从DataFrame分离Series
i = ['1号', '2号', '3号', '4号']
v1 = [10, 20, 30, 40]
v2 = ['女', '男', '男', '女']
v3 = [1, 2, 3, 4]
sr1 = pd.Series(v1, index=i)
sr2 = pd.Series(v2, index=i)
sr3 = pd.Series(v3, index=i)
df = pd.DataFrame({'年龄': sr1, '性别': sr2})
print(df, '\n')
df['牌照'] = sr3 # 一维对象与二维对象的合并:把sr3并入,新建一列
print(df, '\n')
sr4 = df['年龄'] # 从中分离出sr4
print(sr4)
年龄 性别
1号 10 女
2号 20 男
3号 30 男
4号 40 女
年龄 性别 牌照
1号 10 女 1
2号 20 男 2
3号 30 男 3
4号 40 女 4
1号 10
2号 20
3号 30
4号 40
Name: 年龄, dtype: int64
3.4 拼接:pd.concat()
函数pd.concat()
可以拼接两个对象,与np.concatenate()
函数语法相似。一维对象Series与二维对象DataFrame的合并无需使用该函数,实为3.3重塑中的合并操作。
Pandas放弃了Python集合与字典的索引唯一特性,因此合并后的索引可能重复。可通过对对象的index
或columns
属性调用.is_unique()
方法来检查是否有重复索引。
# 一维对象的合并
v1 = [10, 20, 30, 40]
v2 = [40, 50, 60]
k1 = ['1号', '2号', '3号', '4号']
k2 = ['4号', '5号', '6号']
sr1 = pd.Series(v1, index=k1)
sr2 = pd.Series(v2, index=k2)
print(sr1, '\n')
print(sr2, '\n')
print(pd.concat([sr1, sr2]))
1号 10
2号 20
3号 30
4号 40
dtype: int64
4号 40
5号 50
6号 60
dtype: int64
1号 10
2号 20
3号 30
4号 40
4号 40
5号 50
6号 60
dtype: int64
合并二维对象时需设置axis
参数,默认为0,axis=x
意义与NumPy中同为沿轴x。
# 二维对象的合并
v1 = [[10, '女'], [20, '男'], [30, '男'], [40, '女']]
v2 = [[1, '是'], [2, '是'], [3, '是'], [4, '否']]
v3 = [[50, '男', 5, '是'], [60, '女', 6, '是']]
i1 = ['1 号', '2 号', '3 号', '4 号']
i2 = ['1 号', '2 号', '3 号', '4 号']
i3 = ['5 号', '6 号']
c1 = ['年龄', '性别']
c2 = ['牌照', '是否参保']
c3 = ['年龄', '性别', '牌照', '是否参保']
df1 = pd.DataFrame(v1, index=i1, columns=c1)
df2 = pd.DataFrame(v2, index=i2, columns=c2)
df3 = pd.DataFrame(v3, index=i3, columns=c3)
print(df1, '\n')
print(df2, '\n')
print(df3, '\n')
print(pd.concat([df1, df2], axis=1), '\n') # 合并列对象(添加列特征)
print(pd.concat([df1, df3])) # 合并行对象(添加行个体)
年龄 性别
1 号 10 女
2 号 20 男
3 号 30 男
4 号 40 女
牌照 是否参保
1 号 1 是
2 号 2 是
3 号 3 是
4 号 4 否
年龄 性别 牌照 是否参保
5 号 50 男 5 是
6 号 60 女 6 是
年龄 性别 牌照 是否参保
1 号 10 女 1 是
2 号 20 男 2 是
3 号 30 男 3 是
4 号 40 女 4 否
年龄 性别 牌照 是否参保
1 号 10 女 NaN NaN
2 号 20 男 NaN NaN
3 号 30 男 NaN NaN
4 号 40 女 NaN NaN
5 号 50 男 5.0 是
6 号 60 女 6.0 是
4 对象的运算
执行基本运算时也是按元素运算,且可以使用NumPy的各种函数。
4.1 对象与系数的运算
# 一维对象与系数的运算
sr = pd.Series([53, 64, 72], index=['1 号', '2 号', '3 号'])
print(sr, '\n')
print(sr + 10, '\n')
print(sr * 10, '\n')
print(sr ** 2)
1 号 53
2 号 64
3 号 72
dtype: int64
1 号 63
2 号 74
3 号 82
dtype: int64
1 号 530
2 号 640
3 号 720
dtype: int64
1 号 2809
2 号 4096
3 号 5184
dtype: int64
# 二维对象与系数的运算
sr = pd.Series([53, 64, 72], index=['1 号', '2 号', '3 号'])
v = [[53, '女'], [64, '男'], [72, '男']]
df = pd.DataFrame(v, index=['1号', '2号', '3号'], columns=['年龄', '性别'])
print(df, '\n')
df['减法'] = df['年龄'] - 5
df['除法'] = df['年龄'] / 5
df['取余'] = df['年龄'] % 3
print(df)
年龄 性别
1号 53 女
2号 64 男
3号 72 男
年龄 性别 减法 除法 取余
1号 53 女 48 10.6 2
2号 64 男 59 12.8 1
3号 72 男 67 14.4 0
4.2 对象与对象的运算
对象做运算,必须保证其都是数字型对象,两个对象之间的维度可以不同(会产生缺失值)。
# 一维对象之间的运算
v1 = [10, 20, 30, 40]
v2 = [1, 2, 3]
k1 = ['1号', '2号', '3号', '4号']
k2 = ['1号', '2号', '3号']
sr1 = pd.Series(v1, index=k1)
sr2 = pd.Series(v2, index=k2)
print(sr1, '\n')
print(sr2, '\n')
print(sr1 + sr2, '\n')
print(sr1 * sr2, '\n')
print(sr1 ** sr2)
1号 10
2号 20
3号 30
4号 40
dtype: int64
1号 1
2号 2
3号 3
dtype: int64
1号 11.0
2号 22.0
3号 33.0
4号 NaN
dtype: float64
1号 10.0
2号 40.0
3号 90.0
4号 NaN
dtype: float64
1号 10.0
2号 400.0
3号 27000.0
4号 NaN
dtype: float64
# 二维对象之间的运算
v1 = [[10, '女'], [20, '男'], [30, '男'], [40, '女']]
v2 = [2, 8, 8, 5]
i1 = ['1号', '2号', '3号', '4号']
c1 = ['年龄', '性别']
i2 = ['1号', '2号', '3号', '6号']
c2 = ['成绩']
df1 = pd.DataFrame(v1, index=i1, columns=c1)
df2 = pd.DataFrame(v2, index=i2, columns=c2)
print(df1, '\n')
print(df2, '\n')
df1['减法'] = df1['年龄'] - df2['成绩']
df1['除法'] = df1['年龄'] / df2['成绩']
df1['取余'] = df1['年龄'] % df2['成绩']
print(df1)
年龄 性别
1号 10 女
2号 20 男
3号 30 男
4号 40 女
成绩
1号 2
2号 8
3号 8
6号 5
年龄 性别 减法 除法 取余
1号 10 女 8.0 5.00 0.0
2号 20 男 12.0 2.50 4.0
3号 30 男 22.0 3.75 6.0
4号 40 女 NaN NaN NaN
使用np.abs()
、np.cos()
、np.exp()
、np.log()
等数学函数时,会保留索引。
Pandas中仍然存在布尔型对象,用法参考NumPy即可,此处不多赘述。
5 对象的缺失值
5.1 发现缺失值:.isnull()
使用.isnull()
方法发现缺失值NaN
,生成布尔型对象。方法.notnull()
效果与之相反,相当于在前面加非号~
。
# 发现一维对象的缺失值
v = [53, None, 72, 82]
k = ['1号', '2号', '3号', '4号']
sr = pd.Series(v, index=k)
print(sr, '\n')
print(sr.isnull())
1号 53.0
2号 NaN
3号 72.0
4号 82.0
dtype: float64
1号 False
2号 True
3号 False
4号 False
dtype: bool
# 发现二维对象的缺失值
v = [[None, 1], [64, None], [72, 3], [82, 4]]
i = ['1号', '2号', '3号', '4号']
c = ['年龄', '牌照']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
print(df.isnull())
年龄 牌照
1号 NaN 1.0
2号 64.0 NaN
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
1号 True False
2号 False True
3号 False False
4号 False False
5.2 剔除缺失值:.dropna()
使用.dropna()
方法剔除缺失值,直接丢弃。
# 剔除一维对象的缺失值
v = [53, None, 72, 82]
k = ['1号', '2号', '3号', '4号']
sr = pd.Series(v, index=k)
print(sr, '\n')
print(sr.dropna())
1号 53.0
2号 NaN
3号 72.0
4号 82.0
dtype: float64
1号 53.0
3号 72.0
4号 82.0
dtype: float64
二维对象中,要么单独剔除含有缺失值的行,要么剔除含有缺失值的列。默认剔除行,可设置参数axis='columns'
来剔除列(极少用)。也可设置参数how='all'
来只有当全部为缺失值时才剔除。
# 剔除二维对象的缺失值
v = [[None, 1], [None, None], [72, 3], [82, 4]]
i = ['1号', '2号', '3号', '4号']
c = ['年龄', '牌照']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
print(df.dropna(), '\n')
print(df.dropna(axis='columns'), '\n')
print(df.dropna(how='all'))
年龄 牌照
1号 NaN 1.0
2号 NaN NaN
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
3号 72.0 3.0
4号 82.0 4.0
Empty DataFrame
Columns: []
Index: [1号, 2号, 3号, 4号]
年龄 牌照
1号 NaN 1.0
3号 72.0 3.0
4号 82.0 4.0
5.3 填充缺失值:.fillna()
使用.fillna()
方法填充缺失值,通常选用常数(0、均值…)、前值(method='ffill'
)或后值(method='bfill'
)来填充。
# 填充一维对象的缺失值
v = [53, None, 72, 82]
k = ['1号', '2号', '3号', '4号']
sr = pd.Series(v, index=k)
print(sr, '\n')
print(sr.fillna(0), '\n')
print(sr.fillna(np.mean(sr)), '\n')
print(sr.fillna(method='ffill'), '\n')
print(sr.fillna(method='bfill'))
1号 53.0
2号 NaN
3号 72.0
4号 82.0
dtype: float64
1号 53.0
2号 0.0
3号 72.0
4号 82.0
dtype: float64
1号 53.0
2号 69.0
3号 72.0
4号 82.0
dtype: float64
1号 53.0
2号 53.0
3号 72.0
4号 82.0
dtype: float64
1号 53.0
2号 72.0
3号 72.0
4号 82.0
dtype: float64
# 填充二维对象的缺失值
v = [[None, 1], [None, None], [72, 3], [82, 4]]
i = ['1号', '2号', '3号', '4号']
c = ['年龄', '牌照']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
print(df.fillna(0), '\n')
print(df.fillna(np.mean(df)), '\n')
print(df.fillna(method='ffill'), '\n')
print(df.fillna(method='bfill'))
年龄 牌照
1号 NaN 1.0
2号 NaN NaN
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
1号 0.0 1.0
2号 0.0 0.0
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
1号 32.4 1.0
2号 32.4 32.4
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
1号 NaN 1.0
2号 NaN 1.0
3号 72.0 3.0
4号 82.0 4.0
年龄 牌照
1号 72.0 1.0
2号 72.0 3.0
3号 72.0 3.0
4号 82.0 4.0
6 数据分析
6.1 读取csv文件:pd.read_csv()
使用函数pd.read_csv()
读取csv文件为DataFrame对象,参数index_col
表示从第几列开始读取,默认为0。
df = pd.read_csv('data.csv')
6.2 聚合方法
调用.head()
方法可仅输出前五行。除此之外NumPy中所有的聚合函数在Pandas中均有对象版的聚合方法,且均为忽略缺失值的安全版本。
df.head() # 仅输出前五行
# 各种聚合函数,使用方式参考NumPy中的安全版本
df.max()
df.min()
df.mean()
df.std()
df.sum()
可使用.describe()
描述方法直接查看所有聚合函数的信息。其中min、25%、50%、75%、max为把数据从小到大排序后的五个分位点,显然50%分位点即为中位数。如下例所示
v = [[None, 1], [None, 2], [72, 3], [82, 4]]
i = ['1号', '2号', '3号', '4号']
c = ['年龄', '牌照']
df = pd.DataFrame(v, index=i, columns=c)
print(df, '\n')
print(df.describe())
年龄 牌照
1号 NaN 1
2号 NaN 2
3号 72.0 3
4号 82.0 4
年龄 牌照
count 2.000000 4.000000
mean 77.000000 2.500000
std 7.071068 1.290994
min 72.000000 1.000000
25% 74.500000 1.750000
50% 77.000000 2.500000
75% 79.500000 3.250000
max 82.000000 4.000000
6.3 数据透视:.pivot_table()
使用.pivot_table()
方法可创建数据透视,用法如下:
# Output为考察的核心,研究其他特征Input_r、Input_c与之的关系
df.pivot_table(Output, index=Input_r, columns=Input_c)
另有两个用于分割的函数:pd.cut()
指定分割序列、pd.cut()
指定分割段数。详见以下示例
【例】以虚构的示例数据为例,以“是否生还”特征为考察的核心,研究其它特征与之的关系。
df = pd.read_csv('elimination.csv')
print(df, '\n')
# 一个特征
print(df.pivot_table('是否生还', index='性别'), '\n')
# 两个特征
print(df.pivot_table('是否生还', index='性别', columns='等级'), '\n')
# 三个特征,以18岁为分水岭分为两部分
age = pd.cut(df['年龄'], [0, 18, 120])
print(df.pivot_table('是否生还', index=['性别', age], columns='等级'), '\n')
# 四个特征,将费用自动分为两部分
fare = pd.qcut(df['费用'], 2)
print(df.pivot_table('是否生还', index=['等级', fare], columns=['性别', age]))