应对期末考试,对本学期《Python 数据分析与应用》课程学习的内容进行复习。


# 第三章、pandas 统计分析基础

章节考点:

(1)Pandas 作用

(2)重复值、缺失值处理函数及方法

(3)Pandas 数据结构及特点

(4)读写 CSV 数据的相关函数

(5)数据合并

# 1. 读 / 写不同数据源的数据

# 1)认识 pandas 库

pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据(数值型、文本型、时间序列)。

pandas 建造在 NumPy 之上,所以使得 pandas 在以 NumPy 为中心的应用中得以容易的使用,而 pandas 库在与其它第三方科学计算支持库结合时也能够完美的进行集成。

在 Python 中,pandas 库的功能十分强大,它可提供高性能的矩阵运算。

  • 可用于数据挖掘和数据分析,同时也提供数据清洗功能;
  • 支持类似 SQL 的数据增、删、查、改,并且带有丰富的数据处理函数;
  • 支持时间序列分析功能;支持灵活处理缺失数据等。

# 2)Pandas 数据结构

pandas 有两个强大的利器

  • Series(一维数据)是一种类似于一维数组的对象,是由一组数据(各种 NumPy 数据类型)以及一组与之相关的数据标签(即索引)组成,而仅由一组数据也可产生简单的 Series 对象。

    Series

  • DataFrame 是 pandas 中的一个表格型的数据结构,包含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型等),DataFrame 既有行索引也有列索引,可以被看做是由 Series 组成的字典。

    DataFrame

# ①Series 对象

pandas.Series( data, index, dtype, copy)

说明:data 可以是标量、列表、迭代对象、字典、ndarray 等对象。

import pandas as pd
import numpy as np
s1 = pd.Series(5,index=[1,2,3,4],dtype='str')  #标量,设置了索引与类型
print(s1)
s2 = pd.Series([10,20,30,40])  #列表
print(s2)
s3 = pd.Series(range(10,20))  #迭代对象
print(s3)
s4 = pd.Series({'a':'H1','b':'H2','c':'H3'})  #字典,键为索引
print(s4)
s5 = pd.Series(np.array(['x','y','z']))    #ndarray
print(s5)
# 输出结果:
1    5
2    5
3    5
4    5
dtype: object
0    10
1    20
2    30
3    40
dtype: int64
0    10
1    11
2    12
3    13
4    14
5    15
6    16
7    17
8    18
9    19
dtype: int64
a    H1
b    H2
c    H3
dtype: object
0    x
1    y
2    z
dtype: object

Series 属性:

  • axes:以列表的形式返回所有行索引标签
  • dtype:返回对象的数据类型。
  • empty:返回一个布尔值,判断数据对象是否为空
  • ndim:返回输入数据的维数
  • size:返回输入数据的元素数量
  • values:以 ndarray 的形式返回 Series 对象
  • index:返回一个索引的取值

Series 查询操作

使用索引、切片方式

import pandas as pd
info = {'name':'张三','age':20,'tel':'13500100203','hobby':'上网,打游戏,运动'}
sd = pd.Series(info)
print(sd['tel'])
print(sd[1:4])
print(sd[[2,3]])

# ②DataFrame 对象

Pd.DataFrame(data, index, columns, dtype, copy) 
#构造 DataFrame 数据框架

说明:(1)从列表、字典、ndarray 等对象转化为 DataFrame。

import pandas as pd
info = {'name':'张三','age':20,'tel':'13500100203','hobby':'上网,打游戏,运动'}
sd = pd.Series(info)
df1 = pd.DataFrame(sd)
df2 = pd.DataFrame(info,columns=['name','age','tel','hobby'],index=[0])
print(df1)
print(df2)

DataFrame 属性:

  • values:DataFrame 所有行的值
  • index:DataFrame 行索引
  • colums:DataFrame 列名
  • dtypes:DataFrame 指定列数据类型
  • size:DataFrame 元素的个数
  • ndim:DataFrame 维度
  • shape:DataFrame 形状
  • T: 实现 DataFrame 转置

# 2)读 / 写文件

# ①文本文件读取

CSV 文件根据其定义也是一种文本文件。在数据读取过程中可以使用文本文件的读取函数对 CSV 文件进行读取。同时,如果文本文件是字符分隔文件,那么可以使用读取 CSV 文件的函数进行读取。

pandas 提供了 read_table () 函数读取文本文件,提供了 read_csv () 函数读取 CSV 文件。

read_table () 函数和 read_csv () 函数具有许多参数,如果有多个 < expression >,那么表达式之间用逗号隔开,基本使用格式如下。

