一.Anaconda

1.1什么是Anaconda

Anaconda官网地址:https://www.anaconda.com/

简单来说,Anaconda = Python + 包和环境管理器(Conda)+ 常用库 + 集成工具。它适合那些需要快速搭建数据科学或机器学习开发环境的用户。Anaconda和Python相当于是汽车和发动机的关系,安装Anaconda后,就像买了一台车,无需自己去安装发动机和其他零配件,而Python作为发动机提供Anaconda工作所需的内核。

Anaconda包及其依赖项和环境的管理工具为 conda 命令,与传统的 Python pip 工具相比Anaconda的conda可以更方便地在不同环境之间进行切换,环境管理较为简单。

为什么选择 Anaconda?

  • 方便安装: 安装 Anaconda 就像安装一个应用程序一样简单,它为您预先安装好了许多常用的工具,无需单独配置。
  • 包管理器: Anaconda 包含一个名为 Conda 的包管理器,用于安装、更新和管理软件包。Conda 不仅限于 Python,还支持多种其他语言的包管理。
  • 环境管理: 使用 Anaconda,您可以轻松地创建和管理多个独立的 Python 环境,比如可以安装 python2 和 python3 环境,然后实现自由切换。这对于在不同项目中使用不同的库和工具版本非常有用,以避免版本冲突。
  • 集成工具和库: Anaconda 捆绑了许多用于数据科学、机器学习和科学计算的重要工具和库,如 NumPy、Pandas、Matplotlib、SciPy、Scikit-learn 等。
  • Jupyter 笔记本: Jupyter 是一个交互式的计算环境,支持多种编程语言,但在 Anaconda 中主要用于 Python。它允许用户创建和共享包含实时代码、方程式、可视化和叙述文本的文档。
  • Spyder 集成开发环境: Anaconda 中集成了 Spyder,这是一个专为科学计算和数据分析而设计的开发环境,具有代码编辑、调试和数据可视化等功能。
  • 跨平台性: Anaconda可在Windows、macOS和 Linux等操作系统上运行,使其成为一个跨平台的解决方案。
  • 社区支持: Anaconda 拥有庞大的社区,用户可以在社区论坛上获取帮助、分享经验和解决问题

1.2conda常用命令

1.环境管理

功能

命令

创建环境

conda create -n <环境名> python=<版本号>

例如:conda create -n env1 python=3.12

激活环境

conda activate <环境名>

例如:conda activate env1

退出环境

conda deactivate

列出所有环境

conda env list 或 conda info --env

删除环境

conda remove -n <环境名> --all

例如:conda remove -n env1 --all

查看conda信息

conda info

          1. 软件包管理

功能

命令

安装软件包

conda install <包名>

例如:conda install numpy

指定版本安装软件包

conda install <包名>=<版本号>

例如:conda install numpy=1.26.4

更新软件包

conda update <包名>

例如:conda update pandas

卸载软件包

conda remove <包名>

例如:conda remove matplotlib

注意:虚拟新的环境起到的作用是环境隔离,项目间相互不影响,如果使用pycharm在指定anaconda解释器的时候,会自动创建虚拟环境。

1.3 Jupyter

Jupyter 是一个开源的交互式计算环境,广泛应用于数据科学、机器学习、科学研究等领域主要组件Jupyter Notebook和Jupyter Lab。JupyterLab作为Jupyter Notebook 的继承者,提供了更现代化和功能丰富的界面。JupyterLab的多文档界面、内置协作功能和扩展系统使其成为数据科学家和研究人员的首选。

命令提示符中输入jupyter lab或jupyter notebook,会弹出浏览器页面直接进入主页面

二.numpy

2.1 什么是numpy

numpy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/O 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。

numpy的部分功能如下:

  • ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。
  • 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。
  • 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。
  • 线性代数、随机数生成以及傅里叶变换功能。

用于集成由C、C++、Fortran等语言编写的代码的API。

大多数numpy数组都有一些限制:

  • 数组的所有元素必须具有相同的数据类型。
  • 一旦创建,数组的总大小就不能改变。
  • 形状必须是“矩形”,而不是“锯齿状”。例如二维数组的每一行必须具有相同的列数。

先安装numpy

2.2 numpy属性案例

#%%
#导入numpy模块
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print(a)
#a的类型
print(type(a))
#a的维度
print(a.ndim)
#a的形状
print(a.shape)
#a的元素个数
print(a.size)
#数据类型
print(a.itemsize)
#每个元素字节数大小
print(a.dtype)

2.3 ndarry的创建方式

2.3.1 array()和asarray()

array():将输入数据转换为ndarray,会进行copy

asarray():将输入数据转换为ndarray,如果输入本身是ndarray则不会进行copy

import numpy as np

data = [1,2,3]
print(f"data的内存地址->{id(data)}")

#如果传递的参数是数组,array会进行copy,创建一个新的对象
arr1 = np.array(data)
print(type(arr1))
print(f"data的内存地址->{id(arr1)}")

print("------------")

#如果传递的参数是数组,asarray不会进行copy,和参数数组指向同一个的对象
arr2 = np.asarray(arr1)
print(type(arr2))
print(f"data的内存地址->{id(arr2)}")

'''
data的内存地址->4907261760
<class 'numpy.ndarray'>
data的内存地址->4908048112
------------
<class 'numpy.ndarray'>
data的内存地址->4908048112
'''

2.3.2 zeros()、ones()、empty()与zeros_like()、ones_like()、empty_like()

zeros():返回给定形状和类型的新数组,用0填充。

ones():返回给定形状和类型的新数组,用1填充。

empty():返回给定形状和类型的未初始化的新数组。

需要注意的是,np.empty 并不保证数组元素被初始化为 0,它只是分配内存空间,数组中的元素值是未初始化的,可能是内存中的任意值。

上述3个方法创建的数组元素类型默认都是float64。

zeros_like():返回与给定数组具有相同形状和类型的0数组。

ones_like():返回与给定数组具有相同形状和类型的1数组。

empty_like():返回与给定数组具有相同形状和类型的未初始化的数组。

2.3.3 full()与full_like()

full():返回给定形状和类型的新数组,用指定的值填充。

full_like():返回与给定数组具有相同形状和类型的用指定值填充的新数组

import numpy as np

arr1 = np.full((2, 3), 6)
# [[6 6 6]
#  [6 6 6]]

arr2 = np.full_like(arr1, 5)
# [[5 5 5]
#  [5 5 5]]

2.3.4 arange()

arange():返回在给定范围内用均匀间隔的值填充的一维数组。

arr1 = np.arange(0, 10, 2)
# [0 2 4 6 8]

2.3.5 linspace()与logspace()

linspace():返回指定范围和元素个数的等差数列。数组元素类型为浮点型。

logspace():返回指定指数范围、元素个数、底数的等比数列。

arr1 = np.linspace(start=0, stop=10, num=5)
# [ 0.   2.5  5.   7.5 10. ]

arr2 = np.linspace(start=0, stop=10, num=5, endpoint=False)  # 设置endpoint=False,表示不包括stop
# [0. 2. 4. 6. 8.]

arr3 = np.logspace(start=2, stop=5, num=5, base=2)
# [ 4.          6.72717132 11.3137085  19.02731384 32.        ]

默认endpoint=True时

如果把0到10看作一条线段,相当于用5个点将这条线段分成了4段,要计算每段的长度(即相邻元素的间隔),用总长度 (stop - start) 除以段数 (num - 1) ,得到间隔为 10-0 / 4 = 2.5。这样从起始点 0 开始,每次加上间隔 2.5 就能依次得到序列中的元素:0、2.5、5、7.5、10 。

