Pandas 是基于 Numpy 的一套数据分析工具,该工具是为了解决数据分析任务而创建的。
小贴士:
- 本文中多处使用到 Numpy 模块,若对其不熟悉,可先浏览:AI算法工程师 | 03人工智能基础-Python科学计算和可视化(一)Numpy
说明
测试与安装
若不清楚 Python 环境是否安装了 Pandas,可先测试:
win + R 后输入“cmd” → 在 cmd 的命令窗口输入 python →import pandas 并回车 →ModuleNotFoundError: No module named 'pandas'”,说明未安装 Pandas;若什么都没显示,则说明已安装。exit() 可退出 python 环境。cmd 中使用 pip 命令安装 Pandas:(注意该命令是在 cmd 中,而非 python 环境中)
# 安装命令1(不指定版本)
pip install pandas
# 安装命令2(指定下载源,这样下载得更快)
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
安装完成后,可以测试一下 Pandas 是否安装成功。下面是导入 pandas 模块的语句(该语句是在 python 环境中输入),若不报错,说明 Pandas 已经安装成功了。
# 导入 pandas 模块,并起别名为 pd
# 注意:每次使用 pandas 前均需写导入模块的语句
import pandas as pd
# 扩:这是查看 pandas 库的版本号的命令
import pandas
pandas.__version__ # 查看版本号(命令中,version前后均分别有两个下划线)
图示

Pandas 中两个重要的数据类型:Series 和 DataFrame
Series 语法格式
pandas.Series( data, index, dtype, name, copy)
'''
参数说明:
· data :一组数据(ndarray 类型)
· index:数据索引标签(若不指定,默认从 0 开始)
· dtype:数据类型,默认会自己判断
· name :设置名称(默认为 False)
'''
示例1 - 使用列表创建
import pandas as pd # 导包
data = pd.Series([1,2,3,4,5]) # 返回一个序列
data

Series 对象本质上是调用 numpy 创建了一个一维数组,之后在其身上赋予了一个索引,从而组成了一个 Series。即:Series 对象中有 ① numpy 数组、② index 索引。
因此,pandas 中有两个重要的属性 values(Series 对象的原始数据) 和 index(对应 Series 对象的索引对象)
data.values # 查看属性 values
data.index # 查看属性 index

data = pd.Series([4,3,6,7,9],index=['one','two','three','four','five'])
data

data = pd.Series([4,3,6,7,9],index=list('abcde'))
data

示例2 - 使用字典创建
import pandas as pd # 导包
# 使用字典创建 Series 对象,默认将 key 作为 index 属性
population_dict={'bj':3000,'gz':1500,'sh':2800,'sz':1200} # 可传字典
population_series=pd.Series(population_dict)
population_series

# 如果存在取交集
sub_series=pd.Series(population_dict,index=['bj','sh'])
sub_series
# 如果不存在则值为 NaN
sub_series=pd.Series(population_dict,index=['bj','xa'])
sub_series

示例3 - 使用标量与 index 创建
import pandas as pd # 导包
data = pd.Series(6,index=[6,5,8,9,3])
data

关于 DataFrame
DataFrame 可以看成一个数据框(表格),有行与列。其中,每一列可以是不同的值类型,如:数值、布尔、字符串等。
图示 - 由 Series 组成的 DataFrame:

DataFrame 语法格式:
pandas.DataFrame( data, index, columns, dtype, copy)
'''
参数说明:
· data :一组数据(ndarray、series, map, lists, dict 等类型)
· index :数据索引标签(相当于:行索引)
· columns:列索引(默认为 RangeIndex 0, 1, 2, …, n)
· dtype :数据类型
· copy :拷贝数据(默认为 False)
'''
示例1 - 使用 Series 及字典创建
import pandas as pd # 导包
# 字典
population_dict={'beijing':3000,'shanghai':1200,'guangzhou':1800}
area_dict={'beijing':300,'guangzhou':200,'shanghai':180}
# 创建 2 个 series
population_series=pd.Series(population_dict)
area_series=pd.Series(area_dict)
# 通过 DataFrame 创建数据框
citys=pd.DataFrame({'area':area_series,'population':population_series})
citys

citys.index # 数据索引标签(相当于:行索引)
citys.values # 数据值
citys.columns # 列索引

示例2 - 使用列表创建
import pandas as pd # 导包
# 字典
population_dict={'beijing':3000,'shanghai':1200,'guangzhou':1800}
area_dict={'beijing':300,'guangzhou':200,'shanghai':180}
# 使用列表创建 DataFrame 对象
citys=pd.DataFrame([population_dict,area_dict]) # 直接把两个字典放在列表中
citys # 会将‘beijing’‘shanghai’ ‘guangzhou’作为表头(列索引)

