空奈qwq头像
关注
Python 数据分析三剑客:NumPy、Pandas 与 Matplotlib 全解析封面图

Python 数据分析三剑客:NumPy、Pandas 与 Matplotlib 全解析

在数据驱动决策的时代,掌握数据分析能力已经不再是数据科学家的专属技能,而是每一位程序员、产品经理、运营人员都应该具备的基础素养。Python 凭借其丰富的生态系统,成为了数据分析领域的首选语言。而在 Python 数据分析的工具箱中,有三个库你一定绕不开——NumPyPandasMatplotlib,它们被誉为数据分析的"三剑客"。

今天这篇文章,我们就来系统地梳理这三个核心库的核心用法,帮助你从零开始建立数据分析的知识体系。无论你是刚入门的新手,还是想查漏补缺的实践者,都能在这篇文章中找到有价值的内容。


一、NumPy:高效数值计算的基石

NumPy(Numerical Python)是 Python 科学计算的基础库。它提供了高性能的多维数组对象 ndarray,以及大量用于操作这些数组的函数。可以说,没有 NumPy,就没有 Python 数据分析的繁荣生态。

1.1 为什么需要 NumPy

原生的 Python 列表虽然灵活,但在处理大规模数值计算时效率很低。NumPy 的核心优势在于:

  • 内存高效:同类型数据连续存储,比 Python list 占用更少内存

  • 计算速度快:底层用 C 语言实现,向量化操作避免了 Python 循环的开销

  • 功能丰富:内置线性代数、傅里叶变换、随机数生成等高级功能

1.2 数组的创建

NumPy 的核心是 ndarray 对象。创建数组最直接的方式是将 Python 列表传入 np.array()

一维数组:

import numpy as np

list1 = [1, 2, 3]
array = np.array(list1)

print(type(array))  # <class 'numpy.ndarray'>
print(array)        # [1 2 3]

二维数组:

list2 = [[1, 2, 3], [3, 4, 5]]
array2 = np.array(list2)

print(type(array2))  # <class 'numpy.ndarray'>
print(array2)
# [[1 2 3]
#  [3 4 5]]

除了从列表转换,NumPy 还提供了多种便捷的数组创建方法:

方法

作用

示例

np.zeros(shape)

创建全 0 数组

np.zeros((3, 4)) → 3 行 4 列的 0 矩阵

np.ones(shape)

创建全 1 数组

np.ones((2, 3)) → 2 行 3 列的 1 矩阵

np.arange(start, end, step)

创建序列数组

np.arange(8, 18, 1)[8 9 10 ... 17]

np.linspace(start, end, num)

创建等分数组

np.linspace(8, 18, 5)[8. 10.5 13. 15.5 18.]

np.random.randint(low, high, size)

创建随机整数数组

np.random.randint(1, 18, 18)

np.random.randn(shape)

标准正态分布随机数组

np.random.randn(4, 4)

这里特别提一下 arangelinspace 的区别:arange 是按步长生成,不保证包含终点;linspace 是按数量等分,一定会包含起点和终点。在需要精确控制端点时,linspace 往往更可靠。

1.3 索引与切片

掌握数组的索引和切片,是操作数据的第一步。NumPy 的索引语法非常优雅,采用 数组[行索引, 列索引] 的格式。

arr = np.array([[1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]])

# 取单个元素
print(arr[0, 0])      # 1 —— 第一行第一列

# 取整行
print(arr[-1])        # [9 10 11 12] —— 最后一行
print(arr[-1, :])     # 同上,写法更完整

# 取整列
print(arr[:, 1])      # [2 6 10] —— 所有行的第二列
print(arr[:, -1])     # [4 8 12] —— 所有行的最后一列

切片操作的语法是 数组[行起始:结束:步长, 列起始:结束:步长],和 Python 列表切片规则一致,但支持多维同时切片:

print(arr[:2])          # 前两行
print(arr[:2, :2])      # 前两行前两列 → [[1 2] [5 6]]
print(arr[::2, ::2])    # 行和列都隔一个取 → [[1 3] [9 11]]

1.4 Bool 索引

