pandas-数据结构与数据查看

Posted by Hilda on July 21, 2025

在数据科学领域,Python 是最受欢迎的编程语言之一,但它在数据处理和分析方面的原生能力相对有限。pandas 是一个强大的库,它为 Python 补足了这一短板,能够在 Python 中完成从数据清洗、整理到分析、建模的整个工作流程,而无需切换到其他语言,如 R。

pandas 提供了快速、灵活且直观的数据结构,旨在简单地处理各种关系型或标记型数据。它与 Jupyter 等工具以及 NumPyMatplotlibScikit-learn 等库协同工作,共同构建了一个高效、强大的数据分析环境。

pandas非常强大,比numpy强大,或者说基于numpy才会有pandas。

pandas 的核心理念是为数据分析提供“表格”状的数据结构,这比原生 Python 的列表或字典更适合处理大规模、异构的数据。这些数据结构在底层是基于高度优化的 NumPy 数组实现的,这意味着它们继承了 NumPy 的快速计算能力。同时,pandas 在 NumPy 的基础上增加了标签索引功能,使得数据操作不再依赖于简单的整数位置,而是可以通过有意义的标签进行,这极大地提高了代码的可读性和健壮性。

在开始之前,确保已经安装了 pandas 库:

1
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple

image-20250720193328475

1.数据结构

1.1 Series

Series 是一种一维的、带标签的数据结构,可以看作是带有标签索引的 NumPy 数组。它由两个主要部分组成:数据(values)索引(index)

  • 数据(values): 存储 Series 中的实际数据,可以是任何 NumPy 支持的数据类型。
  • 索引(index): 为每个数据点提供标签,可以是整数、字符串或其他可哈希的 Python 对象。如果未指定索引,pandas 会自动生成从 0 开始的整数索引。

一个重要的特性是,无论是 NumPy 中的 np.nan 还是原生 Python 的 None,在 pandas 中都会被视为缺失数据,并统一表示为 NaN(Not a Number)。

Series 的强大之处在于其索引。这个索引不仅提供了标签访问的便利,更重要的是,它在多个 Series 或 DataFrame 之间进行算术运算时,能够自动对齐数据。当对两个 Series 进行操作时,pandas 会根据它们的索引标签进行匹配,如果某个标签在其中一个 Series 中缺失,相应位置的计算结果将是 NaN。这种【自动对齐机制】避免了因数据顺序不一致而导致的错误。

【1】使用列表生成Series,pandas自动添加整数索引。

1
2
3
4
5
import pandas as pd
import numpy as np
l = [0, 1, 9, 8, 23, 98, np.nan, None, 1026]
s1 = pd.Series(data = l)   # 或者s1 = pd.Series(l)
s1

image-20250720193749392

【2】指定行索引和数据类型

1
2
s2 = pd.Series(data = l, index = list("ABCDEFGHI"), dtype="float32")
s2

image-20250720193938602

【3】从字典创建Series,字典的键作为索引

1
2
s3 = pd.Series(data={'a':99, "b": 90, "C":888}, name="Python_score")
s3

image-20250720194052177

【4】索引和切片:

整数索引:

1
display(s2, s2[2], s2.iloc[2])

现在不推荐s2[2],更推荐的是s2.iloc[2]写法。

image-20250720194247347

标签索引:

image-20250720194318569

标签切片:(左边右边都包含)

image-20250720194344244

选择题

  1. 以下关于 pandas Series 和 NumPy 数组的说法,哪一项是错误的?

    A. Series 支持带有标签的索引。 B. Series 只能包含同一种数据类型。 C. Series 可以由 NumPy 数组创建。 D. Series 支持自动数据对齐。

    答案:B,虽然 Series 通常是同一种类型,但如果包含不同类型的数据(例如整数和字符串),其 dtype 将变为 object

    image-20250720194516122

  2. 给定 s = pd.Series([10, 20, 30], index=['a', 'b', 'c']),以下哪种方式会返回一个包含 2030 的新 Series?

    A. s[1:3] B. s['b':'c'] C. A 和 B 都正确。 D. A 和 B 都错误。

    答案:C,s[1:3] 是整数位置切片,左闭右开,返回索引 1 和 2 的元素。

    s['b':'c'] 是标签切片,左闭右闭,返回索引 'b''c' 的元素。

编程题

  1. 创建一个名为 product_prices 的 Series,数据为 [15.5, 20.0, 12.8, 18.2],索引分别为 'Apple', 'Orange', 'Banana', 'Grape'
  2. 使用标签索引访问 'Banana' 的价格。
  3. 使用整数位置索引访问 'Orange' 的价格。
1
2
product_prices = pd.Series(data=[15.5, 20.0, 12.8, 18.2], index = ["Apple", "Orange", "Banana", "Grape"])
display(product_prices, product_prices["Banana"], product_prices.iloc[1])

image-20250720194832047

1.2 DataFrame

DataFrame 是 pandas 的核心数据结构,它是一个二维的、带标签的数据结构,类似于 Excel 表格、SQL 数据库表,或者是 Series 对象的字典。DataFrame 具有行索引和列索引,这让它非常灵活。

DataFrame 的数据可以由多种类型构成,每一列(column)都可以是不同的数据类型,但一列中的所有数据通常是同一种类型。