从结果中可以看到,使用列表创建的 DataFrame 对象,若未指定 index,则行索引默认从 0 开始。
import pandas as pd # 导包
# 字典
population_dict={'beijing':3000,'shanghai':1200,'guangzhou':1800}
area_dict={'beijing':300,'guangzhou':200,'shanghai':180}
# 创建 DataFrame 对象,并设置行索引
citys=pd.DataFrame([population_dict,area_dict], index=['population','area']) # 指定索引号名称
citys

pd.DataFrame([population_dict,area_dict],
index=['population','area'],columns=['beijing','guangzhou']) # 指定 columns,设置列索引

import pandas as pd # 导包
# 创建 1 个 series
population_dict={'beijing':3000,'shanghai':1200,'guangzhou':1800}
population_series=pd.Series(population_dict)
# 设置列索引
pd.DataFrame(population_series,columns=['population']) # 指定列名
# pd.DataFrame({'population':population_series}) # 与上一行的代码等价

import pandas as pd # 导包
pd.DataFrame([{'a':i,'b':i*2} for i in range(3)])
# pd.DataFrame([{'a':i,'b':i*2} for i in range(3)], index=['一','二','三']) # 指定行名称

示例3 - 使用二维数组创建
import pandas as pd # 导包
import numpy as np
# 指明行名称、列名称
pd.DataFrame(np.random.randint(0, 100, (4,3)), index=['a','b','c','d'], columns=['a','b','c'])

示例4 - 使用字典创建
import pandas as pd # 导包
pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
})
data # 字典中所有的键都作为表头(列索引)

import pandas as pd # 导包
data = pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
},columns=['Sno','Sex','Age','Score'])
data

import pandas as pd # 导包
data = pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
},columns=['Sno','Sex','Age','Score'],index=['zs','lisi','ww'])
data

小贴士:
- 关于 DataFrame 的详细介绍,可参考: 菜鸟教程——Pandas 数据结构 - DataFrame
示例
import pandas as pd # 导包
data = pd.Series([45,6,2,3,5],index=list('abcde'))
display('根据key获取:',data['a'])
display('切片获取:',data['a':'d']) # 注意,这里(标签索引)不是左闭右开,会取到 d
display('索引获取:',data[1]) # 取第二个
display('索引切片:',data[2:4])# 这里(位置索引)取值时,是左闭右开

可以看到,Series 和 ndarray 数组类似,可以通过索引来访问元素。但 Series 对象的索引可分为位置索引和标签索引。
其中,标签索引进行切片时:左闭右闭;而位置索引:左闭右开。
data=pd.Series([5,6,7,8],index=[1,2,3,4])
data[1]

上方的 Series 对象 data 中,位置索引与标签索引有相同值 1,则 data[1] 代表的含义便不明确,此时需使用 loc(标签索引)、iloc(位置索引)。
data.loc[1] # 根据名字(标签索引)取值
data.iloc[1] # 根据位置索引取值

获取 DataFrame 的值的介绍
DataFrame 对象获取列的数据:
其中,获取连续的某几列时,用普通索引和位置索引都可以做到。由于要获取的列是连续的,所以需要对列进行切片来获取数据。
获取行的方式主要有两种:
示例1 - 获取列
import pandas as pd # 导包
import numpy as np
data=pd.DataFrame(np.arange(12).reshape(3,4),index=list('abc'),columns=list('ABCD'))
data

print('获取‘B’列:')
print(data['B']) # 如果要获取一列,则只需要传入一个列名
print('获取‘A’‘C’两列:')
print(data[['A','C']]) # 如果是同时选择多列,则传入多个列名(用一个 list 存放)即可

print('获取第 1 列:')
print(data.iloc[:,0])
print('获取第 1 列和第 3 列:')
print(data.iloc[:,[0,2]])
# 说明:iloc 后的方括号中
# ① 逗号之前的部分表示要获取的行的位置。只输入一个冒号,不输入任何数值表示获取所有的行;
# ② 逗号之后的方括号表示要获取的列的位置,列的位置同样也是从 0 开始计数。

print('获取 A B 两列,使用位置索引获取:')
print(data.iloc[:,0:2])
print('获取 A B C 三列,使用普通索引获取:')
print(data.loc[:,'A':'C'])

示例2 - 获取行
print('获取 a 行,普通索引获取:')
print(data.loc['a'])
print('获取 a c 行,普通索引获取:')
print(data.loc[['a','c']])
print('获取第 1 行,位置索引获取:')
print(data.iloc[0])
print('获取第 1 行第 3 行,位置索引获取:')
print(data.iloc[[0,2]])