若 endpoint=False 的情况

当 endpoint=False 时,意味着 stop 这个值不包含在生成的序列中,此时 [start, stop) 区间相当于一条右端点空心(不包含 stop 这个点)的线段。我们在这条线段上放置 num 个点进行划分,每一个点都会划分出一个新的区间段。比如,放 1 个点会把线段分成 1 段,2 个点会分成 2 段,放 num 个点就会分成 num 段,段数就等于点数 num,计算间隔的公式就变为 (stop - start) / num 。

2.3.6 创建随机数数组

random.rand():返回给定形状的数组,用 [0, 1) 上均匀分布的随机样本填充。

random.randint():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机整数填充。

random.uniform():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机浮点数填充。

random.randn():返回给定形状的数组,用标准正态分布(均值为0,标准差为1)的随机样本填充。

arr1 = np.random.rand(2, 3)
# [[0.77112868 0.97415392 0.25668864]
#  [0.49946961 0.23491874 0.40514576]]

arr2 = np.random.randint(0, 10, (2, 3))
# [[7 8 2]
#  [1 2 3]]

arr3 = np.random.uniform(3, 6, (2, 3))
# [[5.69275495 3.84857937 3.2899215 ]
#  [5.32035519 3.7460973  3.33859905]]

arr4 = np.random.randn(2, 3)
# [[-2.03654925 -0.50146561  0.4362483 ]
#  [-1.90585739  0.94797017 -0.77026926]]

2.3.7 matrix()

matrix为ndarray的子类,只能生成二维的矩阵。

arr1 = np.matrix("1 2; 3 4")
# [[1 2]
#  [3 4]]

arr2 = np.matrix([[1, 2], [3, 4]])
# [[1 2]
#  [3 4]]

2.4 ndarray的数据类型

数据类型

类型代码

说明

bool

?

布尔类型

int8、uint8

int16、uint16

int32、uint32

int64、uint64

i1,u1

i2,u2

i4,u4

i8,u8

有符号、无符号的8位(1字节)整型

有符号、无符号的16位(2字节)整型

有符号、无符号的32位(4字节)整型

有符号、无符号的64位(8字节)整型

float16

float32

float64

f2

f4或f

f8或d

半精度浮点型

单精度浮点型

双精度浮点型

complex64

complex128

c8

c16

用两个32位浮点数表示的复数

用两个64位浮点数表示的复数

创建数组时可以使用dtype参数指定元素类型:

arr1 = np.array([1, 2, 3], dtype=np.float64)
# [1. 2. 3.]

也可以使用ndarray.astype()方法转换数组的元素类型:

arr1 = np.array([1, 2, 3], dtype=np.float64)
# [1. 2. 3.]

arr2 = arr1.astype(np.int64)
# [1 2 3]

2.5 ndarray切片和索引

ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。

可以通过内置的slice函数,或者冒号设置start, stop及step参数进行切片,从原数组中切割出一个新数组。

import numpy as np

arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9

#获取索引为2的数据
print(arr[2])
# 2

# 从索引 2开始到索引9(不包含)停止,间隔为2
print(arr[slice(2,9,2)])
# [2 4 6 8]

# 从索引2开始到索引9(不包含)停止,间隔为2
print(arr[2:9:2])
# [2 4 6 8]

# 从索引2开始到最后(不包含),默认间隔为1
print(arr[2:])
# [2 3 4 5 6 7 8 9]


#从索引2开始到索引9(不包含)结束,默认间隔为1
print(arr[2:9])
# [2 3 4 5 6 7 8]

2.6 numpy常用函数

2.6.1 基本函数

函数

说明

np.abs()

元素的绝对值,参数是 number 或 array

np.ceil()

向上取整,参数是 number 或 array

np.floor()

向下取整,参数是 number 或 array

np.rint()

四舍五入,参数是 number 或 array

四舍六入:当需要舍入的数字小于 5 时,直接舍去;当需要舍入的数字大于 5 时,进位。

五成双:当需要舍入的数字恰好是 5 时,会看 5 前面的数字,如果是偶数则直接舍去 5,如果是奇数则进位。

np.isnan()

判断元素是否为NaN(Not a Number) ,参数是 number 或 array

np.multiply()

元素相乘,参数是 number 或 array。如果第二个参数传递的是number,原数组中所有元素乘以这个数字,返回新的数组;如果第二个参数也是一个数组,是将两个数组中对应位置的元素相乘,返回一个新的数组,其形状与输入数组相同。

np.divide()

元素相除,参数是 number 或 array

np.where(condition, x, y)

三元运算符,x if condition else y

2.6.2 统计函数

函数

说明

np.mean()

所有元素的平均值

np.sum()

所有元素的和

np.max()

所有元素的最大值

np.min()

所有元素的最小值

np.std()

所有元素的标准差

np.var()

所有元素的方差

np.argmax()

最大值的下标索引值

np.argmin()

最小值的下标索引值

np.cumsum()

返回一个一维数组,每个元素都是之前所有元素的累加和

np.cumprod()

返回一个一维数组,每个元素都是之前所有元素的累乘积

多维数组在计算时默认计算全部维度,可以使用axis参数指定按某一维度为轴心统计,axis=0按列统计、axis=1按行统计。

2.6.3 比较函数

函数

说明

np.any()

至少有一个元素满足指定条件,就返回True

np.all()

所有的元素都满足指定条件,才返回True

arr1 = np.array([1, 2, 3, 4, 5])
print(np.any(arr1 > 3)) #True
print(np.all(arr1 > 3)) #False

2.6.4 排序函数

ndarray.sort():就地排序(直接修改原数组)。

arr1 = np.random.randint(0, 10, (3, 3))
print(arr1)
arr1.sort()
print(arr1)
arr1.sort(axis=0)
print(arr1)

axis:指定排序的轴。默认值为 -1,表示沿着最后一个轴进行排序。在二维数组中,axis = 0 表示按列排序,axis = 1 表示按行排序。

在 NumPy 中,轴是对数组维度的一种抽象描述。对于多维数组,每个维度都对应一个轴,轴的编号从 0 开始。对于二维数组,它有两个轴:

轴 0:代表垂直方向,也就是行的方向。可以把二维数组想象成一个表格,轴 0 就像是表格中从上到下的行索引方向对列数据排序,所以axis=0表示按列排序,按照每列排序。

轴 1:代表水平方向,也就是列的方向。就像是表格中从左到右的列索引方向对行数据进行排序,所以axis=1表示按行排序

np.sort():返回排序后的副本(创建新的数组)。

arr1 = np.random.randint(0, 10, (3, 3))
print(arr1)
print(np.sort(arr1))

2.6.5 去重函数

np.unique():计算唯一值并返回有序结果。

arr1 = np.random.randint(0, 5, (3, 3))
print(arr1)
print(np.unique(arr1))
"""
结果:[0 1 2 3 4]
"""

2.7 基本运算

numpy中的数组不用编写循环即可执行批量运算,称之为矢量化运算。

大小相等的数组之间的任何算术运算都会将运算应用到元素级。

数组与标量的算术运算会将标量值传播到各个元素,不同大小的数组之间的运算叫做广播。

广播机制是 NumPy 中一个强大的特性,它允许在不同形状的数组之间进行元素级运算。广播机制的规则如下:

NumPy 会从 后往前 比较两个数组的 shape。

