1. pandas简介
Pandas 是一个开源的第三方 Python 库,从 Numpy 和 Matplotlib 的基础上构建而来,享有数据分析“三剑客之一”的盛名(NumPy、Matplotlib、Pandas)。Pandas 已经成为 Python 数据分析的必备高级工具,它的目标是成为强大、灵活、可以支持任何编程语言的数据分析工具,本文主要是对pandas进行入门,通过本文你将系统性了解pandas的基本使用方法。
Pandas优势:
处理浮点与非浮点数据里的缺失数据,表示为 NaN;
大小可变:插入或删除 DataFrame 等多维对象的列;
自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐;
强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据;
把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象;
基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作;
直观地合并(merge)、**连接(join)**数据集;
灵活地重塑(reshape)、**透视(pivot)**数据集;
轴支持结构化标签:一个刻度支持多个标签;
成熟的 IO 工具:读取文本文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,利用超快的 HDF5 格式保存 / 加载数据;
时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。
这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。
其它说明:
Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。
Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。
Pandas 已广泛应用于金融领域。
2. pandas安装以及库的导入
2.1 Pandas安装
Python自带的包管理工具pip来安装:
pip install pandas
2.2 pandas模块的导入
import numpy as np # pandas和numpy常常结合在一起使用,导入numpy库
import pandas as pd # 导入pandas库
3. pandas数据结构
我们知道,构建和处理二维、多维数组是一项繁琐的任务。Pandas 为解决这一问题, 在 ndarray 数组(NumPy 中的数组)的基础上构建出了两种不同的数据结构,分别是 Series(一维数据结构)和 DataFrame(二维数据结构):
- Series 是带标签的一维数组,这里的标签可以理解为索引,但这个索引并不局限于整数,它也可以是字符类型,比如 a、b、c 等;
- DataFrame 是一种表格型数据结构,它既有行标签,又有列标签。
数据结构 | 维度 | 说明 |
Series | 1 | 该结构能够存储各种数据类型,比如字符数、整数、浮点数、Python 对象等,Series 用 name 和 index 属性来描述 数据值。Series 是一维数据结构,因此其维数不可以改变。 |
DataFrame | 2 | DataFrame 是一种二维表格型数据的结构,既有行索引,也有列索引。行索引是 index,列索引是 columns。 在创建该结构时,可以指定相应的索引值。 |
3.1 pandas Series结构
Series 结构,也称 Series 序列,是 Pandas 常用的数据结构之一,它是一种类似于一维数组的结构,由一组数据值(value)和一组标签组成,其中标签与数据值之间是一一对应的关系。
Series 可以保存任何数据类型,比如整数、字符串、浮点数、Python 对象等,它的标签默认为整数,从 0 开始依次递增。Series 的结构图,如下所示:
通过标签我们可以更加直观地查看数据所在的索引位置。
3.1.1创建Series对象
import pandas as pd
s=pd.Series( data, index, dtype, copy)
#参数说明:
#data 输入的数据,可以是列表、常量、ndarray 数组等。
#index 索引值必须是惟一的,如果没有传递索引,则默认为 #np.arrange(n)。
#dtype dtype表示数据类型,如果没有提供,则会自动判断得出。
#copy 表示对 data 进行拷贝,默认为 False。
可以用数组、字典、标量值或者 Python 对象来创建 Series 对象
3.1.2 访问Series数据
Series 访问数据分为两种方式,一种是位置索引访问;另一种是标签索引访问。
3.1.3 Series常用属性
Series 的常用属性和方法。在下表列出了 Series 对象的常用属性
名称 | 属性 |
axes | 以列表的形式返回所有行索引标签 |
dtype | 返回对象的数据类型 |
empty | 判断Series对象是否为空 |
ndim | 返回输入数据的维数 |
size | 返回输入数据的元素数量 |
values | 以ndarray的形式返回Series对象 |
index | 返回一个RangeIndex对象,用来描述索引的取值范围。 |
3.2 pandas DataFrame结构
DataFrame 一个表格型的数据结构,既有行标签(index),又有列标签(columns),它也被称异构数据表,所谓异构,指的是表格中每列的数据类型可以不同,比如可以是字符串、整型或者浮点型等。其结构图示意图,如下所示:
3.2.1创建DataFrame对象
import pandas as pd
pd.DataFrame( data, index, columns, dtype, copy)
#参数说明:
data 输入的数据,可以是 ndarray,series,list,dict,标量以及一个 DataFrame。
index 行标签,如果没有传递 index 值,则默认行标签是 np.arange(n),n 代表 data 的元素个数。
columns 列标签,如果没有传递 columns 值,则默认列标签是 np.arange(n)。
dtype dtype表示每一列的数据类型。
copy 默认为 False,表示复制数据 data。
1)列表创建DataFame对象
import pandas as pd
#单一列表创建 DataFrame
data = [1,2,3]
df1 = pd.DataFrame(data)
print(f'单一列表\n{df1}')
'''
单一列表
0
0 1
1 2
2 3
'''
# 使用嵌套列表创建 DataFrame 对象
data = [['java',10],['python','20'],['C++','30']]
df2 = pd.DataFrame(data)
print(f'嵌套列表创建\n{df2}')
'''
嵌套列表创建
0 1
0 java 10
1 python 20
2 C++ 30
'''
#指定数值元素的数据类型为 float: 并指定columns
df3 = pd.DataFrame(data,columns=['name','age'],dtype=float)
print(f'指定数据类型和colums\n{df3}')
'''
指定数据类型和colums
name age
0 java 10.0
1 python 20.0
2 C++ 30.0
'''
2)字典嵌套列表创建DataFrame对象
data字典中,键对应值的元素长度必须相等(也就是列表的长度相等),如果传递索引那么索引的长度必须等于列表的长度;如果没有传递索引,默认情况下 索引应为range(n).n代表的列表的长度
ata = {'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]}
#没有传递所以
df1 = pd.DataFrame(data)
print(f'默认索引\n{df1}')
'''
默认索引
Name Age
0 Tom 28
1 Jack 34
2 Steve 29
3 Ricky 42
'''
#自定义索引
df2 = pd.DataFrame(data,index=['a','b','c','d'])
print(f'自定义索引\n{df2}')
'''
自定义索引
Name Age
a Tom 28
b Jack 34
c Steve 29
d Ricky 42
3)列表嵌套字典创建DataFrame对象
列表嵌套字典作为传入的值时,默认情况下 字典的键作为名(coloumns)
注意:如果某个元素的值缺失,也就是字典的key无法找到对应的Value,奖使用NaN代替
3.3 常用属性和方法汇总
DataFrame 的属性和方法,与 Series 相差无几,如下所示:
名称 | 属性&方法描述 |
index | 返回行索引 |
coloumns | 返回列索引 |
values | 使用numpy数组表示Dataframe中的元素值 |
head() | 返回前 n 行数据。 |
tail() | 返回后 n 行数据。 |
axes | 返回一个仅以行轴标签和列轴标签为成员的列表。 |
dtypes | 返回每列数据的数据类型。 |
empty | DataFrame中没有数据或者任意坐标轴的长度为0,则返回True。 |
ndim | 轴的数量,也指数组的维数。 |
shape | DataFrame中的元素数量。 |
shift() | 将行或列移动指定的步幅长度 |
T | 行和列转置。 |
info() | 返回相关的信息:行数 列数,列索引 列非空值个数, 列类型 |
1) info(),index,coloumns,values ,axes
info():返回DataFrame对象的相关信息
index:返回行索引
coloumns:返回列索引
values:使用numpy数组表示Dataframe中的元素值
axes: 返回一个行标签、列标签组成的列表
4. pandas描述性统计
描述统计学(descriptive statistics)是一门统计学领域的学科,主要研究如何取得反映客观现象的数据,并以图表形式对所搜集的数据进行处理和显示,最终对数据的规律、特征做出综合性的描述分析。Pandas 库正是对描述统计学知识完美应用的体现,可以说如果没有“描述统计学”作为理论基奠,那么 Pandas 是否存在犹未可知。下列表格对 Pandas 常用的统计学函数做了简单的总结:
函数名称 | 描述说明 |
---|---|
count() | 统计某个非空值的数量。 |
sum() | 求和 |
mean() | 求均值 |
median() | 求中位数 |
mode() | 求众数 |
std() | 求标准差 |
min() | 求最小值 |
max() | 求最大值 |
abs() | 求绝对值 |
prod() | 求所有数值的乘积。 |
cumsum() | 计算累计和,axis=0,按照行累加;axis=1,按照列累加。 |
cumprod() | 计算累计积,axis=0,按照行累积;axis=1,按照列累积。 |
corr() | 计算数列或变量之间的相关系数,取值-1到1,值越大表示关联性越强。 |
在 DataFrame 中,使用聚合类指定轴(a
在 DataFrame 中,使用聚合类方法时需要指定轴(axis)参数。下面介绍两种传参方式:
- 对行操作,默认使用 axis=0 或者使用 "index";
- 对列操作,默认使用 axis=1 或者使用 "columns"。
- 从图 上 可以看出,axis=0 表示按垂直方向进行计算,而 axis=1 则表示按水平方向。
5. pandas常用函数使用方法总结
1. 导入模块
import pandas as pd
import numpy as np
2. 读取数据和保存数据
# 2.1 从CSV文件读取数据,编码'gbk'
pd.read_csv(filename, encoding='gbk')
# 2.2 读取前6行,当数据量比较大时,可以只读取前n行
pd.read_csv(filename, encoding='gbk', nrows = 6)
# 2.3 第一列作为行索引,忽略列索引
pd.read_csv(filename, encoding='gbk', header=None, index_col=0)
# 2.4 读取时忽略第1/3/5行和最后两行
pd.read_csv(filename, encoding='gbk', skiprows=[1,3,5], skipfooter=2, engine='python')
# 2.5 从限定分隔符(',')的文件或文本读取数据
pd.read_table(filename, sep=',', encoding='gbk')
# 2.6 保存数据
# 保存为csv文件
df.to_csv('test_ison.csv')
# 保存为xlsx文件
df.to_excel('test_xlsx.xlsx',index=False)
# 保存为ison文件
df.to_json('test_json.txt')
3. 查看数据信息
# 3.1 查看前n行
df.head(3)
# 3.2 查看后n行
df.tail(3)
# 3.3 查看行数和列数
df.shape
# 3.4查看列索引
df.columns
# 3.5 查看行索引
df.index
# 3.6 查看索引、数据类型和内存信息
df.info()
# 3.7 查看数值型列的汇总统计
df.describe()
# 3.8 查看每一列的唯一值和计数
df.apply(pd.Series.value_counts)
4. 数据处理
# 4.1 重命名列名
df.columns = ['姓名','性别','语文','数学','英语','城市','省份']
# 4.2 选择性更改列名
df.rename(columns={'姓名': '姓--名','性别': '性--别'},inplace=True)
# 4.3 批量更改索引
df.rename(lambda x: x + 10)
# 4.4 批量更改列名
df.rename(columns=lambda x: x + '_1')
# 4.5 设置姓名列为行索引
df.set_index('姓名')
# 4.6 检查哪些列包含缺失值
df.isnull().any()
# 4.7 统计各列空值
df.isnull().sum()
# 4.8 删除本列中空值的行
df[df['数学'].notnull()]
df[~df['数学'].isnull()]
# 4.9 仅保留本列中是空值的行
df[df['数学'].isnull()]
df[~df['数学'].notnull()]
# 4.10 去掉某行
df.drop(0, axis=0)
# 4.11 去掉某列
df.drop('英语', axis=1)
# 4.12 删除所有包含空值的行
df.dropna()
# 4.13 删除行里全都是空值的行
df.dropna(how = 'all')
# 4.14 删除所有包含空值的列
df.dropna(axis=1)
# 4.15 保留至少有6个非空值的行
df.dropna(thresh=6)
# 4.16 保留至少有11个非空值的列
df.dropna(axis=1,thresh=11)
# 4.17 行数据向下填充
df.fillna(method = 'ffill')
# 4.18 列数据向右填充
df.fillna(method = 'ffill',axis=1)
# 4.19 用0替换所有的空值
df.fillna(0)
# 4.20 强制转换数据类型
df_t1 = df.dropna()
df_t1['语文'].astype('int')
# 4.21 查看有多少不同的城市
df['城市'].unique()
# 4.22 单值替换
df.replace('苏州', '南京')
# 4.23 多值替换
df.replace({'苏州':'南京','广州':'深圳'})
df.replace(['苏州','广州'],['南京','深圳'])
# 4.24 多值替换单值
df.replace(['深圳','广州'],'东莞')
# 4.25 替换某列,显示需要加inplace=True
df['城市'] = df['城市'].replace('苏州', '南京')
# 4.26 拆分某列,生成新的Dataframe
df1 = df['姓名'].str.split('-',expand=True)
df1.columns = ['学号','姓名']
# 4.27 某一列类型转换,注意该列类型要一致,包括(NaN)
df1.dropna(inplace = True)
df1['语文'] = df1['语文'].apply(int)
5. 数据切片、筛选
# 5.1 输出城市为上海
df[df['城市']=='上海']
# 5.2 输出城市为上海或广州
df[df['城市'].isin(['上海','广州'])]
# 5.3 输出城市名称中含有‘海’字的行
df[df['城市'].str.contains("海", na=False)]
# 5.4 输出城市名称以‘海’字开头的行
df[df['城市'].str.startswith("海", na=False)]
# 5.5 输出城市名称以‘海’字结尾的行
df[df['城市'].str.endswith("海", na=False)]
# 5.6 输出所有姓名,缺失值用Null填充
df['姓名'].str.cat(sep='、',na_rep='Null')
# 5.7 重置索引
df2 = df1.set_index('学号')
# 5.8 前两行
df2[:2]
# 5.9 后两行
df2[-2:]
# 5.10 2-8行
df2[2:8]
# 5.11 每隔3行读取
df2[::3]
# 5.12 2-8行,步长为2,即第2/4/6行
df2[2:8:2]
# 5.13 选取'语文','数学','英语'列
df2[['语文','数学','英语']]
# df.loc[]只能使用标签索引,不能使用整数索引,通过便签索引切边进行筛选时,前闭后闭
# 5.14 学号为'001'的行,所有列
df2.loc['001', :]
# 5.15 学号为'001'或'003'的行,所有列
df2.loc[['001','003'], :]
# 5.16 学号为'001'至'009'的行,所有列
df2.loc['001':'009', :]
# 5.17 列索引为'姓名',所有行
df2.loc[:, '姓名']
# 5.18 列索引为'姓名'至‘城市’,所有行
df2.loc[:, '姓名':'城市']
# 5.19 语文成绩大于80的行
df2.loc[df2['语文']>80,:]
df2.loc[df2.loc[:,'语文']>80, :]
df2.loc[lambda df2:df2['语文'] > 80, :]
# 5.20 语文成绩大于80的人的学号和姓名
df2.loc[df2['语文']>80,['姓名','城市']]
# 5.21 输出'赵四'和'周七'的各科成绩
df2.loc[df2['姓名'].isin(['赵四','周七']),['姓名','语文','数学','英语']]
# # df.iloc[]只能使用整数索引,不能使用标签索引,通过整数索引切边进行筛选时,前闭后开
# 5.22 选取第2行
df2.iloc[1, :]
# 5.23 选取前3行
df2.iloc[:3, :]
# 5.24 选取第2行、第4行、第6行
df2.iloc[[1,3,5],:]
# 5.25 选取第2列
df2.iloc[:, 1]
# 5.26 选取前3列
df2.iloc[:, 0:3]
# 5.27 选取第3行的第3列
df2.iloc[3, 3]
# 5.28 选取第1列、第3列和第4列
df2.iloc[:, [0,2,3]]
# 5.29 选取第2行的第1列、第3列、第4列
df2.iloc[1, [0,2,3]]
# 5.30 选取前3行的前3列
df2.iloc[:3, :3]
6. 数据排序
# 6.1 重置索引
df_last = df1.reset_index(drop=True)
# 6.2 按照语文成绩升序排序,默认升序排列
df_last.sort_values('语文')
# 6.3 按照数学成绩降序排序
df_last.sort_values('数学', ascending=False)
# 6.4 先按语文成绩升序排列,再按数学成绩降序排列
df_last.sort_values(['语文','数学'], ascending=[True,False])
# 6.5 语文成绩80及以上
df_last[df_last['语文']>=80]
df_last.query('语文 > 80')
# 6.6 语文成绩80及以上以及数学成绩90分及以上
df_last[(df_last['语文']>=80) & (df_last['数学']>=90)]
# 6.7 语文成绩80及以上或数学成绩90分及以上
df_last[(df_last['语文']>=80) | (df_last['数学']>=90)]
# 6.8 输出成绩100的行和列号
row, col = np.where(df_last.values == 100)
# 6.9 增加一列“省份-城市”
df_last['省份-城市'] = df_last['省份'] + '-' + df_last['城市']
# 6.10 增加一列总分
df_last['总分'] = df_last[['语文','数学','英语']].sum(axis = 1)
# 6.11 按照总分、语文、数学、英语成绩依次排序
df_last.sort_values(by =['总分','语文','数学','英语'],ascending=False )
# 6.12 新增一列表示学生语文成绩等级的列(优秀、良好、中等、不及格)
def get_letter_grade(score):
'''
定义一个函数,根据分数返回相应的等级
'''
if score>=90:
return '优秀'
elif score>=80:
return '良好'
elif score>=60:
return '中等'
else:
return '不及格'
df_last['语文等级'] = df_last['语文'].apply(lambda score: get_letter_grade(score))
7. 数据分组
# 7.1 一列分组
df2.groupby('省份').groups
# 7.2 多列分组
df2.groupby(['省份','城市']).groups
# 7.3 每组的统计数据(横向显示)
df2.groupby('省份').describe()
# 7.4 每组的统计数据(纵向显示)
df2.groupby('省份').describe().unstack()
# 7.5 查看指定列的统计信息
df2.groupby('省份').describe()['语文']
# 7.6 分组大小
df2.groupby('省份').count()
df2.groupby('省份').agg(np.size)
# 7.7 分组成绩最大值
df2.groupby('省份').max()
df2.groupby('省份').agg(np.max)
# 7.8 分组成绩最小值
df2.groupby('省份').min()
df2.groupby('省份').agg(np.min)
# 7.9 分组成绩总和
df2.groupby('省份').sum()
df2.groupby('省份').agg(np.sum)
# 7.10 分组平均成绩
df2.groupby('省份').mean()
df2.groupby('省份').agg(np.mean)
# 7.11 按省份分组,计算英语成绩总分和平均分
df2.groupby('省份')['英语'].agg([np.sum, np.mean])
# 7.12 按省份、城市分组计算平均成绩
df2.groupby(['省份','城市']).agg(np.mean)
# 7.13 不同列不同的计算方法
df2.groupby('省份').agg({'语文': sum, # 总和
'数学': 'count', # 总数
'英语':'mean'}) # 平均
# 7.14 性别分别替换为1/0
df2 = df2.dropna()
df2['性别'] = df2['性别'].map({'男':1, '女':0})
# 7.15 增加一列按省份分组的语文平均分
df2['语文平均分'] = df2.groupby('省份')['语文'].transform('mean')
# 7.16 输出语文成绩最高的男生和女生(groupby默认会去掉空值)
def get_max(g):
df = g.sort_values('语文',ascending=True)
print(df)
return df.iloc[-1,:]
df2.groupby('性别').apply(get_max)
# 7.17 按列省份、城市进行分组,计算语文、数学、英语成绩最大值的透视表
df.pivot_table(index=['省份','城市'], values=['语文','数学','英语'], aggfunc=max)
8. 数据统计
# 8.1 数据汇总统计
df.describe()
# 8.2 列中非空值的个数
df.count()
# 8.3 列最小值
df.min()
# 8.4 列最大值
df.max()
# 8.5 列均值
df.mean()
# 8.6 列中位数
df.median()
# 8.7 列与列之间的相关系数
df.corr()
# 8.8 列的标准差
df.std()
# 8.9 语文成绩指标
# 对语文列求和
sum0 = df_last['语文'].sum()
# 语文成绩方差
var = df_last['语文'].var()
# 语文成绩标准差
std = df_last['语文'].std()
# 语文平均分
mean = df_last['语文'].mean()
print('语文总分:',sum0)
print('语文平均分:',mean)
print('语文成绩标准差:',std)
print('语文成绩方差:',var)
# 8.10 三个科目的指标
mean = df_last[['语文','数学','英语']].mean()
var = df_last[['语文','数学','英语']].var()
total = df_last[['语文','数学','英语']].sum()
std = df_last[['语文','数学','英语']].std()
rows = [total,mean,var,std]
# 索引列表
index = ['总分','平均分','方差','标准差']
# 根据指定索引和行构造 DataFrame 对象
df_tmp = pd.DataFrame(rows,index=index)
9. 表格样式
# 9.1 示例数据
df = pd.read_csv(filename, encoding='gbk')
# 9.2 列重命名
df.columns = ['姓名','性别','语文','数学','英语','城市','省份']
# 9.3 设置空值背景红色
df.style.highlight_null(null_color = 'red')
# 9.4 最大数据高亮
df.style.highlight_max()
# 9.5 最小数据高亮
df.style.highlight_min()
# 9.6 部分列最大数据高亮
df.style.apply(highlight_max, subset=['语文', '数学'])
# 9.7 部分列数据高亮(Dataframe全为数据)
df3 = df[['语文','数学','英语']]
def highlight_max(s):
is_max = s == s.max()
return ['background-color: yellow' if v else '' for v in is_max]
df3.style.apply(highlight_max)
# 9.8 95分以上显示红色
def color_negative_red(val):
color = 'red' if val > 95.0 else 'black'
return 'color: %s' % color
df3.style.applymap(color_negative_red)
# 9.9 混合
df3.style.applymap(color_negative_red).apply(highlight_max)
# 9.10 设置float类型列数据大于80.0的背景高亮
yellow_css = 'background-color: yellow'
sfun = lambda x: yellow_css if type(x) == float and x > 80.0 else ''
df3.style.applymap(sfun)
# 9.11 设置数学成绩大于80.0分的行背景高亮
yellow_css = 'background-color: yellow'
sfun = lambda x: [yellow_css]*len(x) if x.数学 > 80.0 else ['']*len(x)
df3.style.apply(sfun, axis=1)
# 9.12 设置数学成绩大于95.0的行数据颜色为红色
def row_color(s):
if s.数学 > 95:
return ['color: red']*len(s)
else:
return ['']*len(s)
df3.style.apply(row_color, axis=1)
# 9.13 显示热度图
import seaborn as sns
cm = sns.light_palette("green", as_cmap=True)
df3.style.background_gradient(cmap=cm)