一、Pandas简介
Pandas是使用Python语言开发的用于数据处理和数据分析的第三方库。它擅长处理数字型数据和时间序列数据,当然文本型的数据也能轻松处理。
作为Python的三方库,Pandas是建构在Python的基础上的,它封装 了一些复杂的代码实现过程,我们只要调用它的方法就能轻松实现我们的需求。
Pandas参考文档:https://pandas.pydata.org/docs/
Pandas的基本功能
Pandas常用的基本功能如下:
- 从Excel、CSV、网页、SQL、剪贴板等文件或工具中读取数据;
- 合并多个文件或者电子表格中的数据,将数据拆分为独立文件;
- 数据清洗,如去重、处理缺失值、填充默认值、补全格式、处理 极端值等;
- 建立高效的索引;
- 支持大体量数据;
- 按一定业务逻辑插入计算后的列、删除列;
- 灵活方便的数据查询、筛选;
- 分组聚合数据,可独立指定分组后的各字段计算方式;
- 数据的转置,如行转列、列转行变更处理;
- 连接数据库,直接用SQL查询数据并进行处理;
- 对时序数据进行分组采样,如按季、按月、按工作小时,也可以 自定义周期,如工作日;
- 窗口计算,移动窗口统计、日期移动等;
- 灵活的可视化图表输出,支持所有的统计图形;
- 为数据表格增加展示样式,提高数据识别效率。
二、Pandas快速入门
简要概括一下利用 Pandas可以做些什么
1、读取数据
读取Excel文件read_excel
import pandas as pd # 引入Pandas并起别名
df = pd.read_excel('team.xlsx') # 如果Excel文件与.py文件在同一目录下,可以写相对路径
print(df)
读取CSV文件read_csv
import pandas as pd # 引入Pandas并起别名
df = pd.read_csv('team.csv')
print(df)
例子
使用了文件 https://www.gairuo.com/file/data/dataset/team.xlsx
name team Q1 Q2 Q3 Q4
0 Liver E 89 21 24 64
1 Arry C 36 37 37 57
2 Ack A 57 60 18 84
3 Eorge C 93 96 71 78
4 Oah D 65 49 61 86
.. ... ... .. .. .. ..
95 Gabriel C 48 59 87 74
96 Austin7 C 21 31 30 43
97 Lincoln4 C 98 93 1 20
98 Eli E 11 74 58 91
99 Ben E 21 43 41 74
[100 rows x 6 columns]
其中:
- 自动增加了第一列,是Pandas为数据增加的索引,从0开始,程 序不知道我们真正的业务索引,往往需要后面重新指定,使它有 一定的业务意义;
- 由于数据量大,自动隐藏了中间部分,只显示前后5条;
- 底部显示了行数和列数。
2、查看数据
# 查看前5条,括号里可以写明你想看的条数
print(df.head())
print(df.head(3))
# 查看尾部5条数据,括号里可以写明你想看的条数
print(df.tail())
# 随机查看5条
print(df.sample(5))
3、验证数据
拿到数据,我们还需要验证一下数据是否加载正确,数据大小是否正常。
df.shape # (100, 6) 查看行数和列数
df.info() # 查看索引、数据类型和内存信息
df.describe() # 查看数值型列的汇总统计
df.dtypes # 查看各字段类型
df.axes # 显示数据行和列名
df.columns # 列名
df.info()显示有数据类型、索引情况、行列数、各字段数据类型、 内存占用等
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 100 non-null object
1 team 100 non-null object
2 Q1 100 non-null int64
3 Q2 100 non-null int64
4 Q3 100 non-null int64
5 Q4 100 non-null int64
dtypes: int64(4), object(2)
memory usage: 4.8+ KB
None
df.describe()会计算出各数字字段的总数(count)、平均数 (mean)、标准差(std)、最小值(min)、四分位数和最大值 (max)
Q1 Q2 Q3 Q4
count 100.000000 100.000000 100.000000 100.000000
mean 49.200000 52.550000 52.670000 52.780000
std 29.962603 29.845181 26.543677 27.818524
min 1.000000 1.000000 1.000000 2.000000
25% 19.500000 26.750000 29.500000 29.500000
50% 51.500000 49.500000 55.000000 53.000000
75% 74.250000 77.750000 76.250000 75.250000
max 98.000000 99.000000 99.000000 99.000000
4、建立索引
以上数据真正业务意义上的索引是name列,所以我们需要使它成为索引
df.set_index('name', inplace=True) # 建立索引并生效
其中可选参数inplace=True会将指定好索引的数据再赋值给df使索引生效,否则索引不会生效。注意,这里并没有修改原Excel,从我们读取数据后就已经和它没有关系了,我们处理的是内存中的df变量。
5、数据选取
- 查看指定列
# 查看指定列
df['Q1']
df.Q1 # 同上,如果列名符合Python变量名要求,可使用
这里返回的是一个Series类型数据,可以理解为数列,它也是带索引的。之前建立的索引在这里发挥出了作用,否则我们的索引是一个数字,无法知道与之对应的是谁的数据。
0 89
1 36
2 57
3 93
4 65
..
95 48
96 21
97 98
98 11
99 21
Name: Q1, Length: 100, dtype: int64
- 查看多列
# 选择多列
df[['team', 'Q1']] # 只看这两列,注意括号
df.loc[:, ['team', 'Q1']] # 和上一行效果一样
df.loc[x, y]是一个非常强大的数据选择函数,其中x代表行,y代表列,行和列都支持条件表达式,也支持类似列表那样的切片(如果要用 自然索引,需要用df.iloc[])。
- 查看行
# 用指定索引选取
df[df.index == 'Liver'] # 指定姓名
# 用自然索引选择,类似列表的切片
df[0:3] # 取前三行
df[0:10:2] # 在前10个中每两个取一个
df.iloc[:10,:] # 前10个
- 查看某行某列
df.loc['Ben', 'Q1':'Q4'] # 只看Ben的四个季度成绩
df.loc['Eorge':'Alexander', 'team':'Q4'] # 指定行区间
- 条件查询
# 单一条件
df[df.Q1 > 90] # Q1列大于90的
df[df.team == 'C'] # team列为'C'的
df[df.index == 'Oscar'] # 指定索引即原数据中的name
# 组合条件
df[(df['Q1'] > 90) & (df['team'] == 'C')] # and关系
df[df['team'] == 'C'].loc[df.Q1>90] # 多重筛选
6、排序
df.sort_values(by='Q1') # 按Q1列数据升序排列
df.sort_values(by='Q1', ascending=False) # 降序
df.sort_values(['team', 'Q1'], ascending=[True, False]) # team升序,Q1降序
7、分组聚合
df.groupby('team').sum() # 按团队分组对应列相加
df.groupby('team').mean() # 按团队分组对应列求平均
# 不同列不同的计算方法
df.groupby('team').agg({'Q1': sum, # 总和
'Q2': 'count', # 总数
'Q3':'mean', # 平均
'Q4': max}) # 最大值
8、数据转换
df.groupby('team').sum().T
df.groupby('team').sum().stack()
df.groupby('team').sum().unstack()
9、增加列
df['one'] = 1 # 增加一个固定值的列
df['total'] = df.Q1 + df.Q2 + df.Q3 + df.Q4 # 增加总成绩列
# 将计算得来的结果赋值给新列
df['total'] = df.loc[:,'Q1':'Q4'].apply(lambda x:sum(x), axis=1)
df['total'] = df.sum(axis=1) # 可以把所有为数字的列相加
df['avg'] = df.total/4 # 增加平均成绩列
10、统计分析
df.mean() # 返回所有列的均值
df.mean(1) # 返回所有行的均值,下同
df.corr() # 返回列与列之间的相关系数
df.count() # 返回每一列中的非空值的个数
df.max() # 返回每一列的最大值
df.min() # 返回每一列的最小值
df.median() # 返回每一列的中位数
df.std() # 返回每一列的标准差
df.var() # 方差
s.mode() # 众数
11、绘图
Pandas利用plot()调用Matplotlib快速绘制出数据可视化图形。注意,第一次使用plot()时可能需要执行两次才能显示图形。如图1-13所 示,可以使用plot()快速绘制折线图。
df['Q1'].plot() # Q1成绩的折线分布
这部分是重点,需要配合 matplotlib 模块使用
12、导出
df.to_excel('team-done.xlsx') # 导出 Excel文件
df.to_csv('team-done.csv') # 导出 CSV文件
三、NumPy
NumPy(官网https://numpy.org)是Python的科学计算包,代表 Numeric Python。NumPy是Python中科学计算的基本软件包。它是一个 Python库,提供多维数组对象以及蒙版数组和矩阵等各种派生对象,用 于对数组进行快速便捷的操作,包括数学、逻辑、形状处理、排序、选 择、I/O、离散傅立叶变换、基本线性代数、基本统计运算、随机模拟 等。可以说,NumPy是数据科学中必不可少的工具。 由于NumPy对数据进行向量化描述,没有任何显式的循环操作,所 以执行速度更快,代码更加简洁优雅,出错率更低。NumPy提供了两个 基本的对象。
- ndarray:存储数据的多维数组
- ufunc:对数组进行处理的函数
1、创建数据
使用NumPy需要先导入,约定俗成地为它起别名np。使用np.array 可传入一个元组或列表。如果是二维数据,可以是由列表组成的列表或 由元组组成的列表等形式。
- 创建一维数据
import numpy as np # 导入numpy 模块并起别名
arr1 = np.array([1,2,3,4]) # 传入列表
arr2 = np.array((1,2,3,4)) # 传入元组
print(arr2)
[1 2 3 4]
- 创建二维数据
arr1 = np.array([[1,2,3,4],[5,6,7,8]]) # 列表嵌套列表
arr2 = np.array(([1,2,3,4],[5,6,7,8])) # 元组嵌套列表
arr3 = np.array(((1,2,3,4),(5,6,7,8))) # 元组嵌套元组
print(arr3)
[[1 2 3 4]
[5 6 7 8]]
- 常用的数据生成函数
np.arange(10) # 10个,不包括10,步长为1, 0-9
np.arange(3, 10, 0.1) # 从3到9,步长为0.1
# 从2.0到3.0,生成均匀的5个值,不包括终值3.0
np.linspace(2.0, 3.0, num=5, endpoint=False)
# 返回一个6×4的随机数组,浮点型
np.random.randn(6, 4)
# 指定范围、指定形状的数组,整型
np.random.randint(3, 7, size=(2, 4))
# 创建值为0的数组
np.zeros(6) # 6个浮点0.
np.zeros((5, 6), dtype=int) # 5×6整型0
np.ones(4) # 同上
np.empty(4) # 同上
# 创建一份和目标结构相同的0值数组
np.zeros_like(np.arange(6))
np.ones_like(np.arange(6)) # 同上
np.empty_like(np.arange(6)) # 同上
2、数据类型
np.int64 # 有符号64位整型
np.float32 # 标准双精度浮点类型
np.complex # 由128位的浮点数组成的复数类型
np.bool # bool类型(True或False)
np.object # Python中的object类型
np.string # 固定长度的string类型
np.unicode # 固定长度的unicode类型
np.NaN # np.float的子类型
np.nan
3、数组信息
n.shape() # 数组的形状,返回值是一个元组
n.shape = (4, 1) # 改变形状
a = n.reshape((2,2)) # 改变原数组的形状,创建一个新数组
n.dtype # 数据类型
n.ndim # 维度数
n.size # 元素数
np.typeDict # np的所有数据类型
4、统计计算
两个数组之间采用行列式的运算规则
np.array([10, 20, 30, 40])[:3] # 支持类似列表的切片
a = np.array([10, 20, 30, 40])
b = np.array([1, 2, 3, 4])
a+b # array([11, 22, 33, 44])(矩阵相加)
a-1 # array([9, 19, 29, 39])
4*np.sin(a)
# 以下是一些数学函数的例子,还支持非常多的数学函数
a.max() # 40
a.min() # 10
a.sum() # 100
a.std() # 11.180339887498949
a.all() # True
a.cumsum() # array([10, 30, 60, 100])
b.sum(axis=1) # 多维可以指定方向
由于Pandas调试依赖NumPy库,我们需要了解基础的NumPy数据类型和操作。不过不用担心,Pandas已经帮助我们封装好了各种计算,可以等到遇到涉及NumPy底层功能的内容时,再来学习查询。
四、Pandas的数据结构
Pandas提供Series和DataFrame作为数组数据的存储框架,数据进入这两种框架后,我们就可以利用它们提供的强大处理方法进行处理。
1、Series
Series(系列、数列、序列)是一个带有标签的一维数组,这一系列连续的数据代表了一定的业务意义。
例如以下数据
中国 14.34
美国 21.43
日本 5.08
dtype: float64
其中,国家是标签(也称索引),不是具体的数据,它起到解释、 定位数据的作用。如果没有标签,只有一个数字,是不具有业务意义 的。Series是Pandas最基础的数据结构。
2、DataFrame
DataFrame意为数据框,它就像一个存放数据的架子,有多行多 列,每个数据在一个格子里,每个格子有自己的编号。
- 横向的称作行(row),我们所说的一条数据就是指其中的一 行;
- 纵向的称作列(column)或者字段,是一条数据的某个值;
- 第一行是表头,或者叫字段名,类似于Python字典里的键,代表数据的属性;
- 第一列是索引,就是这行数据所描述的主体,也是这条数据的关键;
- 在一些场景下,表头和索引也称为列索引和行索引;
- 行索引和列索引可能会出现多层索引的情况(后面会遇到)。
人口 GDP
中国 13.97 14.34
美国 3.28 21.43
日本 1.26 5.08
这就是一个典型的DataFrame结构,其中:
- 共有三行两列(不包含索引)数据;
- 国家所在列是这个表的索引,每一行数据的主体为这个国家;
- 每条数据(横向)有两个值,分别是人口和GDP。
3、索引
在后续的内容中,在不同场景下可能会对索引使用以下名称。
- 索引(index):行和列上的标签,标识二维数据坐标的行索引和列索引,默认情况下,指的是每一行的索引。如果是Series, 那只能是它行上的索引。列索引又被称为字段名、表头。
- 自然索引、数字索引:行和列的0~n(n为数据长度–1)形式的 索引,数据天然具有的索引形式。虽然可以指定为其他名称,但 在有些方法中依然可以使用。
- 标签(label):行索引和列索引,如果是Series,那只能是它行 上的索引。
- 轴(axis):仅用在DataFrame结构中,代表数据的方向,如行和列,用0代表列(默认),1代表行。
4、生成Series
Series是一个带有标签的一维数组,这个数组可以由任何类型数据构成,包括整型、浮点、字符、Python对象等。它的轴标签被称为索引,它是Pandas最基础的数据结构。 Series的创建方式如下:
s = pd.Series(data, index=index)
data可以是Python对象、NumPy的ndarray、一个标量(定值,如 8)。index是轴上的一个列表,必须与data的长度相同,如果没有指定,则自动从0开始,表示为[0, …, len(data)–1]。
(1)使用列表和元组
列表和元组可以直接放入pd.Series():
s1 = pd.Series([1,2,3,4,5])
s2 = pd.Series(('a','b','c','d','e'))
print(s1)
print(s2)
0 1
1 2
2 3
3 4
4 5
dtype: int64
0 a
1 b
2 c
3 d
4 e
dtype: object
(2)使用ndarray
使用NumPy的ndarray结构:
s3 = pd.Series(np.random.randn(5), index=['a','b','c','d','e']) # 由索引分别为a、b、c、d、e的5个随机浮点数数组组成
s4 = pd.Series(np.random.randn(5)) # 未指定索引,使用默认的索引
print(s3)
print(s4)
(3)使用字典
使用Python的字典数据:
s5 = pd.Series({'a':1, 'b':2, 'c':3})
print(s5)
a 1
b 2
c 3
dtype: int64
如果指定索引,则会按索引顺序,如有无法与索引对应的值,会产生缺失值NaN
s5 = pd.Series({'a':1, 'b':2, 'c':3}, index = ['b','a','c','d','e'])
print(s5)
a 1.0
c 3.0
d NaN
e NaN
dtype: float64
(4)使用标量
对于一个具体的值,如果不指定索引,则其长度为1;如果指定索 引,则其长度为索引的数量,每个索引的值都是它。
s6 = pd.Series(5)
print(s6)
0 5
dtype: int64
s6 = pd.Series(5, index = ['a','b','c'])
print(s6)
a 5
b 5
c 5
dtype: int64
5、生成DataFrame
DataFrame是二维数据结构,数据以行和列的形式排列,表达一定的数据意义。DataFrame的形式类似于CSV、Excel和SQL的结果表,有多个数据列,由多个Series组成。 DataFrame最基本的定义格式如下:
df = pd.DataFrame(data=None, index=None, columns=None)
以下是其各参数的说明。
- data:具体数据,结构化或同构的ndarray、可迭代对象、字典或 DataFrame。
- index:索引,类似数组的对象,支持解包,如果没有指定,会 自动生成RangeIndex (0, 1, 2, …, n)。
- columns:列索引、表头,如果没有指定,会自动生成 RangeIndex (0, 1, 2, …, n)。
此外还可以用dtype指定数据类型,如果未指定,系统会自动推断。 大多数情况下,我们是从数据文件(如CSV、Excel)中取得数 据,不过,了解这部分知识可以让我们更好地理解DataFrame的数据机制。
(1)使用字典
字典中的键为列名,值一般为一个列表或者元组,是具体数据
可以使用 index来指定索引
s1 = pd.DataFrame({'county':['china','USA','UK'],
'people':[14,3,0.7]})
print(s1)
county people
0 china 14.0
1 USA 3.0
2 UK 0.7
(2)Series组成的字典
这是一种非常典型的构造数据的方法,字典里的一个键值对为一列 数据,键为列名,值是一个Series。
d = {'x': pd.Series([1, 2, 3], index=['a', 'b', 'c']),
'y': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)
x y
a 1.0 1.0
b 2.0 2.0
c 3.0 3.0
d NaN 4.0
(3)字典组成的列表
由字典组成一个列表,每个字典是一行数据,指定索引后会使用指定的索引。
d = [{'x':1,'y':2,'z':3},{'x':4,'y':7}]
print(pd.DataFrame(d))
x y z
0 1 2 3.0
1 4 7 NaN
(4)Series生成
一个Series会生成只有一列的DataFrame
d = [1,2,3,4,5]
print(pd.DataFrame(d))
0
0 1
1 2
2 3
3 4
4 5
6、常见数据类型
Pandas提供了以下常见的数据类型,默认的数据类型是int64和 float64,文字类型是object。
- float
- int
- bool
- datetime64[ns]
- datetime64[ns, tz]
- timedelta64[ns]
- timedelta[ns]
- category
- object
- string
这些数据类型大多继承自NumPy的相应数据类型,Pandas提供了可以进行有限的数据类型转换的方法,如将数字型转为字符型。
数据检测
可以使用类型判断方法检测数据的类型是否与该方法中指定的类型 一致,如果一致,则返回True,注意传入的是一个Series
pd.api.types.is_bool_dtype(s)
pd.api.types.is_categorical_dtype(s)
pd.api.types.is_datetime64_any_dtype(s)
pd.api.types.is_datetime64_ns_dtype(s)
pd.api.types.is_datetime64_dtype(s)
pd.api.types.is_float_dtype(s)
pd.api.types.is_int64_dtype(s)
pd.api.types.is_numeric_dtype(s)
pd.api.types.is_object_dtype(s)
pd.api.types.is_string_dtype(s)
pd.api.types.is_timedelta64_dtype(s)
五、Pandas数据读取与输出
1、数据读取
(1)CSV文件
CSV(Comma-Separated Values)是用逗号分隔值的数据形式,有 时也称为字符分隔值,因为分隔字符也可以不是逗号。CSV文件的一般 文件扩展名为.csv,用制表符号分隔也常用.tsv作为扩展名。CSV不仅可 以是一个实体文件,还可以是字符形式,以便于在网络上传输。
# 文件目录
pd.read_csv('data.csv') # 如果文件与代码文件在同一目录下
pd.read_csv('data/my/data.csv') # 指定目录
pd.read_csv('data/my/my.data') # CSV文件的扩展名不一定是.csv
CSV不带数据样式,标准化较强,是最为常见的数据格式
(2)Excel文件
Pandas可以读取、处理大体量的数据,通过技术手段,理论上 Pandas可以处理的数据体量无限大。编程可以更加自由地实现复杂的逻 辑,逻辑代码可以进行封装、重复使用并可实现自动化。
# 返回DataFrame
pd.read_excel('team.xlsx') # 默认读取第一个标签页Sheet
pd.read_excel('path_to_file.xlsx', sheet_name='Sheet1') # 指定Sheet
# 从URL读取
pd.read_excel('https://www.gairuo.com/file/data/dataset/team.xls
(3)JSON文件
JSON是互联网上非常通用的轻量级数据交换格式,是HTTP请求中 数据的标准格式之一。Pandas提供的JSON读取方法在解析网络爬虫数据时,可以极大地提高效率。
# data.json为同目录下的一个文件
pd.read_json('data.json')
Pandas还提供了pd.json_normalize(data)方法来读取半结构化的JSON 数据。
(4)HTML
pd.read_html()函数可以接受HTML字符串、HTML文件、URL,并 将HTML中的标签表格数据解析为DataFrame。如返回有多个df的 列表,则可以通过索引取第几个。如果页面里只有一个表格,那么这个列表就只有一个DataFrame。此方法是Pandas提供的一个简单实用的实现爬虫功能的方法。
# id='table'的表格,注意这里仍然可能返回多个
dfs1 = pd.read_html(url, attrs={'id': 'table'})
# dfs1[0]
# class='sortable'
dfs2 = pd.read_html(url, attrs={'class': 'sortable'})
dfs = pd.read_html('https://www.gairuo.com/p/pandas-io')
dfs[0] # 查看第一个df
# 读取网页文件,第一行为表头
dfs = pd.read_html('data.html', header=0)
# 第一列为索引
dfs = pd.read_html(url, index_col=0)
pandas还支持读取数据库中的数据,这里不做介绍。