pandas.read_table(filepath_or_buffer, sep=<no_default>, header='infer', names=<no_default>, index_col=None, dtype=None,  engine=None, nrows=None, skiprows=None)
pandas.read_csv(filepath_or_buffer, sep=<no_default>, header='infer', names=<no_default>, index_col=None, dtype=None,  engine=None, nrows=None, skiprows=None)

read_table () 函数和 read_csv () 函数的多数参数相同,它们的常用参数及其说明如下表:

参数名称参数说明
filepath接收 str。表示文件路径。无默认值
sep接收 str。表示分隔符。read_csv 函数默认为 “,”,read_table 函数默认为制表符 “Tab”
header接收 int 或列表形式的 int。表示将某行数据作为列名。默认为 infer
names接收 array。表示列名。无默认值
index_col接收 int、sequence 或 False。表示索引列的位置,取值为 sequence 则代表多重索引。默认为 None

read_table () 函数和 read_csv () 函数的多数参数相同,它们的常用参数及其说明如下表:

参数名称参数说明
dtype接收字典形式的列名或 type name。表示写入的数据类型(列名为 key,数据格式为 values)。默认为 None
engine接收 c 语言或 python 语言。表示要使用的数据解析引擎。默认为 None
nrows接收 int。要读取的文件行数。默认为 None
skiprows接收 list 或 int 或 callable。表示读取数据时跳过开头的行数。默认为 None

read_csv 和 read_table 之间的区别:

函数 pd.read_csv 和 pd.read_table 的内容相同,只是默认分隔符不同。在 read_csv 中 “逗号,” 作为定界符,在 read_table 中定界符为 “\ t”。如果既不是逗号也不是制表符,则可以通过参数(sep 或 delimiter)设置区分符。

# ②文本文件储存

文本文件的存储和读取类似,对于结构化数据,可以通过 pandas 库中的 to_csv () 方法实现以 CSV 文件格式存储。

to_csv () 函数同样具有许多参数,如果有多个 < expression>,那么表达式之间用逗号隔开,基本使用格式如下。

DataFrame.to_csv(path_or_buf=None, sep=',', na_rep='', columns=None, header=True, index=True, index_label=None, mode='w', encoding=None)

to_csv () 方法的常用参数及其说明如下表:

参数名称参数说明
path_or_buf接收 str。表示文件路径。默认为 None
sep接收 str。表示分隔符。默认为 “,”
na_rep接收 str。表示缺失值。默认为 “”
columns接收 list。表示写出的列名。默认为 None
header接收 bool 或列表形式的 str。表示是否将列名写出。默认为 True
index接收 bool。表示是否将行名(索引)写出。默认为 True
index_label接收 sequence 或 str 或 false。表示索引名。默认为 None
mode接收特定 str。表示数据写入模式。默认为 w
encoding接收特定 str。表示存储文件的编码格式。默认为 None

# 3)读 / 写 Excel 文件

# ①Excel 文件读取

pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, dtype=None, skiprows=None)

read_excel () 函数的常用参数及其说明如下表:

参数名称参数说明
io接收 str。表示文件路径。无默认值
sheet_name接收 str、int、list 或 None。表示 Excel 表内数据的分表位置。默认为 0
header接收 int 或列表形式的 int。表示将某行数据作为列名。如果传递整数列表,那么行位置将合并为 MultiIndex。如果没有表头,那么使用 None。默认为 0
names接收 array。表示要使用的列名列表。默认为 None
index_col接收 int 或列表形式的 int。表示将列索引用作 dataframe 的行索引。默认为 None
dtype接收 dict。表示写入的数据类型(列名为 key,数据格式为 values)。默认为 None
skiprows接收 list、int 或 callable。表示读取数据开头跳过的行数。默认为 None

# ②Excel 文件储存

将数据存储至 Excel,可以使用 to_excel () 方法,基本使用格式如下。

DataFrame.to_excel(excel_writer, sheet_name='Sheet1', na_rep='', columns=None, header=True, index=True, index_label=None, encoding=None)

to_excel () 函数的常用参数及其说明如下表。

参数名称参数说明
excel_writer接收 str。表示文件路径。无默认值
sheet_name接收 str。表示 Excel 文件中工作簿的名称。默认为 Sheet1
na_rep接收 str。表示缺失值。默认为 “”
columns接收列表形式的 str 或 sequence。表示写出的列名。默认为 None
header接收 bool 或列表形式的 str。表示是否将列名写出。默认为 True
index接收 bool。表示是否将行名(索引)写出。默认为 True
index_label接收 sequence 或 str。表示索引名。默认为 None
encoding接收特定 str。表示存储文件的编码格式。默认为 None