除了按位置取值,NumPy 还支持布尔索引——用一个布尔数组作为"筛子",筛选出满足条件的元素。这是数据分析中最常用的操作之一。

bool_arr = arr > 5
print(bool_arr)
# [[False False False False]
#  [False  True  True  True]
#  [ True  True  True  True]]

print(arr[bool_arr])  # [ 6  7  8  9 10 11 12]

# 也可以直接简写
print(arr[arr < 3])   # [1 2]

布尔索引的强大之处在于,可以组合多个条件进行复杂筛选。比如 arr[(arr > 3) & (arr < 10)] 就能选出大于 3 且小于 10 的所有元素。注意这里要用 &| 而不是 Python 的 and / or,因为我们需要的是逐元素的逻辑运算。

1.5 形状操作

数据分析中经常需要调整数据的维度和形状。NumPy 提供了丰富的形状操作方法:

arr = np.arange(12)  # [0 1 2 ... 11]

# reshape:返回新数组,不修改原数组
arr2 = arr.reshape((2, 6))
print(arr2)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]]
print(arr.shape)  # (12,) —— 原数组不变

# resize:直接修改原数组,无返回值
arr.resize(3, 4)
print(arr)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 转置:行列互换
print(arr.T.shape)  # (4, 3)

# 展平:降低维度为一维
print(arr.flatten())  # [0 1 2 ... 11]

这里有一个容易踩的坑:reshape 不会修改原数组,而 resize 会。另外,无论哪种方式,都要求变形前后元素总数一致,否则会报 ValueError

1.6 数组运算与广播

NumPy 的数组运算支持逐元素的加减乘除,也支持矩阵乘法:

matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])

# 矩阵乘法(点积)
print(matrix_a.dot(matrix_b))
# [[19 22]
#  [43 50]]

而广播(Broadcasting)是 NumPy 中一个极其重要但也容易让人困惑的概念。简单来说,当两个数组形状不同时,NumPy 会尝试将它们"对齐",使得运算可以进行。

标量广播 最好理解——一个数和一个数组相加,相当于这个数和数组中每个元素相加:

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
d = 2
print(a + d)
# [[ 3  4  5]
#  [ 6  7  8]
#  [ 9 10 11]]

数组广播 发生在两个数组维度不完全匹配,但行或列至少有一个方向可以"对齐"的时候:

b = np.array([10, 20, 30])  # 形状 (3,)
c = np.array([[1], [2], [3]])  # 形状 (3, 1)

print(a + b)  # b 的每一行与 a 的对应行相加
# [[11 22 33]
#  [14 25 36]
#  [17 28 39]]

print(a + c)  # c 的每一列与 a 的对应列相加
# [[ 2  3  4]
#  [ 6  7  8]
#  [10 11 12]]

广播虽然方便,但也不是万能的。当两个数组的形状在任何维度上都不匹配时,就会报错:

e = np.ones((4, 4))
print(e + b)  # ValueError:(4,4) 和 (3,) 无法广播

理解广播的关键在于记住一个原则:从右往左对齐维度,长度为 1 的维度可以被扩展,不相等且都不为 1 的维度会报错

1.7 统计运算

NumPy 内置了丰富的统计函数,可以方便地计算总和、均值、标准差等指标:

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

print("总和:", np.sum(arr))          # 45
print("列方向总和:", np.sum(arr, axis=0))  # [12 15 18]
print("行方向总和:", np.sum(arr, axis=1))  # [ 6 15 24]

print("平均值:", np.mean(arr))       # 5.0
print("标准差:", np.std(arr))        # 2.581988897471611
print("方差:", np.var(arr))          # 6.666666666666667
print("最小值:", np.min(arr))        # 1
print("最大值:", np.max(arr))        # 9
print("最小值索引:", np.argmin(arr)) # 0
print("最大值索引:", np.argmax(arr)) # 8

这里的 axis 参数是一个重点。axis=0 表示沿着行的方向运算(即对每一列计算),axis=1 表示沿着列的方向运算(即对每一行计算)。这个规则在 Pandas 中也是通用的,理解了它,后续学习 Pandas 时会轻松很多。


二、Pandas:结构化数据分析的利器