# 选择连续的某几行和选择连续某几列类似:把连续行的位置用一个区间表示
print('选择第 1 行 第 2 行,使用位置索引:')
print(data.iloc[0:2])
print('选择 a 行 b 行,使用普通索引:')
print(data.loc['a':'b'])

示例3 - 同时获取行和列
print('同时获取 a b c 行,A B 列,使用普通索引:')
print(data.loc['a':'c','A':'B'] )
print('同时获取 a b 行,A B 列,使用位置索引:')
print(data.iloc[0:2,0:2])

print('同时获取 a c 行,ABD 列,使用普通索引:')
print(data.loc[['a','c'],['A','B','D']])
print('同时获取 a c 行,ABD 列,使用位置索引:')
print(data.iloc[[0,2],[0,1,3]])

Series 对象中有很多常用的方法可以对数据进行各种处理。例如:
| 方法 | 描述 |
|---|---|
| mean | 对某一列数据取平均数 |
| min | 获取最小值 |
| max | 获取最大值 |
| std | 获取标准差 |
示例 - 对数据集进行各种运算,并排序
import pandas as pd # 导包
data = pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
},columns=['Sno','Sex','Age','Score'],index=['zs','lisi','ww'])
display('数据集',data)

ages = data['Age'] # 获取数据集中 Age 列的所有
print(ages)
ages.mean(), ages.min(), ages.max(), ages.std()

ages.sort_values() # 对 Age 列进行排序(默认正序排序)

ages.sort_values(ascending=False) # 对 Age 列进行降序排序

Series 对象也可像 SQL 语句一样,通过指定条件进行数据的过滤。
示例
import pandas as pd # 导包
# 创建数据集
data = pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
},columns=['Sno','Sex','Age','Score'],index=['zs','lisi','ww'])
# 取出 'Score' 列的数据,并对数据进行筛选
scores = data['Score']
print(scores.mean()) # 平均值
scores[scores>scores.mean()] # 筛选出大于平均值的

DataFrame 与 Series 类似,也可使用条件进行过滤。
示例
import pandas as pd # 导包
# 创建数据集
data = pd.DataFrame({
'Name':['zs','lisi','ww'],
'Sno':['1001','1002','1003'],
'Sex':['man','woman','man'],
'Age':[17,18,19],
'Score':[80,97,95]
},columns=['Sno','Sex','Age','Score'],index=['zs','lisi','ww'])
# 输出数据中所有成绩大于平均值的记录
scores = data['Score'] # 取出 'Score' 列的数据
print(scores.mean())
data[scores>scores.mean()] # data 中取值

# 且
ages = data['Age'] # 获取数据集中 Age 列的所有
data[(scores>scores.mean()) & (ages<19)] # 成绩大于平均值,且 年龄小于 19
# 或
data[(scores>scores.mean()) | (ages<19)] # 成绩大于平均值,或 年龄小于 19

# 获取成绩大于平均值的所有记录,只显示 Sno Age Score 三列
data[scores>scores.mean()].loc[:,['Sno','Age','Score']]

何谓缺失值?缺失值是指由某些原因导致部分数据为空。
对于为空的这部分数据,一般有两种处理方式:
在对缺失值进行处理前,需要把缺失值找出来,即查看哪列有缺失值。
Pandas 中缺失值用 NaN 表示,通过调用 info() 方法可看到返回的每一列的缺失情况。
示例
import pandas as pd # 导包
import numpy as np
df=pd.DataFrame([[1,2,np.nan],[4,np.nan,6],[5,6,7]])
df.info() # 缺失值查看

import pandas as pd # 导包
import numpy as np
data=pd.Series([3,4,np.nan,1,5,None])
print(data.isnull(),'\n') # isnull()方法判断是否是缺值
print(data[data.isnull()],'\n') # 获取缺值
print(data[data.notnull()]) # 获取非空值

缺失值分为两种:
调用 dropna() 方法删除缺失值:
axis=’columns’。示例
import pandas as pd # 导包
import numpy as np
df=pd.DataFrame([[1,2,np.nan],[4,np.nan,6],[5,6,7]]) # 3行 3列
new_df = df.dropna() # 缺失值删除(默认为以行为单位剔除)
new_df

df.dropna(axis='columns') # 以列为单位剔除

df.dropna(how='all') # 某行中所有数据为 nan 时才剔除该行