# 4)读 / 写数据库

在生产环境中,绝大多数的数据都存储在数据库中。pandas 库提供了读取与存储关系型数据库数据的函数与方法。除了 pandas 库外,还需要使用 SQLAlchemy 库建立对应的数据库连接。

pandas 支持 MySQL、postgresql、Oracle、SQL Server 和 SQLite 等主流数据库。

SQLAlchemy 是配合相应数据库的 Python 连接工具。

  • MySQL 数据库需要安装 mysqlclient 或 pymysql 库。
  • Oracle 数据库需要安装 cx_oracle 库。
  • 使用 create_engine () 函数,建立一个数据库连接。

下面将以 MySQL 数据库为例,介绍 pandas 数据库数据的读取与存储。

# ①数据库数据读取

pandas 可实现数据库数据的读取,但前提是读者在进行读取操作前确保已安装数据库,并且数据库可以正常打开及使用。进行数据库的读取可利用 3 种函数进行操作。

  • read_sql_table () 函数只能读取数据库的某一个表格,不能实现查询的操作。
  • read_sql_query () 函数则只能实现查询操作,不能直接读取数据库中的某个表。
  • read_sql () 函数是两者的综合,既能够读取数据库中的某一个表,也能够实现查询操作。

在读取数据库数据前,需要先创建数据库连接。Python 提供了 SQLAlchemy 库的 create_engine 函数用于创建数据库连接,在 creat_engine 函数中输入的是一个连接字符串。

在使用 Python 的 SQLAlchemy 时,MySQL 和 Oracle 数据库连接字符串的格式如下:

数据库产品名 + 连接工具名:// 用户名:密码 @数据库 IP 地址:数据库端口号 / 数据库名称?charset = 数据库数据编码

read_sql_table () 函数、read_sql_query () 函数和 read_sql () 函数具有许多参数,参数的表达式之间用逗号隔开,基本使用格式如下。

pandas.read_sql_table(table_name, con, schema=None, index_col=None, coerce_float=True, parse_dates=None, columns=None, chunksize=None)
pandas.read_sql_query(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, chunksize=None, dtype=None)
pandas.read_sql( sql , con , index_col = None , coerce_float = True , params = None , parse_dates = None , columns = None , chunksize = None )

read_sql_table ()、read_sql_query () 和 read_sql () 这 3 个数据库数据读取函数的参数几乎完全一致,唯一的区别在于传入的是语句还是表名。3 个函数的参数及其说明如下表:

参数名称参数说明
sql or table_name接收 str。表示读取的数据的表名或 SQL 语句。无默认值
con接收数据库连接或 str。表示数据库连接信息。无默认值
index_col接收 str 或列表形式的 str。表示列设置为索引。默认为 None
coerce_float接收 bool。表示尝试将非字符串、非数字对象(如十进制)的值转换为浮点。默认为 True
columns接收 list。表示要从 SQL 表中选择的列名列表。默认为 None

# ②数据库数据储存

将 DataFrame 写入数据库中,同样也要依赖 SQLAlchemy 库的 create_engine 函数创建数据库连接。数据库数据读取有 3 个函数,但数据存储则只有一个 to_sql () 方法。

to_sql () 方法的基本使用格式如下:

DataFrame.to_sql(name, con, schema=None, if_exists='fail', index=True, index_label=None, chunksize=None, dtype=None, method=None)

to_sql () 函数的常用参数及其说明如下表。

参数名称参数说明
name接收 str。表示数据库表名。无默认值
con接收数据库连接。表示数据库连接信息。无默认值
if_exists接收 str。表示对表进行操作的方式,可选 “fail”“replace”“append”。fail 表示如果表名存在,那么不执行写入操作;replace 表示如果表名存在,那么将原数据库表删除,再重新创建;append 则表示在原数据库表的基础上追加数据。默认为 fail
index接收 bool。表示是否将 DataFrame 索引写入列并使用 index_Label 作为表中的列名。默认为 True
index_label接收 str 或 sequence。表示索引列的列标签。如果没有给定(默认)且索引为 True,那么使用索引名称。如果 DataFrame 使用 MultiIndex,那么应该给出序列。默认为 None
dtype接收 dict 或 scalar。表示指定列的数据类型。默认为 None

# 2. 掌握 DataFrame 的常用操作