如果说 NumPy 是基础,那么 Pandas 就是 Python 数据分析的"瑞士军刀"。Pandas 构建在 NumPy 之上,提供了两种核心数据结构:Series(一维)和 DataFrame(二维),以及大量用于数据清洗、转换、聚合的工具。

2.1 Series 对象

Series 可以理解为"带索引的一维数组"。它和 NumPy 数组的区别在于,Series 拥有自定义的索引标签。

从列表创建:

import pandas as pd

s1 = pd.Series([1, 2, 3])
# 0    1
# 1    2
# 2    3
# dtype: int64

# 自定义索引
s3 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
# a    1
# b    2
# c    3
# d    4
# dtype: int64

从字典创建:

s2 = pd.Series({'a': 1, 'b': 2, 'c': 3})
# a    1
# b    2
# c    3
# dtype: int64

字典的键自动变成索引,值变成数据。需要注意的是,Series 创建后不建议随意修改索引名,否则可能导致数据全部变为 NaN。

2.2 DataFrame 对象

DataFrame 是 Pandas 中最核心的数据结构,你可以把它想象成一张 Excel 表格——有行、有列、有表头。

从字典创建:

data = {
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 30, 35, 28],
    "城市": ["北京", "上海", "广州", "深圳"],
    "工资": [5000, 7000, 6000, 8000]
}
df = pd.DataFrame(data)
print(df)
#    姓名  年龄  城市    工资
# 0  张三  25  北京  5000
# 1  李四  30  上海  7000
# 2  王五  35  广州  6000
# 3  赵六  28  深圳  8000

从字典创建时,每个键对应一列,键名就是列名。

从列表创建:

data2 = [
    ["张三", 25, "北京", 5000],
    ["李四", 30, "上海", 7000],
    ["王五", 35, "广州", 6000],
    ["赵六", 28, "深圳", 8000]
]
df2 = pd.DataFrame(data2, columns=["姓名", "年龄", "城市", "工资"])

从列表创建时,每个子列表代表一行数据,需要通过 columns 参数指定列名。

2.3 数据查看与基本信息

拿到一个新数据集后,第一步通常是快速了解数据的全貌:

print(df.shape)       # (4, 4) —— 行数和列数
print(df.dtypes)      # 每列的数据类型
print(df.columns)     # 所有列名
print(df.index)       # 行索引信息

print(df.head(3))     # 查看前 3 行
print(df.tail(3))     # 查看后 3 行
print(df.describe())  # 数值列的统计摘要

describe() 是一个非常实用的方法,它会一次性输出数值列的计数、均值、标准差、最小值、四分位数和最大值,让你对数据的分布有一个快速的认知:

             年龄          工资
count   4.000000     4.000000
mean   29.500000  6500.000000
std     4.283173  1290.994449
min    25.000000  5000.000000
25%    27.250000  5750.000000
50%    29.500000  6500.000000
75%    31.250000  7250.000000
max    35.000000  8000.000000

2.4 数据获取

Pandas 提供了多种获取数据的方式,最常用的有三种:

直接用列名取列:

print(df["姓名"])          # 取一列,返回 Series
print(df[["姓名", "年龄"]]) # 取多列,返回 DataFrame

loc 按标签索引:

# 行标签为 0,列标签为"姓名"
print(df.loc[0, "姓名"])   # 张三

# 取多行多列
print(df.loc[[0, 1], ["姓名", "工资"]])

iloc 按位置索引:

# 第 0 行第 0 列
print(df.iloc[0, 0])      # 张三

# 前两行前两列
print(df.iloc[:2, :2])

简单来说,loc 用的是"名字"(索引标签和列名),iloc 用的是"位置"(从 0 开始的整数)。在实际使用中,loc 更常用也更安全,因为它不依赖于列的顺序。

2.5 条件筛选

数据分析中最常见的操作就是按条件筛选数据。Pandas 的条件筛选和 NumPy 的布尔索引思路一致,但表达能力更强:

# 单条件筛选
print(df[df["年龄"] > 28])

# 多条件筛选
print(df[(df["年龄"] > 28) & (df["工资"] >= 7000)])