满足以下任意条件即可广播:

  1. 两个维度相等
  2. 其中一个维度是 1

否则报错。

  • 规则1:如果俩个数组的维度数不相同,那么小维度数组的形状将会在最左边补1。
import numpy as np
# 一维数组
arr1 = np.array([1, 2, 3])  # 形状为 (3,)
# 二维数组
arr2 = np.array([[4], [5], [6]])  # 形状为 (3, 1)
# 对 arr1 应用规则 1,在其形状最左边补 1,变为 (1, 3)  [[1,2,3]]
# 此时 arr1 形状 (1, 3) 和 arr2 形状 (3, 1) 满足广播条件
result = arr1 + arr2
print("规则 1 示例结果:\n", result)

'''
规则 1 示例结果:
 [[5 6 7]
 [6 7 8]
 [7 8 9]]
'''
  • 规则2:如果俩个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度大小(元素个数)为1的维度开始扩展 ,(维度必须是1开始)直到所有维度都一样, 以匹配另一个数组的形状。

  • 规则3:如果俩个数组的形状在任何一个维度上都不匹配,并且没有任何一个维度大小等于1,那么会引发异常。

2.8 矩阵乘法

通过*运算符和np.multiply()对两个数组相乘进行的是对位乘法而非矩阵乘法运算。

使用np.dot()、ndarray.dot()、@可以进行矩阵乘法运算。

arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[6, 5], [4, 3], [2, 1]])
#对于矩阵乘法来说,要求第一个矩阵的列数等于第二个矩阵的行数
print(arr1)
print(arr2)
print(arr1.shape, arr2.shape)
print(np.dot(arr1, arr2))
print(arr1.dot(arr2))
print(arr1 @ arr2)
# 一个二维数组跟一个大小合适的一维数组的矩阵点积运算之后将会得到一个一维数组
arr3 = np.array([6, 5, 4])
print(arr1 @ arr3)
'''
[[1 2 3]
 [4 5 6]]
[[6 5]
 [4 3]
 [2 1]]
(2, 3) (3, 2)
[[20 14]
 [56 41]]
[[20 14]
 [56 41]]
[[20 14]
 [56 41]]
[28 73]
'''

三.pandas

3.1 什么是pandas

Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。

Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。

Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。

用得最多的pandas对象是Series,一个一维的标签化数组对象,另一个是DataFrame,它是一个面向列的二维表结构。

pandas兼具numpy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作。

pandas功能:

  • 有标签轴的数据结构

在数据结构中,每个轴都被赋予了特定的标签,这些标签用于标识和引用轴上的数据元素,使得数据的组织、访问和操作更加直观和方便

  • 集成时间序列功能。
  • 相同的数据结构用于处理时间序列数据和非时间序列数据。
  • 保存元数据的算术运算和压缩。
  • 灵活处理缺失数据。
  • 合并和其它流行数据库(例如基于SQL的数据库)的关系操作。

pandas这个名字源于panel data(面板数据,这是多维结构化数据集在计量经济学中的术语)以及Python data analysis(Python数据分析)。

3.2 pandas数据结构-Series

Series 是 Pandas 中的一个核心数据结构,类似于一个一维的数组,具有数据和索引

Series 可以存储任何数据类型(整数、浮点数、字符串等),并通过标签(索引)来访问元素。Series 的数据结构是非常有用的,因为它可以处理各种数据类型,同时保持了高效的数据操作能力,比如可以通过标签来快速访问和操作数据。

Series 特点:

  • 一维数组:Series 中的每个元素都有一个对应的索引值。
  • 索引: 每个数据元素都可以通过标签(索引)来访问,默认情况下索引是从 0 开始的整数,但你也可以自定义索引。
  • 数据类型: Series 可以容纳不同数据类型的元素,包括整数、浮点数、字符串、Python 对象等。
  • 大小不变性:Series 的大小在创建后是不变的,但可以通过某些操作(如 append 或 delete)来改变。
  • 操作:Series 支持各种操作,如数学运算、统计分析、字符串处理等。
  • 缺失数据:Series 可以包含缺失数据,Pandas 使用NaN(Not a Number)来表示缺失或无值。
  • 自动对齐:当对多个 Series 进行运算时,Pandas 会自动根据索引对齐数据,这使得数据处理更加高效。

我们可以使用 Pandas 库来创建一个 Series 对象,并且可以为其指定索引(Index)、名称(Name)以及值(Values):

3.2.1 series的创建

1.先安装pandas包,如果在Pycharm中加载不出来,可以通过如下命令安装

conda activate python-2025-conda

conda install pandas

2.直接通过列表创建Series

import pandas as pd

s = pd.Series([4, 7, -5, 3])
print(s)
# 0    4
# 1    7
# 2   -5
# 3    3
# dtype: int64

Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。

3.通过列表创建Series时指定索引

s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"])
print(s)
# a    4
# b    7
# c   -5
# d    3
# dtype: int64

4.通过列表创建Series时指定索引和名称

s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"],name="hello_python")
print(s)
# a    4
# b    7
# c   -5
# d    3
# Name: hello_python, dtype: int6

5.直接通过字典创建Series

dic = {"a": 4, "b": 7, "c": -5, "d": 3}
s = pd.Series(dic)
print(s)
# a    4
# b    7
# c   -5
# d    3
# dtype: int64
s1 = pd.Series(dic,index=["a","c"],name="aacc")
print(s1)
# a    4
# c   -5
# Name: aacc, dtype: int64

3.2.2 Series的常用属性

属性

说明

index

Series的索引对象

values

Series的值

ndim

Series的维度

shape

Series的形状

size

Series的元素个数

dtype或dtypes

Series的元素类型

name

Series的名称

loc[]

显式索引,按标签索引或切片

iloc[]

隐式索引,按位置索引或切片

at[]

使用标签访问单个元素

iat[]

使用位置访问单个元素

import pandas as pd
arrs = pd.Series([11,22,33,44,55],name="atguigu",index=["a","b","c","d","e"])
# print(arrs)
# index Series的索引对象
print(arrs.index)
for i in arrs.index:
    print(i)
# values    Series的值
print(arrs.values)
# ndim  Series的维度
print(arrs.ndim)
# shape Series的形状
print(arrs.shape)
# size  Series的元素个数
print(arrs.size)
# dtype或dtypes  Series的元素类型
print(arrs.dtype)
print(arrs.dtypes)
# name  Series的名称
print(arrs.name)
# loc[] 显式索引,按标签索引或切片
print(arrs.loc["c"])
print(arrs.loc["c":"d"])
# iloc[]    隐式索引,按位置索引或切片
print(arrs.iloc[0])
print(arrs.iloc[0:3])
# at[]  使用标签访问单个元素
print(arrs.at["a"])
# iat[] 使用位置访问单个元素
print(arrs.iat[3])

'''
Index(['a', 'b', 'c', 'd', 'e'], dtype='str')
a
b
c
d
e
[11 22 33 44 55]
1
(5,)
5
int64
int64
atguigu
33
c    33
d    44
Name: atguigu, dtype: int64
11
a    11
b    22
c    33
Name: atguigu, dtype: int64
11
44
'''

3.2.3 Series的常用方法

方法

说明

head()

查看前n行数据,默认5行

tail()

查看后n行数据,默认5行

isin()

元素是否包含在参数集合中

isna()

元素是否为缺失值(通常为 NaN 或 None)

sum()

求和,会忽略 Series 中的缺失值

mean()

平均值

min()

最小值

max()