# 1)DataFrame 的常用属性

DataFrame 的基础属性如下:

  • values:DataFrame 所有行的值
  • index:DataFrame 行索引
  • colums:DataFrame 列名
  • dtypes:DataFrame 指定列数据类型
  • size:DataFrame 元素的个数
  • ndim:DataFrame 维度
  • shape:DataFrame 形状
  • T: 实现 DataFrame 转置

# 2)查改增删 DataFrame 数据

DataFrame 作为一种二维数据表结构,能够像数据库一样实现查改增删操作,如添加一行、删除一行、添加一列、删除一列、修改某一个值、某个区间的值替换等。

# ①查看访问 DataFrame 中的数据

使用索引、切片方式:

DataFrame名称[行索引编号范围或名称][列索引范围或列名]
DataFrame名称[列索引范围或列名][行索引范围或名称]
print(sql_table_data['id'][1:5])
print(sql_table_data[['id','book_name']][1:5])
print(sql_table_data[1:5][['id','book_name']])
print(sql_table_data[1:5])

除了可以使用基本的查看方式查看访问 DataFrame 中的数据之外,还可以通过 loc () 方法和 iloc () 方法进行访问。

使用 iloc (iat) 或 loc (at) 函数:

使用 loc () 方法和 iloc () 方法可以对 DataFrame 进行多种操作:单列切片、多列切片、取出 DataFrame 中的任意数据。

DataFrame.loc[行索引名称或条件, 列索引名称]
DataFrame.iloc[行索引编号位置, 列索引编号位置]
  • loc () 方法更加灵活多变,代码的可读性更高;
  • iloc () 方法的代码简洁,但可读性不高。在数据分析工作中具体使用哪一种方法,应根据情况而定,大多数时候建议使用 loc () 方法。
print("打印第1-3列所有行数据",sql_table_data.iloc[:,[0,1,2]])
print("打印第1-3列所有行数据",sql_table_data.loc[:,['id','book_name','jd_price']])
print("打印第1-3列前10行数据",sql_table_data.iloc[0:10,[0,1,2]])
print("打印第1-3列前10行数据",sql_table_data.loc[0:10,['id','book_name','jd_price']])

通过 DataFrame 提供的方法 head () 和 tail () 也可以得到多行数据,但是用这两种方法得到的数据都是从开始或末尾获取的连续数据。

  • head () 方法和 tail () 方法使用的都是默认参数,所以访问的是前、后 5 行。
  • 在方法后的 “()” 中输入访问行数,即可实现目标行数的查看。

# ②DataFrame 的 loc、iloc 访问方式

pandas 提供了 loc () 和 iloc () 两种更加灵活的方法来实现数据访问。

loc () 方法是针对 DataFrame 索引名称的切片方法,如果传入的不是索引名称,那么切片操作将无法执行。

  • 利用 loc () 方法,能够实现所有单层索引切片操作。
  • iloc () 方法接收的必须是行索引和列索引的位置。

loc () 方法和 iloc () 方法基本使用格式如下:

DataFrame.loc[行索引名称或条件, 列索引名称]
DataFrame.iloc[行索引位置, 列索引位置]

使用 loc () 方法和 iloc () 方法可以对 DataFrame 进行多种操作。

  • 单列切片。
  • 多列切片,其原理是将多列的列名或位置作为一个列表或数据传入。
  • 取出 DataFrame 中的任意数据。

在使用 loc () 方法的时候,如果内部传入的行索引名称为一个区间,那么前后均为闭区间。

而使用 iloc () 方法时,如果内部传入的行索引位置或列索引位置为区间,那么为前闭后开区间。

loc () 方法的内部还可以传入表达式,结果会返回满足表达式的所有值。

iloc () 方法不能接收表达式,原因在于,iloc () 方法可以接收的数据类型并不包括 Series。根据 Series 的构成,应取出该 Series 的 values。

# ③更改 DataFrame 的数据

更改 DataFrame 中的数据的原理是将这部分数据提取出来,重新赋值为新的数据。

需要注意的是,数据更改是直接对 DataFrame 原数据更改,操作无法撤销。

如果不希望直接对原数据做出更改,那么需要对更改条件进行确认或对数据进行备份。

重命名列标签

DateFrame.rename(columns={k1:v1,k2:v2....}):重命名部分列标签
DateFrame.columns=['新列名',.......]:重命名全部列标签

# ④为 DataFrame 增添数据

为 DataFrame 添加一列的方法非常简单,只需要新建一个列索引,并对该索引下的数据进行赋值操作即可。如果新增的一列值是相同的,那么可以直接为其赋值一个常量。