# 使用 query 方法(更接近 SQL 语法)
print(df.query("年龄 > 28 and 工资 >= 7000"))

query 方法在条件复杂时特别好用,代码更简洁易读,而且执行效率通常也更高。

2.6 排序

排序也是日常分析中的高频操作:

# 按工资降序排序
print(df.sort_values("工资", ascending=False))

# 按多列排序:部门升序,工资降序
print(df.sort_values(["部门", "工资"], ascending=[True, False]))

多列排序时,会先按第一列排序,第一列相同的再按第二列排序,依此类推。

2.7 缺失值处理

真实世界的数据往往是"脏"的,缺失值无处不在。Pandas 提供了完整的缺失值处理方案:

检测缺失值:

print(df.isnull())    # 返回布尔 DataFrame,缺失为 True
print(df.notnull())   # 反之

删除缺失值:

df.dropna()           # 删除包含任何缺失值的行
df.dropna(how="all")  # 只删除全部为缺失值的行
df.dropna(subset=["A", "B"], how="all")  # 关注特定列

填充缺失值:

df.fillna(0)               # 用固定值填充
df.fillna(df.mean())       # 用均值填充
df.fillna(method="ffill")  # 用前一个值填充(前向填充)

删除还是填充,没有标准答案,取决于缺失值的比例和业务含义。如果缺失比例很低且随机,直接删除通常没问题;如果缺失有规律,或者比例较高,就需要考虑填充甚至特征工程了。

2.8 数据透视与分组聚合

数据分析的核心价值在于从不同维度洞察数据。groupbypivot_table 是实现这一目标的利器。

groupby 分组:

# 按部门分组,计算工资总和
print(df.groupby("部门")["工资"].sum())

# 多维度分组,同时计算多个统计量
print(df.groupby(["部门", "城市"])["工资"].aggregate(["sum", "mean"]))

pivot_table 数据透视表:

# 基本透视表
print(df.pivot_table(index="部门", values="工资", aggfunc="sum"))

# 多维度 + 多指标
print(df.pivot_table(
    index=["部门", "城市"],
    values="工资",
    aggfunc=["sum", "mean"]
))

如果你熟悉 Excel 的数据透视表,对 pivot_table 一定会感到亲切。index 对应行标签,columns 对应列标签,values 对应值,aggfunc 对应汇总方式。掌握了分组和透视表,就掌握了数据分析的核心方法论。


三、Matplotlib:让数据开口说话

数据可视化是数据分析流程中不可或缺的一环。一图胜千言,好的图表能让数据中的规律和异常一目了然。Matplotlib 是 Python 中最基础也是最灵活的绘图库。

3.1 中文显示问题

使用 Matplotlib 时,第一个需要解决的就是中文显示问题。默认配置下,中文会显示为方框,需要手动设置字体:

import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置中文字体
plt.rcParams["axes.unicode_minus"] = False    # 解决负号显示问题

这两行代码几乎是所有中文绘图的标配,建议放在绘图代码的最前面。

3.2 折线图入门

我们从最简单的折线图开始,感受 Matplotlib 的基本用法:

import numpy as np

arr1 = np.array([1, 2, 3, 4])
arr2 = [4, 5, 6, 6]

fig, ax = plt.subplots()
ax.plot(arr1, arr2)
ax.set(xlabel="横轴", ylabel="纵轴", title="测试折线图")
ax.grid()
plt.show()

这段代码展示了 Matplotlib 的标准绘图流程:创建画布和坐标轴 → 调用绘图方法 → 设置标签和标题 → 显示图表。这种"面向对象"的写法虽然比 plt.plot() 稍长,但代码结构更清晰,在绘制复杂图表时优势明显。

3.3 学习建议

Matplotlib 的功能非常强大,支持折线图、柱状图、散点图、饼图、热力图、箱线图等几十种图表类型,还可以自定义颜色、图例、标注、子图布局等。

但实话实说,对于初学者而言,不必一开始就深入钻研 Matplotlib 的所有细节。原因有三:

第一,Matplotlib 的 API 比较底层,要画出美观的图表需要大量的参数配置,学习曲线较陡。第二,现在有很多基于 Matplotlib 封装的高级库(如 Seaborn、Plotly),用更少的代码就能画出更好看的图。第三,AI 时代,完全可以借助 AI 工具快速生成图表代码,把精力放在理解数据和分析逻辑上。

我的建议是:掌握基本的绘图流程和核心概念,了解常见图表的适用场景,具体的代码细节在需要的时候查文档或问 AI 即可。数据分析的核心是"分析",而不是"画图"。


四、三剑客的协同作战

单独看每个库各有所长,但真正的威力在于它们的配合。一个典型的数据分析流程是这样的:

  1. 数据获取:用 Pandas 读取 CSV、Excel 或数据库中的数据

  2. 数据清洗:用 Pandas 处理缺失值、重复值、异常值

  3. 数值计算:必要时转换为 NumPy 数组进行高性能计算

  4. 数据聚合:用 Pandas 的 groupby 和透视表做多维分析

  5. 可视化呈现:用 Matplotlib(或 Seaborn)将结果可视化

举个简单的例子,假设我们有一份销售数据:

# 1. 读取数据(Pandas)
df = pd.read_csv("sales.csv")

# 2. 清洗数据(Pandas)
df = df.dropna(subset=["销售额"])

# 3. 计算同比增长率(NumPy 向量化运算)
df["同比增长率"] = (df["本年销售额"] - df["上年销售额"]) / df["上年销售额"] * 100

# 4. 按地区汇总(Pandas)
region_sales = df.groupby("地区")["销售额"].sum().sort_values(ascending=False)

# 5. 绘制柱状图(Matplotlib)
fig, ax = plt.subplots(figsize=(10, 6))
region_sales.plot(kind="bar", ax=ax)
ax.set_title("各地区销售额对比")
ax.set_ylabel("销售额(万元)")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

在这个流程中,Pandas 承担了大部分工作,NumPy 在需要数值计算时提供支持,Matplotlib 负责最后的呈现。三者各司其职又无缝衔接,构成了 Python 数据分析的黄金组合。


五、学习路径与心得

聊完了技术本身,最后分享几点学习心得,希望能帮你少走一些弯路。

第一,动手实践远比看教程重要。 数据分析是一门实践性极强的技能,看十遍教程不如亲手写一遍代码。找一份感兴趣的数据集(Kaggle 上有很多),尝试用学到的方法去分析它,遇到问题再去查资料,这样的学习效率最高。

第二,理解原理比死记 API 更有价值。 NumPy、Pandas 的函数和参数非常多,没人能全部记住。重要的是理解核心概念——比如广播机制、axis 方向、分组聚合的逻辑。理解了原理,具体的函数名和参数随时可以查文档。

第三,善用 AI 工具,但不要依赖。 AI 时代,写代码的方式已经发生了很大变化。你可以用 AI 快速生成代码模板、解释报错信息、优化性能。但前提是你得能看懂代码、判断对错,否则 AI 生成的东西你也用不好。工具是放大器,不是替代品。

第四,从业务出发,而不是从技术出发。 数据分析的终极目的是解决业务问题。技术只是手段,理解业务背景、提出正确的问题、给出有价值的洞察,这些能力比掌握多少个函数重要得多。拿到数据后先别急着写代码,想一想:我要回答什么问题?数据能帮我吗?


最后

NumPy、Pandas、Matplotlib 这"三剑客",构成了 Python 数据分析的基础设施。NumPy 提供了高效的数值计算能力,Pandas 让结构化数据的处理变得简单优雅,Matplotlib 则让数据可视化成为可能。

当然,数据分析的世界远不止这些。数据获取、特征工程、机器学习、数据挖掘……每一个方向都有广阔的天地。但打好基础永远是第一步。把这三个库的核心用法吃透,你就拥有了进一步探索的底气。

希望这篇文章能为你的数据分析学习之路提供一份清晰的地图。路漫漫其修远兮,吾将上下而求索。与君共勉。


如果你觉得这篇文章对你有帮助,欢迎点赞收藏,也欢迎在评论区交流你的学习心得。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/wiwiwiwiooo/article/details/165006635

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--