最大值

var()

方差

std()

标准差

median()

中位数

mode()

众数(出现频率最高的值),如果有多个值出现的频率相同且都是最高频率,这些值都会被包含在返回的 Series 中

quantile(q,interpolation)

指定位置的分位数

q的取值范围是 0 到 1 之间的浮点数或浮点数列表,如quantile(0.5)表示计算中位数(即第 50 百分位数);

interpolation:指定在计算分位数时,如果分位数位置不在数据点上,采用的插值方法。默认值是线性插值 'linear',还有其他可选值如 'lower'、'higher'、'midpoint'、'nearest' 等

describe()

常见统计信息

value_count()

每个元素的个数

count()

非缺失值元素的个数,如果要包含缺失值,用len()

drop_duplicates()

去重

unique()

去重后的数组

nunique()

去重后元素个数

sample()

随机采样

sort_index()

按索引排序

sort_values()

按值排序

replace()

用指定值代替原有值

to_frame()

将Series转换为DataFrame

equals()

判断两个Series是否相同

keys()

返回Series的索引对象

corr()

计算与另一个Series的相关系数 

默认使用皮尔逊相关系数(Pearson correlation coefficient)来计算相关性。要求参与比较的数组元素类型都是数值型。

当相关系数为 1 时,表示两个变量完全正相关,即一个变量增加,另一个变量也随之增加。

当相关系数为 -1 时,表示两个变量完全负相关,即一个变量增加,另一个变量随之减少。

当相关系数为 0 时,表示两个变量之间不存在线性相关性。

例如,分析某地区的气温和冰淇淋销量之间的关系

cov()

计算与另一个Series的协方差

hist()

绘制直方图,用于展示数据的分布情况。它将数据划分为若干个区间(也称为 “bins”),并统计每个区间内数据的频数

需要安装matplotlib包

items()

获取索引名以及值

3.2.4 Series的布尔索引

可以使用布尔索引从Series中筛选满足某些条件的值。

s = pd.Series({"a": -1.2, "b": 3.5, "c": 6.8, "d": 2.9})
bools = s > s.mean()  # 将大于平均值的元素标记为 True
print(bools)
# a    False
# b     True
# c     True
# d    False
# dtype: bool
print(s[bools])
# b    3.5
# c    6.8
# dtype: float64

3.2.5 Series的运算

1.Series与标量运算

标量会与每个元素进行计算

s = pd.Series({"a": -1.2, "b": 3.5, "c": 6.8, "d": 2.9})
print(s * 10)
# a   -12.0
# b    35.0
# c    68.0
# d    29.0
# dtype: float64

2.​​​​​​​Series与Series运算

会根据标签索引进行对位计算,索引没有匹配上的会用NaN填充。

s1 = pd.Series([1, 1, 1, 1])
s2 = pd.Series([2, 2, 2, 2], index=[1, 2, 3, 4])
print(s1 + s2)
# 0    NaN
# 1    3.0
# 2    3.0
# 3    3.0
# 4    NaN
# dtype: float64

3.3 Pandas数据结构-DataFrame

DataFrame是Pandas 中的另一个核心数据结构,类似于一个二维的表格或数据库中的数据表。它是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值),既有行索引也有列索引。

DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。它可以被看做由Series组成的字典(共同用一个索引)。提供了各种功能来进行数据访问、筛选、分割、合并、重塑、聚合以及转换等操作,广泛用于数据分析、清洗、转换、可视化等任务。

3.3.1 DataFrame创建

1.直接通过字典创建DataFrame

df = pd.DataFrame({"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [20, 30, 40]})
print(df)
#     id name  age
# 0  101   张三   20
# 1  102   李四   30
# 2  103   王五   40

2.通过字典创建时指定列的顺序和行索引

df = pd.DataFrame(
    data={"age": [20, 30, 40], "name": ["张三", "李四", "王五"]}, columns=["name", "age"], index=[101, 102, 103]
)
print(df)

3.3.2 DataFrame的常用属性

属性

说明

index

DataFrame的行索引

columns

DataFrame的列标签

values

DataFrame的值

ndim

DataFrame的维度

shape

DataFrame的形状

size

DataFrame的元素个数

dtypes

DataFrame的元素类型

T

行列转置

loc[]

显式索引,按行列标签索引或切片

iloc[]

隐式索引,按行列位置索引或切片

at[]

使用行列标签访问单个元素

iat[]

使用行列位置访问单个元素

import pandas as pd
df = pd.DataFrame(data={"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [20, 30, 40]},index=["aa", "bb", "cc"])
print(df.T)
'''
 aa   bb   cc
id    101  102  103
name   张三   李四   王五
age    20   30   40
'''

3.3.3 DataFrame的常用方法

方法

说明

head()

查看前n行数据,默认5行

tail()

查看后n行数据,默认5行

isin()

元素是否包含在参数集合中

isna()

元素是否为缺失值

sum()

求和

mean()

平均值

min()

最小值

max()

最大值

var()

方差

std()

标准差

median()

中位数

mode()

众数

quantile()

指定位置的分位数,如quantile(0.5)

describe()

常见统计信息

info()

基本信息

value_counts()

每个元素的个数

count()

非空元素的个数

drop_duplicates()

去重

sample()

随机采样

replace()

用指定值代替原有值

equals()

判断两个DataFrame是否相同

cummax()

累计最大值

cummin()

累计最小值

cumsum()

累计和

cumprod()

累计积

diff()

一阶差分,对序列中的元素进行差分运算,也就是用当前元素减去前一个元素得到差值默认情况下,它会计算一阶差分,即相邻元素之间的差值。参数:

periods:整数,默认为 1。表示要向前或向后移动的周期数,用于计算差值。正数表示向前移动,负数表示向后移动。

axis:指定计算的轴方向。0 或 'index' 表示按列计算,1 或 'columns' 表示按行计算,默认值为 0。

sort_index()

按行索引排序

sort_values()

按某列的值排序,可传入列表来按多列排序,并通过ascending参数设置升序或降序

nlargest()

返回某列最大的n条数据

nsmallest()

返回某列最小的n条数据

在Pandas的 DataFrame 方法里,axis 是一个非常重要的参数,它用于指定操作的方向。

axis 参数可以取两个主要的值,即 0 或 'index',以及 1 或 'columns' ,其含义如下:

  • axis=0 或 axis='index':表示操作沿着行的方向进行,也就是对每一列的数据进行处理。例如,当计算每列的均值时,就是对每列中的所有行数据进行计算。
  • axis=1 或 axis='columns':表示操作沿着列的方向进行,也就是对每行的数据进行处理。例如,当计算每行的总和时,就是对每行中的所有列数据进行计算。
import pandas as pd
df = pd.DataFrame(data={"id": [101, 102, 103,104,105,106,101], "name": ["张三", "李四", "王五","赵六","冯七","周八","张三"], "age": [10, 20, 30, 40, None, 60,10]},index=["aa", "bb", "cc", "dd", "ee", "ff","aa"])
print("\n",df.info())
print("\n",df.describe())
# drop_duplicates() 去重  duplicated()判断是否为重复行
print("\n",df.duplicated(subset="age"))

# sample() 随机采样
print("\n",df.sample())

# equals()  判断两个DataFrame是否相同
df1 = pd.DataFrame(data={"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [10, 20, 30]})
df2 = pd.DataFrame(data={"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [10, 20, 30]})
print("\n",df1.equals(df2))

"""
<class 'pandas.DataFrame'>
Index: 7 entries, aa to aa
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   id      7 non-null      int64  
 1   name    7 non-null      str    
 2   age     6 non-null      float64
dtypes: float64(1), int64(1), str(1)
memory usage: 224.0+ bytes
None

                id        age
count    7.000000   6.000000
mean   103.142857  28.333333
std      1.951800  19.407902
min    101.000000  10.000000
25%    101.500000  12.500000
50%    103.000000  25.000000
75%    104.500000  37.500000
max    106.000000  60.000000

aa    False
bb    False
cc    False
dd    False
ee    False
ff    False
aa     True
dtype: bool

      id name   age
aa  101   张三  10.0

 True
"""

3.3.4 DataFrame的布尔索引

可以使用布尔索引从DataFrame中筛选满足某些条件的行。

df = pd.DataFrame(
    data={"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 104, 103, 102],
)
print(df["age"] > 25)
print(df[df["age"] > 25])
#101    False
#104     True
#103     True
#102    False
Name: age, dtype: bool
#     name  age
# 104   李四   30
# 103   王五   40

3.3.5 DataFrame的运算

1.dataframe与标量运算

标量与每个元素进行计算。

df = pd.DataFrame(
    data={"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 104, 103, 102],
)
print(df * 2)
#      name  age
# 101  张三张三   40
# 104  李四李四   60
# 103  王五王五   80
# 102  赵六赵六   20

2.​​​​​​​​​​​​​​DataFrame与DataFrame运算

根据标签索引进行对位计算,索引没有匹配上的用NaN填充

df1 = pd.DataFrame(
data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "赵六"]},
columns=["name", "age"],
index=[101, 102, 103, 104],
)
df2 = pd.DataFrame(
data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "田七"]},
columns=["name", "age"],
 index=[102, 103, 104, 105],
)
print(df1 + df2)

"""

     name   age
101   NaN   NaN
102  李四张三  30.0
103  王五李四  50.0
104  赵六王五  70.0
105   NaN   NaN
"""

3.3.6 DataFrame的更改操作

1.设置行索引

创建DataFrame时如果不指定行索引,pandas会自动添加从0开始的索引。

df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]})
print(df)
#    age name   id
# 0   20   张三  101
# 1   30   李四  102
# 2   40   王五  103
# 3   10   赵六  104

通过set_index()设置行索引

"""
inplace=True:这是一个布尔类型的参数。当设为 True 时,会直接在原 
 DataFrame上进行修改;若设为 False(默认值),则会返回一个新的 
 DataFrame,原DataFrame 保持不变
"""
df.set_index("id", inplace=True)  # 设置行索引
print(df)
#      age name
# id
# 101   20   张三
# 102   30   李四
# 103   40   王五
# 104   10   赵六

通过reset_index()重置行索引

df.reset_index(inplace=True)  # 重置索引
print(df)
#     id  age name
# 0  101   20   张三
# 1  102   30   李四
# 2  103   40   王五
# 3  104   10   赵六

2.修改行索引名和列名

通过rename()修改行索引名和列名

df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]})
df.set_index("id", inplace=True)
print(df)
#      age name
# id
# 101   20   张三
# 102   30   李四
# 103   40   王五
# 104   10   赵六