创建一个新的列索引,对该列索引赋值即可

import pandas as pd
stu_data = {'A':['张三','李四','王五','何六','谢七','陆九'],
            'B':['男','女','男','女','女','男'],           'C':['20000302','19990416','20011214','20000812','20010708','20001017'],
            'D':[173,162,182,159,162,178],
            'E':['无','无','','','','无']
           }
student = pd.DataFrame(stu_data)
print(student)
#修改 C 列的数据类型为 'datetime64'
student['C'] =student['C'].astype('datetime64')
print(student.dtypes)
#修改列标签
student.columns = ['姓名','性别','出生日期','身高','备注']
print(student)
#修改备注列中所有空值为 "暂无"
student.loc[student['备注']=='',['备注']]='暂无'
print(student)
#新增 "专业" 列,数值为 "数据科学与大数据技术"
student['专业']='数据科学与大数据技术'
print(student)

# ⑤删除某列或某行数据

删除某列或某行数据需要用到 pandas 提供的方法 drop ()。

drop () 方法的基本使用格式如下:

DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None,inplace=False, errors='raise')

drop () 函数的常用参数及其说明如下表:

参数名称参数说明
labels接收单一标签。表示要删除的索引或列标签。无默认值
axis接收 0 或 1。表示操作的轴向。默认为 0
level接收 int 或索引名。表示标签所在级别。默认为 None
inplace接收 bool。表示操作是否对原数据生效。默认为 False

删除某行数据,只需要将 drop () 方法参数中的 “labels” 参数换成对应的行索引,将 “axis” 参数设置为 0 即可。

# 3)描述分析 DataFrame 数据

描述性统计是用于概括、表述事物整体状况,以及事物间关联、类属关系的统计方法。通过几个统计值可简捷地表示一组数据的集中趋势和离散程度等。

# ①数值型特征的描述性统计

数值型特征的描述性统计主要包括了计算数值型数据的最小值、均值、中位数、最大值、四分位数、极差、标准差、方差、协方差和变异系数等。

在 NumPy 库中已经提到了为数不少的统计函数,为方便读者查看,将 NumPy 库简写为 np,部分统计函数如下表

函数名称参数说明函数名称函数说明
np.min最小值np.max最大值
np.mean均值np.ptp极差
np.median中位数np.std标准差
np.var方差np.cov协方差

pandas 库是基于 NumPy 库的,自然也可以使用表中的统计函数对数据进行描述性统计。

pandas 还提供了更加便利的方法来进行数值型数据的统计。用 np.mean 函数实现计算某列的均值,也可以通过 pandas 实现。

作为专门为数据分析而生的 Python 库,pandas 还提供了一个 describe () 方法,能够一次性得出数据框中所有数值型特征如下。

  • 非空值数目。
  • 均值。
  • 四分位数。
  • 标准差。
  • 最大值和最小值。

pandas 还提供了与统计相关的主要方法,这些方法能够满足绝大多数数据分析所需要的数值型特征的描述性统计工作,统计方法如下表

函数名称参数说明函数名称函数说明
min最小值Max最大值
mean均值Ptp极差
median中位数Std标准差
var方差Cov协方差
sem标准误差Mode众数
skew样本偏度Kurt样本峰度
quantile分位数Count非空值数目
describe描述统计Mad平均绝对离差

# ②类别型特征的描述性统计

描述类别型特征的分布状况,可以使用频数统计。在 pandas 库中实现频数统计的方法为 value_counts ()。

除了使用 value_counts () 方法分析频率分布外,pandas 提供了 category 类,可以使用 astype () 方法将目标特征的数据类型转换为 category 类型。

describe () 方法除了支持传统数值型数据以外,还能够支持对 category 类型的数据进行描述性统计,4 个统计量如下。

  • 列非空元素的数目。
  • 类别的数目。
  • 数目最多的类别。
  • 数目最多类别的数目。

# 3. 转换与处理时间序列数据

# 1)转换字符串时间为标准时间

在多数情况下,对时间类型数据进行分析的前提就是将原本为字符串的时间转换为标准时间。pandas 继承了 NumPy 库和 datetime 库的时间相关模块,提供了 6 种时间相关的类如下表:

函数名称参数说明
Timestamp最基础的时间类。表示某个时间点。绝大多数的场景中的时间数据都是 Timestamp 形式
Period表示某个时间段,如某一天、某一小时等
Timedelta表示不同单位的时间,如 1d、1.5h、3min、4s 等,而非具体的某个时间段
DatetimeIndex一组 Timestamp 构成的 Index,可以用于作为 Series 或 DataFrame 的索引
PeriodtimeIndex一组 Period 构成的 Index,可以用于作为 Series 或 DataFrame 的索引
TimedeltaIndex一组 Timedelta 构成的 Index,可以用于作为 Series 或 DataFrame 的索引

Timestamp 是时间类中较为基础的,也是较为常用的。在多数情况下,会将与时间相关的字符串转换成为 Timestamp。pandas 提供的 to_datetime 函数,能够实现这一目标。

date_range ():指定时间的起始 start 和结束范围 end、时间间隔 freq、数据数量 periods 等参数。主要用于生成一个固定频率的时间索引,数据类型为:DatetimeIndex。保存在 DataFrame 对象中的每一个时间数据,都会被转换为 Timestamp 类型的数据。可以调用对应的属性获得日期中的部分数据。

import pandas as pd
date1 = pd.date_range(start='20230301',freq='D',periods=10)
date2 = pd.date_range(end='20230301',freq='M',periods=10)
print(date1[0].year)  #输出 date1 中第一个日期的年份
y_m = [(i.year,i.month) for i in date2]  #获取 date2 日期中的年、月
print(y_m)

to_datetime ():用于实现将规范或不规范的时间数据转换为标准的 datetime 类型数据。可以使用 errors 参数对无效数据进行解析,参数值设置有:接收 “ignore”、“raise”、“coerce”。

to_datetime 函数的基本使用格式如下:

pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True)
import pandas as pd
date1 = pd.to_datetime('2023 03 08 9:00')
print(date1)

to_datetime () 函数的常用参数及其说明如下表

函数名称参数说明
arg接收 str、int、float、list、tuple、datetime 或 array。表示需要转换的时间日期对象。无默认值
errors接收 “ignore”“raise”“coerce”。表示无效解析。默认为 raise
dayfirst\yearfirst接收 bool。表示指定日期的解析顺序。默认为 False

Timedelta ():根据一个指定时间计算未知的时间,Timedelta () 括号内参数可以指定多个参数,如周 weeks、天 days、小时 hours 等。

import pandas as pd
date1 = pd.date_range(start='20230301',freq='D',periods=10)
date2 = pd.date_range(end='20230301',freq='M',periods=10)
print(date1[0].year)  #输出 date1 中第一个日期的年份
y_m = [(i.year,i.month) for i in date2]  #获取 date2 日期中的年、月
print(y_m)

除了将数据从原始 DataFrame 中直接转换为 Timestamp 格式外,还可以将数据单独提取出来,将其转换为 DatetimeIndex 格式或 PeriodIndex 格式。但 DatetimeIndex 和 PeriodIndex 在日常使用的过程中并无太大区别。

  • DatetimeIndex 是用于指代一系列时间点的一种数据结构。
  • PeriodIndex 则是用于指代一系列时间段的数据结构。

DatetimeIndex 类与 PeriodIndex 类的基本使用格式如下:

class pandas.DatetimeIndex(data=None, freq=<no_default>, tz=None, normalize=False, closed=None, ambiguous='raise', dayfirst=False, yearfirst=False, dtype=None, copy=False, name=None)
class pandas.PeriodIndex(data=None, ordinal=None, freq=None, dtype=None, copy=False, name=None, **fields)

DatetimeIndex 可以用于转换数据,还可以用于创建时间序列数据,常用参数及其说明如下表:

函数名称参数说明
data接收类数组。表示用可选的类似日期时间的数据来构造索引。默认为 None
freq接收 str。表示一种 pandas 周期字符串或相应的对象。无默认值
tz接收时区或 str。表示设置数据的时区。默认为 None
dtype接收 Numpy.dtype 或 DatetimeTZDtype 或 str。表示数据类型。默认为 None

PeriodIndex 可以用于转换数据,还可以用于创建时间序列数据,常用参数及其说明如下表:

函数名称参数说明
data接收类数组。表示用可选的类似周期的数据来构造索引。默认为 None
freq接收 str。表示一种 pandas 周期字符串或相应的对象。默认为 None
dtype接收 str 或 PeriodDtype。表示数据类型。默认为 None

query ():Pandas 提供此函数可以实现内容(包括时间)的查询、修改列、创建新列。

# 2)提取时间序列数据信息

在多数涉及与时间相关的数据处理、统计分析的过程中,都需要提取时间中的年份、月份等数据。使用对应的 Timestamp 类属性就能够实现这一目的,其常用类属性及说明如下表