DataFrame 在内部可以被看作是一个共享相同行索引的 Series 对象的字典。它的行索引(index)列索引(columns) 提供了双重的标签对齐能力。这种结构使得数据处理和分析变得非常直观:

  • 列操作: 您可以像操作字典一样操作 DataFrame 的列,例如 df['column_name']
  • 行操作: 您可以使用切片或标签索引来选择行。
  • 数据对齐: 当进行操作时,pandas 会同时根据行和列标签进行对齐,确保即使数据顺序或缺失值不同,计算结果也是正确的。

【1】从字典创建DataFrame

1
2
df = pd.DataFrame(data={"Python":[99, 107, 122], "Math":[111, 37, 88], "En":[89, 109, 67]}, index = ["Adele", "Bob", "Cathy"], columns=["Python", "Math", "En"])
df

image-20250720195227232

【2】从numpy数组创建DataFrame:

1
2
3
4
5
data = np.random.randint(0, 151, (5, 3))
index = ["Adele", "Bob", "David", "Zed", "John"]
columns = ["Python", "Math", "En"]
df = pd.DataFrame(data = data, index = index, columns=columns)
df

image-20250720195431166

【3】访问列:

1
df["Python"]

image-20250720195603296

选择题

  1. 以下关于 DataFrame 的说法,哪一项是正确的?

    A. DataFrame 只能包含一种数据类型。 B. DataFrame 类似于一维的 Series。 C. DataFrame 具有行索引和列索引。 D. DataFrame 总是从 NumPy 数组创建。

    答案:C

  2. 如果一个 DataFrame 的行索引和列索引都是字符串,如何使用 .loc 访问名为 'a' 的行和名为 'b' 的列的交汇处的元素?

    A. df['a']['b'] B. df.loc['a', 'b'] C. df.iloc['a', 'b'] D. df['a', 'b']

    答案:B,df.loc 是基于标签的索引器,用于访问行和列。

编程题

  1. 创建一个 DataFrame,包含两列 'Name''Age',以及三行数据。
  2. 为这个 DataFrame 添加一列 'City',并为每一行赋一个城市名。
  3. 打印出添加列后的 DataFrame。
1
2
3
4
5
data = {"Name": ["Adele", "Bob", "David"], "Age": [18, 19, 20]}
df = pd.DataFrame(data = data, columns=["Name", "Age"])
display(df)
df["City"] = ["北京", "上海", "杭州"]
display(df)

image-20250721130107498

2.数据查看

在数据分析的初期,数据探索是至关重要的。pandas 提供了多种方法和属性来快速查看 DataFrame 的基本信息、形状、数据类型和统计概览。

  • df.head(n): 查看 DataFrame 的前 n 行,默认显示前 5 行。
  • df.tail(n): 查看 DataFrame 的后 n 行,默认显示后 5 行。
  • df.shape: 一个元组,表示 DataFrame 的维度(行数, 列数)。
  • df.dtypes: 返回一个 Series,显示每列的数据类型。
  • df.index: 返回行索引对象。
  • df.columns: 返回列索引对象。
  • df.values: 返回一个 NumPy ndarray,包含 DataFrame 的所有值。
  • df.describe(): 生成数值型列的汇总统计信息,包括计数、均值、标准差、最小值、四分位数和最大值。
  • df.info(): 打印出 DataFrame 的简明摘要,包括索引类型、列索引、数据类型、非空值的数量和内存使用情况。

这些查看方法是数据分析工作流的第一步,它们能够提供关于数据质量和分布的快速洞察。df.info() 在底层遍历 DataFrame 的所有列,并检查每个列的元数据和内存使用情况,这比手动检查每一列的 isnull().sum() 更快,尤其是在大型数据集中。df.describe() 则在底层对每一列的 NumPy 数组执行快速的聚合计算,生成汇总统计信息。这些方法之所以高效,是因为它们充分利用了 pandas 的 C 语言底层实现。


【1】准备150*3 的数据:

1
2
3
data = np.random.randint(0, 151, (150, 3))
df = pd.DataFrame(data=data, columns=["Python", "Math", "En"])
display(df)

image-20250721130523982

【2】查看前10行:

1
df.head(10)

image-20250721130608212

【3】查看后10行

1
df.tail(10)

image-20250721130642379

【4】查看形状

image-20250721140403906

【5】数据类型:

image-20250721140444875

【6】查看索引:

行索引与列索引

image-20250721140549261

image-20250721140801849

【7】查看对象值(底层是二维的numpy数组)

image-20250721140848755

【8】查看数值型列的汇总统计

image-20250721140935533

【9】概览和非空计数

image-20250721141012821

选择题

  1. 以下哪个方法主要用于快速了解 DataFrame 中是否存在缺失值、数据类型是否正确以及内存使用情况?

    A. df.describe() B. df.head() C. df.info() D. df.shape

    答案:C,info() 提供了关于数据类型、非空计数和内存使用的摘要信息。

  2. df.describe() 的输出结果中,哪一项通常不包含在内?

    A. 均值(mean) B. 四分位数(25%, 50%, 75%) C. 非空计数(non-null count) D. 最大值(max)

    答案:C,df.describe() 只对数值型数据进行统计,不报告非空计数。非空计数由 df.info() 提供。

编程题

  1. 创建一个包含 3 列 (A, B, C) 和 5 行的 DataFrame,并用随机数填充。
  2. C 列的第 2 和第 4 个元素手动赋值为 np.nan
  3. 使用 df.info() 打印 DataFrame 的摘要,并观察 C 列的非空计数变化。
1
2
3
4
5
data = np.random.randint(0, 151, (5, 3))
df = pd.DataFrame(data=data, columns=["A", "B", "C"])
df.loc[[1, 3], "C"] = np.nan
display(df)
df.info()

image-20250721141547599