df.rename(index={101: "一", 102: "二", 103: "三", 104: "四"}, columns={"age": "年龄", "name": "姓名"}, inplace=True)
print(df)
#     年龄  姓名
# id
# 一   20  张三
# 二   30  李四
# 三   40  王五
# 四   10  赵六

将index和columns重新赋值

df.index = ["Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ"]
df.columns = ["年齡", "名稱"]
print(df)
#    年齡  名稱
# Ⅰ  20  张三
# Ⅱ  30  李四
# Ⅲ  40  王五
# Ⅳ  10  赵六
3.添加列

通过 df[“列名”] 添加列。

df["phone"] = ["13333333333", "14444444444", "15555555555", "16666666666"]
print(df)
#      age name          phone
# id
# 101   20   张三   13333333333
# 102   30   李四   14444444444
# 103   40   王五   15555555555
# 104   10   赵六   16666666666
4.删除列

通过 df.drop(“列名”, axis=1) 删除,也可是删除行 axis=0

df.drop("phone", axis=1, inplace=True)  # 删除phone,按列删除,inplace=True表示直接在原对象上修改
print(df)
#      age name
# id
# 101   20   张三
# 102   30   李四
# 103   40   王五
# 104   10   赵六

    通过del df[列名] 删除

    del df["phone"]
    print(df)
    #      age name
    # id
    # 101   20   张三
    # 102   30   李四
    # 103   40   王五
    # 104   10   赵六
    5.插入列

    通过 insert(loc, column, value) 插入。该方法没有inplace参数,直接在原数据上修改。

    df.insert(loc=0, column="phone", value=df["age"] * df.index)
    print(df)
    #      phone  age name
    # id
    # 101   2020   20   张三
    # 102   3060   30   李四
    # 103   4120   40   王五
    # 104   1040   10   赵六

    3.3.7DataFrame数据的导入和导出

    1.导出数据

    方法

    说明

    to_csv()

    将数据保存为csv格式文件,数据之间以逗号分隔,可通过sep参数设置使用其他分隔符,可通过index参数设置是否保存行标签,可通过header参数设置是否保存列标签。

    to_pickle()

    如要保存的对象是计算的中间结果,或者保存的对象以后会在Python中复用,可把对象保存为.pickle文件。如果保存成pickle文件,只能在python中使用。文件的扩展名可以是.p、.pkl、.pickle。

    to_excel()

    保存为Excel文件,需安装openpyxl包。

    to_clipboard()

    保存到剪切板。

    to_dict()

    保存为字典。

    to_hdf()

    保存为HDF格式,需安装tables包。

    to_html()

    保存为HTML格式,需安装lxml、html5libbeautifulsoup4包。

    to_json()

    保存为JSON格式。

    to_feather()

    feather是一种文件格式,用于存储二进制对象。feather对象也可以加载到R语言中使用。feather格式的主要优点是在Python和R语言之间的读写速度要比csv文件快。feather数据格式通常只用中间数据格式,用于Python和R之间传递数据,一般不用做保存最终数据。需安装pyarrow包。

    to_sql()

    保存到数据库。

    import os
    import pandas as pd
    
    os.makedirs("data", exist_ok=True)
    df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]})
    df.set_index("id", inplace=True)
    print(df)
    
    df.to_csv("data/df.csv")
    

    如何导出到mysql?

    2.导入数据

    方法

    说明

    read_csv()

    加载csv格式的数据。可通过sep参数指定分隔符,可通过index_col参数指定行索引。

    read_pickle()

    加载pickle格式的数据。

    read_excel()

    加载Excel格式的数据。

    read_clipboard()

    加载剪切板中的数据。

    read_hdf()

    加载HDF格式的数据

    read_html()

    加载HTML格式的数据

    read_json()

    加载JSON格式的数据。

    read_feather()

    加载feather格式的数据。

    read_sql()

    加载数据库中的数据

    df_csv = pd.read_csv("data/df.csv", index_col="id")  # 指定行索引
    

    3.4 pandas日期数据处理初识

    3.4.1 to_datetime()进行日期格式转换

    1.参数说明

    参数名

    说明

    arg

    要转换为日期时间的对象

    errors

    ignore,raise,coerce, 默认为ignore,表示无效的解析将会返回原值

    dayfirst

    指定日期解析顺序。如果为True,则以日期开头解析日期,例如:“10/11/12”解析为2012-11-10。默认false

    yearfirst

    如果为True,则以日期开头解析,例如:“10/11/12”解析为2010-11-12。如果dayfirst和yearfirst都为True,则yearfirst在前面。默认false。当日期字符串格式不明确时,指定年份是否在最前面。当日期字符串是 '2010/1/4' 这种形式,由于年份是 4 位数字,pandas 能很清晰地识别出这是年份,所以即使 yearfirst 为 False,也不会影响其正确解析

    utc

    返回utc,即协调世界时间

    format

    格式化显示时间的格式,字符串,默认值为None

    exact

    要求格式完全匹配

    unit

    参数的单位表示时间的单位

    infer_datetime_format

    如果为True且未给出格式,则尝试基于第一个非nan元素推断datetime字符串的格式,如果可以推断,则切换到更快的解析方法。在某些情况下,这可以将解析速度提高5-10倍。

    origin

    默认值为unix,定义参考日期1970-01-01

    cache

    使用唯一的已转换日期缓存来应用日期时间转换。在解析重复日期字符串时产生显著的加速。

    2.将字符串字段转化为日期类型

    mport pandas as pd
    df = pd.DataFrame({"gmv":[100,200,300,400],"trade_date":["2025-01-06","2023-10-31","2023-12-31","2023-01-05"]})
    df["ymd"] = pd.to_datetime(df["trade_date"])
    print(df)

    3.4.2 时间属性访问起对象Series.dt,获取日期数据的年月日星期

    import pandas as pd
    df = pd.DataFrame({"gmv":[100,200,300,400],"trade_date":["2025-01-06","2023-10-31","2023-12-31","2023-01-05"]})
    df["ymd"] = pd.to_datetime(df["trade_date"])
    print(df)
    print("\n")
    
    #获取年月日
    df['yy']=df['ymd'].dt.year
    df['mm']= df['ymd'].dt.month
    df['dd']= df['ymd'].dt.day
    print(df)
    print("\n")
    
    #获取星期
    df['week']=df['ymd'].dt.day_name()
    print(df)
    
    #获取日期所在季度
    df['quarter']=df['ymd'].dt.quarter
    print(df)
    print("\n")
    
    
    #判断月期是否月底年底
    df['mend']=df['ymd'].dt.is_month_end
    df['yend']=df['ymd'].dt.is_year_end
    print(df)

    3.4.3 to_period()获取统计周期

    freq:这是 to_period() 方法最重要的参数,用于指定要转换的时间周期频率

    常见的取值如下:

    • "D":按天周期,例如 2024-01-01 会转换为 2024-01-01 这个天的周期。
    • "W":按周周期,通常以周日作为一周的结束,比如日期落在某一周内,就会转换为该周的周期表示。
    • "M":按月周期,像 2024-05-15 会转换为 2024-05。
    • "Q":按季度周期,一年分为四个季度,日期会转换到对应的季度周期,例如 2024Q2 。
    • "A" 或 "Y":按年周期,如 2024-07-20 会转换为 2024 。
    df["ystat"] = df["ymd"].dt.to_period("Y")
    df["mstat"] = df["ymd"].dt.to_period("M")
    df["qstat"] = df["ymd"].dt.to_period("Q")
    df["wstat"] = df["ymd"].dt.to_period("W")
    print(df)

    3.5DataFrame数据分析入门

    3.5.1 加载数据集

    使用weather(天气)数据集。其中包含6个字段:

    • date:日期,年-月-日格式。
    • precipitation:降水量。
    • temp_max:最高温度。
    • temp_min:最低温度。
    • wind:风力。
    • weather:天气状况。
    
    #加载天气数据
    import pandas as pd
    df = pd.read_csv("/Users/uiber-liujie/Desktop/project1/numpy-pandas/data/employees.csv")
    print(type(df)) # 查看df类型
    print(df.shape) # 查看df形状
    print(df.columns) # 查看df的列名
    print(df.dtypes) # 查看df各列数据类型
    df.info() # 查看df基本信息

    pandas类型

    Python类型

    说明

    object

    string

    字符串类型

    int64

    int

    整型

    float64

    float

    浮点型

    datetime64

    datetime

    日期时间类型

    3.5.2 查看部分数据

    1.通过head()、tail()获取前n行或者后n行

    print(df.head())
    print(df.tail(10))

    2.获取一列或多列数据

    #加载一列数据
    df_date_series = df["date"]  # 返回的是Series
    df_date_dataframe = df[["date"]]  # 返回的是DataFrame
    
    #加载多列数据
    df[["date", "temp_max", "temp_min"]]  # 获取多列数据

    3.按行获取数据

    ​​​​​​​​​​​​​​        ​​​​​​​loc:通过行标签获取数据​​​​​​​

    df.loc[1]  # 获取行标签为1的数据
    df.loc[[1, 10, 100]]  # 获取行标签分别为1、10、100的数据

            iloc:通过行位置获取数据

    df.iloc[0]  # 获取行位置为0的数据
    df.iloc[-1]  # 获取行位置为最后一位的数据

    4.获取指定行与列的数据

    df.loc[1, "precipitation"]  # 获取行标签为1,列标签为precipitation的数据
    df.loc[:, "precipitation"]  # 获取所有行,列标签为precipitation的数据
    df.iloc[:, [3, 5, -1]]  # 获取所有行,列位置为3,5,最后一位的数据
    df.iloc[:10, 2:6]  # 获取前10行,列位置为2、3、4、5的数据
    df.loc[:10, ["date", "precipitation", "temp_max", "temp_min"]]  # 通过行列标签获取数据

    3.5.3 分组聚合计算

    df.groupby("分组字段")["要聚合的字段"].聚合函数()
    df.groupby(["分组字段", "分组字段2", ...])[["要聚合的字段", "要聚合的字段2", ...]].聚合函数()

    1.将数据按月分组,并统计最大温度和最小温度的平均值

    df["month"] = pd.to_datetime(df["date"]).dt.to_period("M").astype(str)  # 将date转换为 年-月 的格式
    
    df_groupby_date = df.groupby("month")  # 按month分组,返回一个分组对象(DataFrameGroupBy)
    
    month_temp = df_groupby_date[["temp_max", "temp_min"]]  # 从分组对象中选择特定的列
    month_temp_mean = month_temp.mean()  # 对每个列求平均值

    test:将数据按照年分组,并且统计最大温度和最小温度的平均值

    df["year"] = pd.to_datetime(df["data"]).dt.to_period("Y").astype(str)
    
    df_groupby_date = df.groupby("year")["temp_max","temp_min"]
    
    year_temp_mean = df_groupby_date.mean()

    分组后默认会将分组字段作为行索引。如果分组字段有多个,得到的是复合索引。

    2.分组频数计算

    统计每个月不同天气状况的数量。

    df.groupby("month")["weather"].nunique()
    # date
    # 2012-01    4
    # 2012-02    4
    # 2012-03    4
    # 2012-04    4
    # 2012-05    3

    3.5.4 基本绘图

    plot():pandas 提供的绘图方法,它基于 matplotlib 库。将前面计算得到的均值结果绘制成图表,默认情况下会绘制折线图,其中 "month" 作为 x 轴,"temp_max" 和 "temp_min" 的均值作为 y 轴。

    df.groupby("month")[["temp_max", "temp_min"]].mean().plot()  # 使用plot绘制折线图

    3.5.5 常用统计值

    可通过describe()查看常用统计信息。

    df.describe()  # 查看常用统计信息
    df.describe().T  # 行列转置

    可通过include参数指定要统计哪些数据类型的列。

    df.describe(include="all")  # 统计所有列
    df.describe(include=["float64"])  # 只统计数据类型为float64的列

    3.5.6 常用排序方法

    nlargest(n, [列名1, 列名2, ]):按列排序的最大n个

    nsmallest(n, [列名1, 列名2, ]):按列排序的最小n个

    sort_values([列名1, 列名2, ], asceding=[True, False, ]):按列升序或降序排序

    drop_duplicates(subset=[列名1, 列名2]):按列去重

    1.找到最高温度最大的30天

    通过nlargest()找出temp_max最大的30条数据

    2.从最高温度最大的30天中找出最低温度最小的5天

    通过nlargest()找出temp_min最小的5条数据

    df.nlargest(30, "temp_max").nsmallest(5, "temp_min")

    3.找出每年的最高温度

    df["year"] = pd.to_datetime(df["date"]).dt.to_period("Y").astype(str)  # 将date转换为 年 格式
    df_sort = df.sort_values(["year", "temp_max"], ascending=[True, False])  # 按year升序,temp_max降序排序
    df_sort.drop_duplicates(subset="year")  # 按year去重

    3.5.7 案例:简单数据分析练习

    使用employees(员工)数据集,其中包含10个字段:

    • employee_id:员工id。
    • first_name:员工名称。
    • last_name:员工姓氏。
    • email:员工邮箱。
    • phone_number:员工电话号码。
    • job_id:员工工种。
    • salary:员工薪资。
    • commission_pct:员工佣金比例。
    • manager_id:员工领导的id。

    department_id:员工的部门id。

    import pandas as pd
    #加载数据
    df = pd.read_csv("/Users/uiber-liujie/Desktop/project1/numpy-pandas/data/employees.csv")
    
    #查看数据
    print(df.head(5),"\n") #查看数据前5行
    print(df.tail(10),"\n") #查看数据后10行
    print(df.describe(),"\n") #查看统计信息
    
    #找出薪资最高和最低的员工
    print(df[df["salary"] == df["salary"].min()], "\n") #薪资最低
    print(df[df["salary"] == df["salary"].max()], "\n") #薪资最高
    
    print(df.sort_values("salary", ascending=False).head(1), "\n")#薪资最高
    
    #找出薪资最高的10名员工
    print(df.nlargest(10,"salary"), "\n")
    
    #查看所有部门id
    print(df["department_id"].unique(), "\n")
    
    #查看每个部门的员工数
    df.groupby("department_id")["employee_id"].count().rename("employee_count")
    
    #绘图
    df.groupby("department_id")["employee_id"].count().rename("employee_count").plot(kind="bar")
    
    
    #平均薪资最高的部门
    print(df.groupby("department_id")["salary"].mean().nlargest(1))  # 平均薪资最高的部门

    3.6 pandas的数据组合连接

    3.6.1 concat连接

    沿着一条轴将多个对象堆叠到一起,可通过axis参数设置沿哪一条轴连接

    1.Series与Series连接

    import pandas as pd
    s1 = pd.Series(["A","B"],index = [1,2])
    s2 = pd.Series(["C","D"],index = [3,4])
    s3 = pd.Series(["E","F"],index = [5,6])
    m1 = pd.concat([s1,s2])
    print(m1,"\n")
    
    m2 = pd.concat([s1, s2, s3],axis=1)# 按列连接
    print(m2,"\n")
    
    '''
    1    A
    2    B
    3    C
    4    D
    dtype: str 
    
         0    1    2
    1    A  NaN  NaN
    2    B  NaN  NaN
    3  NaN    C  NaN
    4  NaN    D  NaN
    5  NaN  NaN    E
    6  NaN  NaN    F 
    '''

    2.DataFrame与series连接

    df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2])
    s1 = pd.Series(data=[7, 10], index=[1, 2], name="a")
    
    pd.concat([df1, s1])  # 按行连接
    #     a    b
    # 1   1  4.0
    # 2   2  5.0
    # 1   7  NaN
    # 2  10  NaN
    
    pd.concat([df1, s1], axis=1)  # 按列连接
    #    a  b   a
    # 1  1  4   7
    # 2  2  5  10

    3.DataFrame与DataFrame连接

    df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2])
    df2 = pd.DataFrame(data={"a": [7, 8], "b": [10, 11]}, index=[1, 2])
    
    pd.concat([df1, df2])  # 按行连接
    #    a   b
    # 1  1   4
    # 2  2   5
    # 1  7  10
    # 2  8  11
    
    pd.concat([df1, df2], axis=1)  # 按列连接
    #    a  b  a   b
    # 1  1  4  7  10
    # 2  2  5  8  11

    4.重制索引

    可通过ignore_index=True来重置索引。

    df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2])
    df2 = pd.DataFrame(data={"a": [7, 8], "b": [10, 11]}, index=[1, 2])
    
    pd.concat([df1, df2], ignore_index=True)  # 重置索引
    #    a   b
    # 0  1   4
    # 1  2   5
    # 2  7  10
    # 3  8  11

    5.类似join的连接

    默认的合并方式是对其他轴进行并集合并(join=outer),可以用join=inner实现其他轴上的交集合并。

    df1 = pd.DataFrame(data={"a": [1, 2], "b": [4, 5]}, index=[1, 2])
    df2 = pd.DataFrame(data={"b": [7, 8], "c": [10, 11]}, index=[2, 3])
    
    pd.concat([df1, df2]) #等价于pd.concat([df1, df2], join="outer")
    #      a  b     c
    # 1  1.0  4   NaN
    # 2  2.0  5   NaN
    # 2  NaN  7  10.0
    # 3  NaN  8  11.0
    
    pd.concat([df1, df2], join="inner")
    #    b
    # 1  4
    # 2  5
    # 2  7
    # 3  8

    concat一般就是对结果集进行合并的时候使用

    3.6.2 merge连接

    merge()实现了三种数据连接的类型:一对一、多对一和多对多。

    1.一对一连接

    df1 = pd.DataFrame( {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame({"employee": ["Lisa", "Bob", "Jake", "Sue"], "hire_date": [2004, 2008, 2012, 2014]})
    print(df1)
    print(df2)
    df3 = pd.merge(df1, df2)
    print(df3)

    2.多对一连接

    在需要连接的两个列中,有一列的值有重复。通过多对一连接获得的结果将会保留重复值。

    df1 = pd.DataFrame(
        {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame({"group": ["Accounting", "Engineering", "HR"], "supervisor": ["Carly", "Guido", "Steve"]})
    print(df1)
    print(df2)
    df3 = pd.merge(df1, df2)
    print(df3)

    在supervisor列中有些值会因为输入数据的对应关系而有所重复

    3.多对多连接

    如果左右两个输入的共同列都包含重复值,那么合并的结果就是一种多对多连接

    df1 = pd.DataFrame(
        {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame(
        {
            "group": ["Accounting", "Accounting", "Engineering", "Engineering", "HR", "HR"],
            "skills": ["math", "spreadsheets", "coding", "linux", "spreadsheets", "organization"],
        }
    )
    print(df1)
    print(df2)
    df3 = pd.merge(df1, df2)
    print(df3)

    多对多连接产生的是行的笛卡尔积。由于左边有2个Engineering,右边有2个Engineering,所以最终结果有4个Engineering

    设置合并的键与索引

    merge()会将两个输入的一个或多个共同列作为键进行合并。但由于两个输入要合并的列通常都不是同名的,因此merge()提供了一些参数处理这个问题。

    1.通过on指定某个列连接,只能在有共同列名的时候使用

    df1 = pd.DataFrame(
        {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame({"employee": ["Lisa", "Bob", "Jake", "Sue"], "hire_date": [2004, 2008, 2012, 2014]})
    print(df1)
    print(df2)
    df3 = pd.merge(df1, df2, on="employee")
    print(df3)

    2.两对象列名不同,通过left_on和right_on分别指定列名

    df1 = pd.DataFrame(
        {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "salary": [70000, 80000, 120000, 90000]})
    print(df1)
    #   employee        group
    # 0      Bob   Accounting
    # 1     Jake  Engineering
    # 2     Lisa  Engineering
    # 3      Sue           HR
    print(df2)
    #    name  salary
    # 0   Bob   70000
    # 1  Jake   80000
    # 2  Lisa  120000
    # 3   Sue   90000
    df3 = pd.merge(df1, df2, left_on="employee", right_on="name")
    print(df3)
    #   employee        group  name  salary
    # 0      Bob   Accounting   Bob   70000
    # 1     Jake  Engineering  Jake   80000
    # 2     Lisa  Engineering  Lisa  120000
    # 3      Sue           HR   Sue   90000

    3.通过left_index和right_index设置合并的索引

    通过设置merge()中的left_index、right_index参数将索引设置为键来实现合并。

    df1 = pd.DataFrame(
     {"employee": ["Bob", "Jake", "Lisa", "Sue"], "group": ["Accounting", "Engineering", "Engineering", "HR"]}
    )
    df2 = pd.DataFrame({"employee": ["Lisa", "Bob", "Jake", "Sue"], "hire_date": [2004, 2008, 2012, 2014]})
    df1.set_index("employee", inplace=True)
    df2.set_index("employee", inplace=True)
    print(df1)
    print(df2)
    # 设置索引后,如果不指定关联列会报错,建议通过以下方式指定,on="employee"也可#以实现,但是不同的解释器可能效果不一样,因为设置索引后,employee就不算是列了
    df3 = pd.merge(df1, df2, left_index=True, right_index=True)
    print(df3)
    '''
                   group
    employee             
    Bob        Accounting
    Jake      Engineering
    Lisa      Engineering
    Sue                HR
              hire_date
    employee           
    Lisa           2004
    Bob            2008
    Jake           2012
    Sue            2014
                    group  hire_date
    employee                        
    Bob        Accounting       2008
    Jake      Engineering       2012
    Lisa      Engineering       2004
    Sue                HR       2014
    '''

    DataFrame实现了join()方法,可以按照索引进行数据合并。但要求没有重叠的列,或通过lsuffix、rsuffix指定重叠列的后缀。

    import pandas as pd
    
    df1 = pd.DataFrame({
        'key': ['A', 'B', 'C'],
        'value1': [1, 2, 3]
    })
    
    df2 = pd.DataFrame({
        'key': ['B', 'C', 'D'],
        'value2': [4, 5, 6]
    })
    
    # 合并两个 DataFrame,并处理列名冲突,如果通过on指定列,只是指定的df1。会用
    #df1指定的列和df2的索引连接,会报错。除非df2.set_index指定索引。
    df1.join(df2,lsuffix='_left',rsuffix='_right')
    '''
    	key_left	value1	key_right	value2
    0	A	1	B	4
    1	B	2	C	5
    2	C	3	D	6
    '''
    设置数据连接的集合操作规则

    1.当一个值出现在一列,却没有出现在另一列时,就需要考虑集合操作规则了。

    df1 = pd.DataFrame({"name": ["Peter", "Paul", "Mary"], "food": ["fish", "beans", "bread"]}, columns=["name", "food"])
    df2 = pd.DataFrame({"name": ["Mary", "Joseph"], "drink": ["wine", "beer"]}, columns=["name", "drink"])
    print(df1)
    #     name   food
    # 0  Peter   fish
    # 1   Paul  beans
    # 2   Mary  bread
    print(df2)
    #      name drink
    # 0    Mary  wine
    # 1  Joseph  beer
    print(pd.merge(df1, df2))
    #    name   food drink
    # 0  Mary  bread  wine

    2.合并两个数据集,在name列中只有一个共同的值Mary。默认情况下,结果中只会包含两个输入集合的交集,这种连接方式被称为内连接(inner join)。

    我们可以通过how参数设置连接方式,默认值为inner。how参数支持的数据连接方式还有outer、left和right。外连接(outer join)返回两个输入列的并集,所有缺失值都用 NaN 填充。

    print(pd.merge(df1, df2, how="outer"))
    #      name   food drink
    # 0  Joseph    NaN  beer
    # 1    Mary  bread  wine
    # 2    Paul  beans   NaN
    # 3   Peter   fish   NaN

    3.左连接(left join)和右连接(right join)返回的结果分别只包含左列和右列

    print(pd.merge(df1, df2, how="left"))
    #     name   food drink
    # 0  Peter   fish   NaN
    # 1   Paul  beans   NaN
    # 2   Mary  bread  wine
    重复列名处置

    可能会遇到两个输入DataFrame有重名列的情况,merge()会自动为其增加后缀_x和_y,也可以通过suffixes参数自定义后缀名。

    df1 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "rank": [1, 2, 3, 4]})
    df2 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "rank": [3, 1, 4, 2]})
    print(df1)
    print(df2)
    print(pd.merge(df1, df2, on="name"))  # 不指定后缀名,默认为_x和_y
    print(pd.merge(df1, df2, on="name", suffixes=("_df1", "_df2")))  # 通过suffixes指定后缀名

    3.7 pandas的缺失值处理函数

    3.7.1 pandas中的缺失值

    pandas使用浮点值NaN(Not a Number)表示缺失数据,使用NA(Not Available)表示缺失值。可以通过isnull()、isna()或notnull()、notna()方法判断某个值是否为缺失值。

    Nan通常表示一个无效的或未定义的数字值,是浮点数的一种特殊取值,用于表示那些不能表示为正常数字的情况,如 0/0、∞-∞等数学运算的结果。nan与任何值(包括它自身)进行比较的结果都为False。例如在 Python 中,nan == nan返回False。

    NA一般用于表示数据不可用或缺失的情况,它的含义更侧重于数据在某种上下文中是缺失或不存在的,不一定特指数字类型的缺失。

    na和nan都用于表示缺失值,但nan更强调是数值计算中的特殊值,而na更强调数据的可用性或存在性。

    s = pd.Series([np.nan, None, pd.NA])
    print(s)
    # 0     NaN
    # 1    None
    # 2    <NA>
    # dtype: object
    print(s.isnull())
    # 0    True
    # 1    True
    # 2    True
    # dtype: bool

    3.7.2 加载数据中包含缺失值

    df = pd.read_csv("data/weather_withna.csv")
    print(df.tail(5))
    #             date  precipitation  temp_max  temp_min  wind weather
    # 1456  2015-12-27            NaN       NaN       NaN   NaN     NaN
    # 1457  2015-12-28            NaN       NaN       NaN   NaN     NaN
    # 1458  2015-12-29            NaN       NaN       NaN   NaN     NaN
    # 1459  2015-12-30            NaN       NaN       NaN   NaN     NaN
    # 1460  2015-12-31           20.6      12.2       5.0   3.8    rain

      Logo

      汇聚全球AI编程工具,助力开发者即刻编程。

      更多推荐