Python 数据分析与机器学习入门 (三):Pandas 数据导入与核心操作
引言:Pandas 是什么,为何如此重要?
如果说 NumPy 是处理原始数值数组的利器,那么 Pandas 则是驾驭结构化数据的瑞士军刀。在真实世界的数据分析项目中,数据很少是单纯的数字矩阵。它们通常以表格形式存在,包含行和列,每列可能有不同的数据类型(如文本、数字、日期),并且带有描述性的列名和行索引。Pandas 正是为高效处理这类数据而生。
Pandas 构建于 NumPy 之上,它不仅继承了 NumPy 的高性能计算能力,还提供了两种极为强大和灵活的数据结构:
Series
和DataFrame
。这使得数据清洗、转换、分析和可视化变得前所未有的简单和直观。对于任何数据分析师或科学家来说,精通 Pandas 是必备技能。
核心数据结构:Series 与 DataFrame
理解 Pandas 的第一步是掌握其两个核心数据结构。
Series
可以看作是一个一维带标签的数组。它类似于电子表格中的一列或数据库表中的一个字段。每个 Series
对象都由数据和与之关联的标签(即索引)组成。
import pandas as pd# 从列表创建 Series
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s)
# 输出:
# a 10
# b 20
# c 30
# d 40
# dtype: int64
DataFrame
这是 Pandas 的核心,一个二维带标签的数据结构,可以看作是一个电子表格、一个 SQL 表,或者一个由多个 Series
对象组成的字典。
DataFrame
的每一列都可以是不同的数据类型。它有行索引和列索引。
# 从字典创建 DataFrame
data = {'State': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],'Year': [2000, 2001, 2002, 2001, 2002],'Population': [1.5, 1.7, 3.6, 2.4, 2.9]}
df = pd.DataFrame(data)
print(df)
# 输出:
# State Year Population
# 0 Ohio 2000 1.5
# 1 Ohio 2001 1.7
# 2 Ohio 2002 3.6
# 3 Nevada 2001 2.4
# 4 Nevada 2002 2.9
关键关系:一个
DataFrame
是由多个Series
共享同一个索引组成的。你可以将DataFrame
的每一列都视为一个Series
。
数据导入:pd.read_csv()
数据分析的第一步通常是加载数据。Pandas 提供了强大的 I/O 工具,可以轻松读取多种格式的文件,其中最常用的是 pd.read_csv()
。
# 从本地 CSV 文件加载数据
# 假设当前目录下有一个名为 'titanic.csv' 的文件
df_titanic = pd.read_csv('titanic.csv')
read_csv()
函数功能非常强大,拥有众多参数。对于初学者,掌握以下几个核心参数至关重要:
filepath_or_buffer
: 文件的路径。这可以是一个本地文件路径,也可以是一个 URL。sep
(或delimiter
): 指定列之间的分隔符。默认是逗号,
。如果文件是制表符分隔(TSV),则应设置为sep='\t'
。header
: 指定哪一行作为列名。默认是0
(第一行)。如果文件没有列名,可以设置为header=None
。usecols
: 一个列表,用于指定只加载哪些列。在处理大文件时,这可以显著节省内存和加载时间。例如:usecols=['Name', 'Age', 'Sex']
。skiprows
: 一个整数或列表,用于跳过文件开头的指定行数。nrows
: 只读取文件的前n
行,这对于快速预览大文件非常有用。
基础检查:初探数据
加载数据后,第一要务是快速了解其概况。Pandas 提供了一系列简洁的方法来完成这项工作:
.head(n)
和.tail(n)
: 查看数据的前 n 行或后 n 行(默认 n=5)。print(df_titanic.head())
.info()
: 提供DataFrame
的简明摘要,包括行数、列数、每列的非空值数量和数据类型。这是检查缺失值的首选方法。df_titanic.info()
.describe()
: 对数值型列生成描述性统计数据,如计数、均值、标准差、最小值、最大值和四分位数。print(df_titanic.describe())
.shape
: 返回一个包含行数和列数的元组。print(df_titanic.shape)
数据选择:loc 与 iloc 的艺术
从 DataFrame
中精确地选取所需数据是数据处理的核心技能。Pandas 提供了两种主要的索引方法:.loc
和 .iloc
。理解它们的区别是成为 Pandas 高手的关键一步。
列选择
- 选择单列(返回一个
Series
):ages = df_titanic['Age']
- 选择多列(返回一个
DataFrame
):subset = df_titanic[['Name', 'Age', 'Sex']]
行选择:.loc
vs. .iloc
这是初学者最容易混淆的地方。一个简单的原则是:.loc
是基于标签 (Label) 的,而 .iloc
是基于位置 (Integer position) 的。
.loc
(基于标签)
- 使用行和列的名称进行选择。
- 切片操作是包含结束标签的。
# 选择索引标签为 0 的行
print(df_titanic.loc[0])# 选择索引标签为 0 到 4 的行,以及 'Name' 和 'Age' 列
print(df_titanic.loc[0:4, ['Name', 'Age']])
.iloc
(基于位置)
- 使用行和列的整数索引(从 0 开始)进行选择。
- 切片操作不包含结束位置,与 Python 标准切片行为一致。
# 选择第一行 (位置 0)
print(df_titanic.iloc[0])# 选择前 5 行 (位置 0 到 4),以及第 4 和第 5 列 (位置 3 和 4)
print(df_titanic.iloc[0:5, [3, 4]])
为什么区分 loc
和 iloc
如此重要?
这不仅仅是语法上的差异,更关乎代码的健壮性和可读性。当你使用
df.iloc[:, 2]
来选择第三列时,如果未来数据源的列顺序发生变化(例如,在前面插入了一列),你的代码就会在不报错的情况下默默地选择了错误的列。而如果你使用df.loc[:, 'Age']
,代码要么继续正确工作,要么在 ‘Age’ 列被重命名或删除时,会明确地抛出KeyError
错误。这种明确性使得.loc
在大多数情况下是更安全、更易于维护的选择。
特性 | .loc | .iloc |
---|---|---|
索引方法 | 基于标签 (Label-based) | 基于位置 (Position-based) |
输入类型 | 行/列的名称(标签) | 行/列的整数位置 |
切片行为 | 包含结束标签 | 不包含结束位置 |
核心用途 | 通过有意义的标签选择数据 | 通过数字位置选择数据 |
示例 | df.loc['row_label', 'col_name'] | df.iloc[row_index, col_index] |
条件选择 (Boolean Indexing)
这是数据筛选最强大、最常用的方式。它允许你根据列中的值来选择行。
# 选择所有年龄大于 30 岁的乘客
adults = df_titanic[df_titanic['Age'] > 30]# 结合多个条件 (使用 & 和 |,注意括号)
# 选择所有头等舱 (Pclass=1) 且年龄大于 30 的女性乘客
wealthy_women = df_titanic[(df_titanic['Pclass'] == 1) & (df_titanic['Sex'] == 'female') & (df_titanic['Age'] > 30)]
print(wealthy_women.head())
总结与展望
您现在已经掌握了使用 Pandas 加载、检查和选择数据的核心技能。这是进行任何数据分析的基础。我们学会了如何从文件中读取数据,如何快速评估数据质量,以及如何使用 .loc
、.iloc
和布尔索引精确地提取我们感兴趣的数据子集。
然而,真实世界的数据往往是“凌乱”的。它可能来自多个源头,需要合并;或者我们需要按类别进行汇总统计。在下一篇文章中,我们将学习 Pandas 更高级的功能:数据聚合与合并,这将使我们能够从原始数据中提炼出更有价值的洞见。