属性名称属性说明属性名称属性说明
yearweek一年中第几周
monthquarter季节
dayweekofyear一年中第几周
hour小时dayofyear一年中的第几天
minute分钟dayofweek一周第几天
secondweekday一周第几天
date日期is_leap_year是否闰年
time时间

# 3)加减时间数据

时间数据的算术运算在现实中随处可见,例如,2020 年 1 月 1 日减一天就是 2019 年 12 月 31 日。pandas 的时间数据和现实生活中的时间数据一样可以做运算。这时就涉及 pandas 的 Timedelta 类。

Timedelta 是时间相关类中的一个异类,不仅能够使用正数,还能够使用负数表示单位时间,如 1s、2min、3h 等。使用 Timedelta 类,配合常规的时间相关类能够轻松实现时间的算术运算。

在 Timedelta 类的时间周期中没有年和月,所有周期名称、对应单位及其说明如下表(注:表中单位采用程序定义的符号,与法定单位符号可能不一致)。

周期名称单位说明
weeks星期
daysD
hoursh小时
minutesm
secondss
millisecondsms毫秒
microsecondsus微妙
nanosecondsns纳秒

# 4. 使用分组聚合进行组内计算

# 1)groupby () 方法拆分数据

groupby () 方法提供的是分组聚合步骤中的拆分功能,能够根据索引或特征对数据进行分组,其基本使用格式如下。

DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=<no_default>, observed=False, dropna=True)

groupby () 方法的常用参数及其说明如下表:

函数名称参数说明
by接收 list、str、mapping、function 或 generator。表示用于确定进行分组的依据,若传入的是一个函数,则对索引进行计算并分组;若传入的是一个字典或 Series,则字典或 Series 的值用于作为分组依据;若传入一个 NumPy 数组,则数据的元素作为分组依据;若传入的是字符串或字符串列表,则使用这些字符串所代表的特征作为分组依据。默认为 None
axis接收 0 或 1。表示操作的轴向。默认为 0
level接收 int 或索引名。表示标签所在级别。默认为 None
as_index接收 bool。表示聚合后的聚合标签是否以 DataFrame 索引形式输出。默认为 True
sort接收 bool。表示是否对分组依据、分组标签进行排序。默认为 True
group_keys接收 bool。表示是否显示分组标签的名称。默认为 True

分组后的结果并不能直接查看,而是被存在内存中,输出的是内存地址。实际上,分组后的数据对象 groupby 类似于 Series 与 DataFrame,是 pandas 提供的一种对象。

groupby 对象常用的描述性统计方法及说明如下表。

方法名称方法说明方法名称方法说明
count返回各组的计数值,不包括缺失值cumcount对每个分组中的组员进行标记,0~n-1
head返回每组的前 n 个值size返回每组的大小
max返回每组最大值min返回每组最小值
mean返回每组的均值std返回每组的标准差
median返回每组的中位数sum返回每组的和

agg () 方法和 aggregate () 方法都支持对每个分组应用某函数,包括 Python 内置函数或自定义函数。同时,这两个方法也能够直接对 DataFrame 进行函数应用操作。

针对 DataFrame 的 agg () 方法与 aggregate () 方法的基本使用格式如下。

DataFrame.agg(func, axis=0, *args, **kwargs)
DataFrame.aggregate(func, axis=0, *args, **kwargs)

# 2)使用 agg () 方法聚合数据

在正常使用过程中,agg () 方法和 aggregate () 方法对 DataFrame 对象操作时的功能几乎完全相同,因此只需要掌握其中一个方法即可。

agg () 方法的常用参数及其说明如下表

函数名称参数说明
func接收 list、dict、function 或 str。表示用于聚合数据的函数。无默认值
axis接收 0 或 1。代表操作的轴向。默认为 0

使用 agg () 方法时,对于某个特征希望只做求均值操作,而对另一个特征则希望只做求和操作。此时需要使用字典的方式,将两个特征名分别作为 key,然后将 NumPy 库的求和与求均值的函数分别作为 value。

如果希望求出某个特征的多个统计量,对某些特征则只需要求一个统计量,此时只需要将字典对应 key 的 value 转换为列表,将列表元素转换为多个目标的统计量即可。

在 agg () 方法中还可以传入读者自定义的函数。

在 NumPy 库中的函数 np.mean、np.median、np.prod、np.sum、np.std 和 np.var 能够在 agg () 方法中直接使用。