由于数据是宝贵的,一般情况下如果数据缺失比例不高,尽量不会选择删除,而是选择填充。
调用 fillna() 方法填充缺失值:
示例
import pandas as pd # 导包
import numpy as np
data=pd.Series([3,4,np.nan,1,5,None])
print('以 0 进行填充:')
display(data.fillna(0))
print('以前一个数进行填充:')
display(data.fillna(method='ffill'))
print('以后一个数进行填充:')
display(data.fillna(method='bfill'))
print('先按后一个,再按前一个')
display(data.fillna(method='bfill').fillna(method='ffill'))

import pandas as pd # 导包
import numpy as np
df=pd.DataFrame([[1,2,np.nan],[4,np.nan,6],[5,6,7]])
print('使用数值 0 来填充:')
display(df.fillna(0))
print('使用行的前一个数来填充:')
display(df.fillna(method='ffill'))
print('使用列的后一个数来填充:')
display(df.fillna(method='bfill' ,axis=1))

import pandas as pd # 导包
import numpy as np
df=pd.DataFrame([[1,2,np.nan],[4,np.nan,6],[5,6,7]])
display(df) # 原数据 df
for i in df.columns:
df[i]=df[i].fillna(np.nanmean(df[i])) # 将填充完后的序列赋值给原序列(达到修改原数据的效果)
display(df) # 填充后的数据 df

示例1 - Series 对象拼接
import pandas as pd # 导包
ser1=pd.Series([1,2,3],index=list('ABC'))
ser2=pd.Series([4,5,6],index=list('DEF'))
pd.concat([ser1,ser2])

示例2 - DataFrame 对象拼接
import pandas as pd # 导包
# 声明一个函数
def make_df(cols,index):
data={c:[str(c)+str(i) for i in index] for c in cols}
return pd.DataFrame(data,index=index)
# 调用函数,创建两个 DataFrame 对象
df1=make_df('AB',[1,2])
df2=make_df('AB',[3,4])
# 拼接(默认找相同的列索引进行合并)
pd.concat([df1, df2])

pd.concat([df1, df2], axis=1) # 按列拼接,axis=1与 axis='columns' 等价

从上图结果中可以看到,多个 df 对象按列拼接时,若行索引不同,行也会往下拼接,并用 NaN 填充没有的数据。
多个 df 对象拼接,当设置 axis=1 按列拼接时,相同的行索引会进行合并,如:

示例3 - DataFrame 对象拼接的索引重复问题
import pandas as pd # 导包
# 声明一个函数
def make_df(cols,index):
data={c:[str(c)+str(i) for i in index] for c in cols}
return pd.DataFrame(data,index=index)
# 调用函数,创建两个 DataFrame 对象
df1=make_df('AB',[1,2])
df2=make_df('AB',[1,2])
# 拼接(默认找相同的列索引进行合并)
pd.concat([df1, df2])

# 解决索引重复问题,方式 1 :加 ignore_index 属性
pd.concat([df1,df2], ignore_index=True)

# 解决索引重复问题,方式 2 :加 keys 属性
pd.concat([df1,df2],keys=['df1', 'df2'])

示例4 - join 拼接
import pandas as pd # 导包
# 声明一个函数
def make_df(cols,index):
data={c:[str(c)+str(i) for i in index] for c in cols}
return pd.DataFrame(data,index=index)
# 调用函数,创建两个 DataFrame 对象
a=make_df('ABC',[1,2])
b=make_df('BCD',[3,4])
# 内连接(取列相交部分)
pd.concat([a,b],join='inner')

pandas 中 的 merge 和 concat 类似,但主要是用于两组有 key column 的数据,统一索引的数据。通常也被用在 Database 的处理当中。
使用 merge 合并时有 4 种方式 how = [‘left’, ‘right’, ‘outer’, ‘inner’],默认为 inner。
示例 - merge 的使用
import pandas as pd # 导包
# 创建 DataFrame 对象
left=pd.DataFrame({'key':['k0','k1','k2','k3'],
'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3'],
}) # 通过字典方式传入3个列
right=pd.DataFrame({'key':['k0','k1','k4','k3'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3'],
})
# 合并
pd.merge(left, right) # 默认合并,此处以 'key' 作为公共部分(可能会丢数据)
# 语句说明:
# 先看left、right这两内容 是否有相同名字这一列,
# 对相同列 key 的数据做交集,再把交集所对应的其他列数据合并到结果中去

pd.merge(left, right, how='outer') # 数据全部保留

pd.merge(left, right, how='left') # 左侧的全部保留

pd.merge(left, right, how='right')# 右侧的全部保留

—— 说明:本文写于 7.30~8.1,文中内容基于 python3,使用工具 Jupyter Notebook 编写的代码
(本文中使用函数前的 np 代表 Numpy 的别名,pd 为 Pandas 的别名,每次使用前需导入相关模块)