在自定义函数中使用 NumPy 库中的这些函数。

  • 计算的时候是单个序列,会无法得出想要的结果。
  • 多列数据同时计算,才能得到正确的结果。

使用 agg () 方法也能够实现对每一个特征的每一组使用相同的函数。

若需要对不同的特征应用不同的函数,则与 DataFrame 中使用 agg () 方法的操作相同。

# 3)使用 apply () 方法聚合数据

apply () 方法类似于 agg () 方法,能够将函数应用于每一列。不同之处在于,与 apply () 方法相比,agg () 方法传入的函数只能够作用于整个 DataFrame 或 Series,而无法像 agg () 方法一样能够对不同特征应用不同函数来获取不同结果。

apply () 方法的基本使用格式如下。

DataFrame.apply(func, axis=0, raw=False, result_type=None, args=(), **kwargs)

apply () 方法的使用方式和 agg () 方法相同。

使用 apply () 方法对 GroupBy 对象进行聚合操作的方法和 agg () 方法也相同,但使用 agg () 方法能够实现对不同的特征应用不同的函数,而 apply () 方法则不行。

apply () 方法的常用参数及其说明如下表。

函数名称参数说明
func接收 functions。表示应用于每行或每列的函数。无默认值
axis接收 0 或 1。表示操作的轴向。默认为 0
raw接收 bool。表示是否直接将 ndarray 对象传递给函数。默认为 False

transform () 方法能够对整个 DataFrame 的所有元素进行操作,其基本使用格式如下。

DataFrame.transform(func, axis=0, *args, **kwargs)

transform () 方法的常用参数及其说明如下表。

函数名称参数说明
func接收 functions、str、类列表或类字典。表示用于转换的函数。无默认值
axis接收 0 或 'index'、1 或 'columns'。代表操作的轴向。默认为 0

# 5. 创建透视表与交叉表

# 1)使用 pivot_table () 函数创建透视表

透视表是各种电子表格和其他数据分析软件中一种常见的数据汇总形式,可根据一个或多个建对数据进行聚和,并根据行或列的分组键将数据划分到各个区域。利用 pivot_table 函数可以实现创建透视表。

pivot_table () 函数的基本使用格式如下:

DataFrame.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

pivot_table () 方法的常用参数及其说明如下表

函数名称参数说明
values接收 str。用于指定要聚合的数据特征名,默认使用全部数据。默认为 None
index接收列、组、数组或前一列的列表。表示行分组键。默认为 None
columns接收列、组、数组或前一列的列表。表示列分组键。默认为 None
aggfunc接收函数、函数列表、dict。表示聚合函数。默认为 mean
margins接收 bool。表示添加所有行 / 列(如小计 / 总计)。默认为 False
dropna接收 bool。表示是否删掉全为 NaN 的列。默认为 True

使用 pivot_talbe () 函数时,若不特殊指定聚合函数的参数 aggfunc,会默认使用 numpy.mean 进行聚合运算,numpy.mean 会自动过滤掉非数值类型数据。读者可以通过指定 aggfunc 参数来修改聚合函数。

和 groupby () 方法分组相同,pivot_table () 函数在创建透视表的时候分组键 index 可以有多个,使用 format 和 metric 特征作为索引的透视表。

当全部数据列数很多时,若要只显示自己关心的列,则可以通过指定 values 参数来实现。

# 2)使用 crosstab () 函数创建交叉表

交叉表是透视表的一种,crosstab () 函数的参数和 pivot_table () 函数基本相同。

不同之处在于,对于 crosstab () 函数中的参数 index、columns、values,输入的都是从 DataFrame 中取出的某一列。

交叉表是一种特殊的透视表,主要用于计算分组频率。利用 pandas 提供的 crosstab 函数可以制作交叉表。

crosstab () 函数的基本使用格式如下。

pandas.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)

crosstab () 方法的常用参数及其说明如下表:

函数名称参数说明
index接收类数组或数组列表。表示行索引键。无默认值
columns接收类数组或数组列表。表示列索引键。无默认值
values接收类数组。表示聚合数据。默认为 None
rownames接收 sequence。表示行分组键名。默认为 None
colnames接收 sequence。表示列分组键名。默认为 None
aggfunc接收 function。表示聚合函数。默认为 None
margins接收 bool。表示汇总(Total)功能的开关,设置为 True 后,结果集中会出现名为 “ALL” 的行和列。默认为 False
dropna接收 bool。表示是否删掉全为 NaN 的列。默认为 True
normalize接收 bool。表示是否对值进行标准化。默认为 False