03. Pandas库的使用

一、Pandas库简介

  Pandas 是基于 NumPy 构建的专门用于处理表格和混杂数据设计的 Python 库,核心设计理念包括:

  • 标签化数据结构,提供带标签的轴。
  • 灵活处理确实数据,内置 NaN 处理机制。
  • 智能数组对齐,自动按标签对齐数据。
  • 强大的 IO 工具,支持从 CSC、Excel、SQL 等 20+ 数据源读写。
  • 时间序列处理,原生支持日期时间处理和频率转换。

  我们可以终端中使用 pip 安装 pandas 包。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pandas  -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

二、 pandas的数据结构

  Pandas 提供了两个主要数据结构:Series 和 DataFrame。

特性 Series DataFrame
维度 一维 二维
索引 单索引 行索引 + 列名
数据存储 同质化数据类型 各列可不同数据类型
类比 Excel 单列 整张 Excel 工作表
创建 pandas.Series([1, 2, 3]) pandas.DataFrame({"col": [1, 2, 3]})

2.1、Series

2.1.1、Series的创建

  Series 是一种类似于一维数组的对象,它由一组(类似 NumPy 数据类型的)数据以及一组与之相关的数据标签(即索引)组成。仅由一个数组即可创建最简单的 Series。

import pandas as pd

series = pd.Series([10, 20, 30])
print(series)

  Series 字符串以交互式的方式呈现,索引位于左边,值位于右边。由于我们没有为数据指定索引,因此会自动创建一个 0 到 N-1(N 为数据的长度)的整数型索引。如果我们要自定义索引,可以使用 index 参数指定。

import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"])
print(series)

  我们在创建 Series 的时候,我们可以使用 name 参数 指定索引的标签

import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"], name='Monthly Sales')
print(series)

  如果数据已经存放在一个Python 字典中,也可以通过传入这个字典来创建 Series。

import pandas as pd

monthly_sales = {'January': 100, 'February': 200, 'March': 300}
series = pd.Series(monthly_sales, name='Monthly Sales')
print(series)

  在使用字典的方式或者传入一个已经创建 Series 对象时创建新的 Series时,我们可以使用 index 参数指定使用那些键值对。

import pandas as pd

monthly_sales = {"January": 100, "February": 200, "March": 300}
series1 = pd.Series(monthly_sales, index=["January", "March"], name="Monthly Sales")
print(series1)

series2 = pd.Series(series1, index=["March"], name="Monthly Sales")
print(series2)

2.1.2、Series的属性

  Series 中常用的属性如下:

index                                                                           # 索引对象
values                                                                          # 值
dtype                                                                           # 元素类型
dtypes                                                                          # 元素类型
shape                                                                           # 形状
ndim                                                                            # 维数
size                                                                            # 元素个数
name                                                                            # 名称
import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"], name="Monthly Sales")

print("索引对象:", series.index)                                                # 索引对象
print("值:", series.values)                                                    # 值
print("形状:", series.shape)                                                   # 形状
print("维度:", series.ndim)                                                    # 维度
print("大小:", series.size)                                                    # 大小
print("数组类型:", series.dtype)                                                # 数据类型
print("数组类型:", series.dtypes)                                               # 数据类型
print("名字:", series.name)                                                    # 名字

2.1.3、访问Series的数据

  与 NumPy 的数组相比,我们还可以通过索引的标签来访问 Series 中的数据。

import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"], name="Monthly Sales")

print(series[1])
print(series["February"])

  虽然,我们可以使用 Series[] 的方式用 标签 选取数据,但是这里更推荐使用 Series.loc[]Series.iloc[] 运算符选择索引。这是因为,当我们使用 Series[] 进行索引时,针对整数的处理有所不同。如果索引包含整数,常规的 Series[] 的索引会将整数用作标签。Series.loc[] 运算符只使用 标签,而 Series.iloc[] 运算符只使用 默认生成的整数索引

import pandas as pd

series = pd.Series([100, 200, 300], index=[1, 2, 3], name="Monthly Sales")

print(series[1])
print(series.loc[1])
print(series.iloc[1])

  我们还可以使用标签进行切片,但区别于普通 Python 的切片方式,Series.loc[] 的切片是 包含末端 的。

import pandas as pd

monthly_sales = {"january": 100, "february": 200, "march": 300, "april": 400, "may": 500}
series = pd.Series(monthly_sales, name="Monthly Sales")
print(series.loc["february": "april"])

  我们还可以使用 Series.at[]Series.iat[] 的方式访问数据,它们的使用与 Series.loc[]Series.iloc[] 类似。

import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"], name="Monthly Sales")
print(series.at["February"])
print(series.iat[1])

  在 Series 中,我们可以使用布尔索引的方式进行刷选。

import pandas as pd

series = pd.Series([100, 200, 300], index=["January", "February", "March"], name="Monthly Sales")
print(series[series > 150])

2.1.4、Series的方法

import pandas as pd
import numpy as np

dictionaries = {"A": 100, "B": 200, "C": None, "D": np.nan, "E": 500, "F": 300, "G": 100}
series = pd.Series(dictionaries, name="Monthly Sales")

print("前三行数据:")
print(series.head(3))                                                           # 查看前n行数据,默认前5行
print("后三行数据")
print(series.tail(3))                                                           # 查看后n行数据,默认后5行

print("所有描述信息")
print(series.describe())                                                        # 查看所有描述信息

print("元素个数:", series.count())                                              # 获取元素个数,忽略缺失值
print("获取索引:", series.keys())                                               # 获取索引

print("获取是否是缺失值")
print(series.isna())                                                            # 获取是否是缺失值,返回布尔值

print("获取是否包含在参数列表中")
print(series.isin([300, 700]))                                                  # 获取是否包含在参数列表中,返回布尔值

print("平均数:", series.mean())                                                 # 获取平均数,忽略缺失值
print("中位数:", series.median())                                               # 获取中位数,忽略缺失值
print("标准差:", series.std())                                                  # 获取标准差,忽略缺失值
print("最大值:", series.max())                                                  # 获取最大值,忽略缺失值
print("最小值:", series.min())                                                  # 获取最小值,忽略缺失值
print("总和:", series.sum())                                                    # 获取总和,忽略缺失值
print("25%分位数:", series.quantile(0.25))                                      # 获取25%分位数,忽略缺失值
print("75%分位数:", series.quantile(0.75))                                      # 获取75%分位数,忽略缺失值
print("众数:", series.mode())                                                   # 获取众数(出现最多次数的数),忽略缺失值

print("绝对值:")
print(series.abs())                                                             # 绝对值

print("每个数出现的次数")
print(series.value_counts())                                                    # 每个数出现的次数,忽略缺失值

print("去重后的数据")
print(series.drop_duplicates())                                                 # 去重

print("去重后的数据")
print(series.unique())                                                          # 去重

print("去重后数据个数:", series.nunique())                                        # 去重后数据个数,忽略缺失值

print("按值升序排序:")
print(series.sort_values())                                                     # 排序,默认升序

print("按值降序排序:")
print(series.sort_values(ascending=False))                                      # 排序,降序

print("按索引升序排序:")
print(series.sort_index())                                                      # 排序,默认升序

print("按索引降序排序:")
print(series.sort_index(ascending=False))                                       # 排序,降序

print("与前一个元素的差值:")
print(series.diff())                                                            # 与前一个元素的差值

2.2、DataFrame

  DataFrame 是矩形的数据表,它含有一组有序且有命名的列,每一列可以是不同的数据类型(数值、字符串、布尔值等)。DataFrame 既有行索引也有列索引,可以看作由共用同一个索引的 Series 组成的字典。

2.2.1、DataFrame的创建

  有多种创建 DataFrame 的方式,我们可以使用 Series 来创建 DataFrame。

import pandas as pd

s1 = pd.Series([1, 2, 3, 4, 5])
s2 = pd.Series([6, 7, 8, 9, 10])
df = pd.DataFrame([s1, s2])
print(df)
print(type(df))

  我们还可以通过字典的键值对来创建 DataFrame。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])
print(df)

  我们还可以通过列表的方式构建 DataFrame。

import pandas as pd

person_info = [
    ["Sakura", 10],
    ["Mikoto", 14],
    ["Shana", 15]
]

df = pd.DataFrame(person_info, columns=["name", "age"], index=["1st", "2nd", "3rd"])
print(df)

2.2.2、DataFrame的属性

  DataFrame 中常用的属性如下:

index                                                                           # 行索引
columns                                                                         # 列标签
values                                                                          # 值
dtypes                                                                          # 元素类型
shape                                                                           # 形状
ndim                                                                            # 维数
size                                                                            # 元素个数
T                                                                               # 转置
import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

print("行索引:", df.index)
print("列标签:", df.columns)
print("数据:\n", df.values)
print("数据类型\n", df.dtypes)
print("维度:", df.ndim)
print("大小:", df.size)
print("形状:", df.shape)
print("转置:\n", df.T)

2.2.3、访问DataFrame的数据

  我们可以 DataFrame["列名"]DataFrame.列名 的方式访问某列数据,它的返回类型是一个 Series。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

# 获取某列数据
name = df["name"]
print(name)
print(type(name))

age = df.age
print(age)
print(type(age))

  我们还可以使用 DataFrame[["列名"] 的方式获取某几列的数据,此时它的类型是 DataFrame 类型。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15],
    "sex": ["女", "女", "女"]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

# 获取某列数据
name = df[["name"]]
print(name)
print(type(name))

# 获取多列数据
print(df[["name", "age"]])

  我们还可以使用 DataFrame.loc[]DataFrame.iloc[] 运算符选择索引。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

# 获取某行数据
print(df.loc["2nd"])
print(df.iloc[1])

# 获取某列数据
print(df.loc[:, "name"])
print(df.iloc[:, 0])

# 获取某行某列数据
print(df.loc["2nd", "age"])
print(df.iloc[1, 1])

  我们还可以使用 DataFrame.at[]DataFrame[] 的方式访问数据,它们的使用与 DataFrame.loc[]DataFrame.iloc[] 类似。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

# 获取某行某列数据
print(df.at["2nd", "name"])
print(df.iat[1, 0])

  在 DataFrame 中,我们可以使用布尔索引的方式进行刷选。

import pandas as pd

person_info = {
    "name": ["Sakura", "Mikoto", "Shana"],
    "age": [10, 14, 15]
}

df = pd.DataFrame(person_info, index=["1st", "2nd", "3rd"])

print(df[df.age <= 10])
print(df[(df["age"] > 10) & (df["age"] < 15)])

2.3.4、DataFrame的方法

import pandas as pd

person_info = {
    "name": ["木之本樱", "桔梗", "夏娜", "御坂美琴", "白钰袖", "风铃儿", "木之本樱", "夏娜"],
    "age": [10, 18, 15, 14, 16, 16, 12, 15]
}

df = pd.DataFrame(person_info)

print("后三行数据:\n", df.tail(3))                                              # 查看后n行数据,默认后5行
print("随机采样3行数据:\n", df.sample(3))                                       # 随机采样n行数据
print("查看元素是否包含在参数集合中:\n", df.isin([10, 15]))                       # 判断元素是否包含在参数集合中
print("获取是否是缺失值:\n", df.isna())                                         # 获取是否是缺失值,返回布尔值
print("获取是否是缺失值:\n", df.isnull())                                       # 获取是否是缺失值,返回布尔值
print("所有描述信息:\n", df.describe())                                         # 查看所有描述信息                     
print("元素个数:", df.count())                                                  # 获取元素个数,忽略缺失值
print("获取索引:", df.keys())                                                   # 获取索引
print("每行数据出现的次数:\n", df.value_counts())                                # 每个数出现的次数,忽略缺失值                                          
print("去重后的数据:\n", df.drop_duplicates())                                  # 去重  
print("检查是否有重复数据:\n", df.duplicated())                                  # 检查是否有重复数据
print("去重后数据个数:\n", df.nunique())                                        # 去重后数据个数,忽略缺失值
print("总和:\n", df.sum())                                                     # 求和
print("最大值:\n", df.max())                                                    # 最大值
print("最小值:\n", df.min())                                                    # 最小值 
print("累计:\n", df.cumsum())                                                  # 累计
print("按索引降序排序:\n", df.sort_index(ascending=False))                      # 按索引排序
print("按值排序:", df.sort_values(by=["name", "age"], ascending=[True, False])) # 按值排序
print("前2条最大数据", df.nlargest(2, columns=["age"]))                          # 前n条最大数据
print("前2条最小数据", df.nsmallest(2, columns=["age"]))                         # 前n条最小数据

三、时间序列

  在 Pandas 中,我们可以使用 pandas.Timestamp("时间格式字符串") 的方式获取对应时间的时间戳。

import pandas as pd

date = pd.Timestamp("1987-04-01 00:30:10")

print(date.year)
print(type(date))
print(f"年:{date.year}, 月:{date.month}, 日:{date.day}, 時:{date.hour}, 分:{date.minute}, 秒:{date.second}")
print(f"季度: {date.quarter}")
print(f"星期: {date.day_name()}")

  通过使用 pandas.to_period() 方法,可以将由时间戳索引的 Series 和 DataFrame 对象转换为以周期作为索引:

import pandas as pd

date = pd.Timestamp("1987-04-01 00:30:10")

print("转换为天:", date.to_period("D"))
print("转换为周维度:", date.to_period("W"))
print("转换为月度:", date.to_period("M"))
print("转换为季度:", date.to_period("Q"))
print("转换为年度:", date.to_period("Y"))

  如果我们要把一个日期格式的字符串转换成日期格式,则可以使用 pandas.to_datetime("日期格式的字符串") 方法解析多种不同的日期表示形式。

import pandas as pd

date = pd.to_datetime("1987-04-01 00:30:10")

print(date)
print(type(date))

  Pandas 最基本的时间序列类型就是以 时间戳索引Series,时间戳通常以 Python 字符串或 datatime.datatime 对象表示。我们可以使用 pandas.date_range(日期1, 日期2) 方法生成一个日期范围的标签。默认情况下, pandas.date_range(日期1, 日期2) 方法会生成每日的时间戳。

import pandas as pd

index = pd.date_range("2000-01-01", "2000-01-10")
# 在底层,这些datetime对象实际上是放在DatetimeIndex中的
print(index)

  如果只传入起始日期或结束日期,还必须传入要生成的周期个数:

import pandas as pd

index = pd.date_range("2000-01-01", periods=10)
print(index)

# end参数指定结束日期
index = pd.date_range(end="2000-01-01", periods=10)
print(index)

  如果想要生成一个时间区间内符合频率要求的日期序列,则可以自己指定 freq 参数。例如如果想要生成一个由每月最后一个工作日组成的日期索引,可以将 freq 参数指定为 "BM"(表示 business end of month)。

  常见的基本时间序列频率如下:

参数值 偏移量类型 说明
D Day 日历日的每天
B BusinessDay 工作日的每天
H Hour 每时
T 或 min Minute 每分
S Second 每秒
L 或 ms Milli 每毫秒
U Micro 每微秒
MS MonthBegin 每月第一个工作日
M 或 ME MonthEnd 每月最后一个日历日
BMS BusinessMonthBegin 每月第一个工作日
BM 或 BME BusinessMonthEnd 每月最后一个工作日
W-MON, W-TUE, ... Week 从指定的星期几开始算起,每周取日期
WOM-1MON, WOM-2MON, ... WeekOfMonth 产生每月第一、第二、第三或第四周的星期几
QS-JAN, QS-FEB, ... QuarterBegin 对于以指定月份结束的年度,每季度最后一月的第一个日历日
Q-JAN, Q-FEB, ... QuarterEnd 对于以指定月份结束的年度,每季度最后一月的最后一个日历日
BQS-JAN, BQS-FEB, ... BusinessQuarterBegin 对于以指定月份结束的年度,每季度最后一月的第一个工作日
BQ-JAN, BQ-FEB, ... BusinessQuarterEnd 对于以指定月份结束的年度,每季度最后一月的最后一个工作日
AS-JAN, AS-FEB, ... YearBegin 每年指定月份的第一个日历日
A-JAN, A-FEB, ... YearEnd 每年指定月份的最后一个日历日
BAS-JAN, BAS-FEB, ... BusinessYearBegin 每年指定月份的第一个工作日
BA-JAN, BA-FEB, ... BusinessYearEnd 每年指定月份的最后一个工作日
import pandas as pd

index = pd.date_range("2000-01-01", "2000-12-31", freq="BM")
print(index)

index = pd.date_range("2000-01-01", periods=12, freq="BM")
print(index)

  date_range() 方法默认会保留起始时间戳和结束时间戳的时间信息(如果有的话)。

import pandas as pd

index = pd.date_range("2000-01-01", periods=12, freq="BM")
print(index)

  我们还可以使用 pandas.resample() 方法进行重采样。重采样指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据连接到低频率称为降采样,而将低频率数据转换到高频率则称为升采样。

import pandas as pd

data = {
    "date": pd.date_range(start="2000-01-01", end="2000-12-31", freq="D"), 
    "value": range(366)
} 
df = pd.DataFrame(data) 


df.set_index("date", inplace=True)                                              # 将日期列设置为索引 

# 使用resample()方法进行重新采样 
# 将每日数据转换为每月数据并计算每月的总和 
monthly_data = df['value'].resample('ME').sum() 

# 将每月数据转换为每季度数据并计算每季度的平均值 
quarterly_data = monthly_data.resample('QE').mean() 

# 将每季度数据转换为每年数据并计算每年的最大值 
annual_data = quarterly_data.resample('YE').max() 

print(monthly_data) 
print(quarterly_data) 
print(annual_data)

四、读写文件

4.1、读写CSV文件

  我们可以使用 DataFrame.to_csv("文件路径") 的方式将数据保存到一个 CSV 文件中。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 15],
    ["白钰袖", 16],
    ["桔梗", 18]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
df.to_csv("person_info.csv")

  我们可以使用 DataFrame = read_csv("文件路径") 的方式读取一个 CSV 文件中的内容。

import pandas as pd

df = pd.read_csv("person_info.csv")
print(df)

4.2、读写JSON文件

  我们可以使用 DataFrame.to_json("文件路径") 的方式将数据保存到一个 JSON 文件中。

import pandas

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 15],
    ["白钰袖", 16],
    ["桔梗", 18]
]

dataFrame = pandas.DataFrame(person_info, columns=["姓名", "年龄"])

dataFrame.to_json("person_info.json")

  我们可以使用 DataFrame = read_json("文件路径") 的方式读取一个 JSON 文件中的内容。

import pandas as pd

df = pd.read_json("person_info.json")
print(df)

如果是较为复杂的 JSON 文件,推荐使用 Python 自带的 json 模块的 json.load() 方法读取到文件中的内容到字典中,在用字典构造 DataFrame 的方式使用。

五、数据清洗

5.1、处理缺失值

5.1.1、判断是否有缺失值

  读取数据之后,我们可以使用 DataFrame.isna() 方法或者 DataFrame.isnull() 方法判断数据中是否包含缺失值。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", pd.NA],
    ["涂山苏苏", None],
    ["桔梗", 18]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.isna())
print(df.isnull())

  如果我们要查看缺失值的个数,可以在后面在调用 DataFrame.sum() 方法。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", pd.NA],
    ["涂山苏苏", None],
    ["桔梗", 18]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.isnull().sum())

5.1.2、剔除缺失值

  如果我们要剔除缺失值,可以使用 DataFrame.dropna() 方法。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", pd.NA],
    ["涂山苏苏", None],
    ["桔梗", 18]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.dropna())

  只要 DataFrame 中的一行数据,有一个数据为缺失值,则 DataFrame.dropna() 方法会将这行数据删除。如果我们要这行数据全部为缺失值时删除,可以使用指定关键字参数 how="all"

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", pd.NA],
    ["涂山苏苏", None],
    ["桔梗", 18]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.dropna(how="all"))

  如果我们要保留至少有 n 个不是缺失值的数据,可以传入关键字参数 thresh=n 来实现。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(df.dropna(thresh=2))

  DataFrame.dropna() 方法默认是删除行,如果我们要删除列,可以传入 axis=1 关键字参数。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(df.dropna(axis=1))

  如果我们只要删除某一列中有缺失值的那行数据,可以传入 subset=["列标签名"] 关键字参数实现。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(df.dropna(subset=["性别"]))

5.1.3、填充缺失值

  我们可以使用 DataFrame.fillna({"列标签名": 填充值}) 的方式使用一个常量值填充缺失值。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(df.fillna({"性别": "保密", "年龄": "未知"}))

5.2、重复数据的处理

  我们可以使用 DataFrame.duplicated() 方法检测是否存在重复数据。DataFrame 的 DataFrame.duplicated() 方法返回一个布尔型 Series,表示各行是不是重复行。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 14],
    ["白钰袖", 16],
    ["桔梗", 18],
    ["木之本樱", 12],
    ["夏娜", 15],
    ["桔梗", 18],
    ["木之本樱", 10],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.duplicated())

  DataFrame.duplicated() 方法默认会判断全部列,我们也可以指定部分列判断是否重复,此时需要传入 subset=["列标签名"] 关键字参数。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 14],
    ["白钰袖", 16],
    ["桔梗", 18],
    ["木之本樱", 12],
    ["夏娜", 15],
    ["桔梗", 18],
    ["木之本樱", 10],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.duplicated(subset=["姓名"]))

  如果我们要删除重复行数据,可以使用 DataFrame.drop_duplicates() 方法。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 14],
    ["白钰袖", 16],
    ["桔梗", 18],
    ["木之本樱", 12],
    ["夏娜", 15],
    ["桔梗", 18],
    ["木之本樱", 10],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.drop_duplicates())

  如果我们需要根据某几列去重,可以传入关键字参数 subset=["列标签名"]

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 14],
    ["白钰袖", 16],
    ["桔梗", 18],
    ["木之本樱", 12],
    ["夏娜", 15],
    ["桔梗", 18],
    ["木之本樱", 10],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.drop_duplicates(subset=["姓名"]))

  当我们使用 DataFrame.drop_duplicates() 方法去除重复数据时,默认保存的是第一次的重复数据,如果我们想要保存最新一条的重复数据,可以传入 kepp="last" 关键字参数。

import pandas as pd

person_info = [
    ["木之本樱", 10],
    ["御坂美琴", 14],
    ["夏娜", 14],
    ["白钰袖", 16],
    ["桔梗", 18],
    ["木之本樱", 12],
    ["夏娜", 15],
    ["桔梗", 18],
    ["木之本樱", 10],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄"])
print(df.drop_duplicates(keep="last"))

六、数据类型转换

  我们可以使用 Series 的 DataFrame.astype("数据类型") 的方法转换某一列的数据类型。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(df.dtypes)

# 转换数据类型
df["年龄"] = df["年龄"].astype("Int16")
print(df.dtypes)

  我们还可以使用 Series 的 DataFrame.map() 方法可以接收一个函数或含有映射关系的字典型对象,来实现值转换。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", pd.NA, "女"],
    ["涂山苏苏", None, "女"],
    ["桔梗", 18, "女"],
    ["利姆鲁", pd.NA, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
df["性别"] = df["性别"].map({"女": 0, "男": 1})
print(df)

七、数据变形

  我们可以使用 pandas.melt(dataFrame, id_vars=["不转换的列标签名"], var_name="转换后的列标签名", value="转换后列的值的标签名") 方法将一个宽表转换成长表。同样,我们还可以使用 pandas.pivot(dataFrame, index=["不转换的列标签名"], columns="要转换的列标签名", values="转换后为值的列标签名")

import pandas as pd

person_info = [
    ["木之本樱", 10, "女", "97", "75", "98"],
    ["御坂美琴", 14, "女", "100", "100", "100"],
    ["夏娜", pd.NA, "女", "93", "87", "65"],
    ["桔梗", 18, "90", "90", "90"],
    ["利姆鲁", pd.NA, None, "93", "97", "97"]
]

# 宽表转长表
df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别", "国语", "算数", "生活"])
ldf = pd.melt(df, id_vars=["姓名", "年龄", "性别"], var_name="科目", value_name="分数")
ldf = ldf.sort_values(by=["姓名"])
print(ldf)

print()

# 长表转宽表
wdf = ldf.pivot(index=["姓名", "年龄", "性别"], columns="科目", values="分数")
print(wdf)

八、数据分箱

  我们可以使用 pandas.cut() 将连续数据划分为固定的区间(或类别),该函数返回对应的区间标签。如果我们要将数据分成指定数量的等宽区间,可以传入 bins=n 关键字参数。

import pandas as pd

person_info = [
    ["Kinomoto Misaka ", 10, "女"],
    ["Misaka Mikoto", 14, "女"],
    ["Shana", 15, "女"],
    ["Kikyō", 18],
    ["Rimuru Tempest", 0, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(pd.cut(df["年龄"], bins=3).value_counts())

  如果我们想要自定义的区间边界,可以给 bins 关键字传入一个列表。它默认是 左闭右开 的,如果我们自定义区间为 左开右闭,可以在传入一个 right=False 关键字参数。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", 15, "女"],
    ["桔梗", 18],
    ["利姆鲁", 0, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
print(pd.cut(df["年龄"], bins=[0, 6 , 12, 15, 18, 22], right=False).value_counts())

  我们还可以传入 labels=["标签名"] 关键字参数为指定每个区间的标签,如果我们传入为 False 则返回区间编号而不是标签。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女"],
    ["御坂美琴", 14, "女"],
    ["夏娜", 15, "女"],
    ["桔梗", 18],
    ["利姆鲁", 0, None]
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别"])
df["学校"] = pd.cut(df["年龄"], bins=[0, 6 , 12, 15, 18, 22], right=False, labels=["幼儿园", "小学", "初中", "高中", "大学"])
print(df)

九、数据分组与聚合

  在 Pandas中的数据会根据你所提供的单键或多键拆分为多组。拆分操作是在对象的特定轴上执行的。我们所说的 “分组 (group by)” 是指一个或多个以下步骤的过程:

  1. 根据某些标准将数据 拆分 成组。
  2. 独立地对每个组 应用 一个函数。
  3. 将结果 合并 成一个数据结构。
DataFrame.groupby(["分组的字段"])["聚合的字段"].聚合函数()
import pandas as pd

person_info = [
    ["木之本樱", 10, "女", "魔法少女"],
    ["高町奈叶", 9, "女", "魔法少女"],
    ["菲特·泰斯特罗莎·哈拉温", 9, "女", "魔法少女"],
    ["御坂美琴", 14, "女", "超能力使"],
    ["食蜂操祈", 14, "女", "超能力使"],
    ["夏娜", 15, "女", "战士"],
    ["桔梗", 18, "女", "巫女"],
    ["日暮戈薇", 15, "女", "巫女"],
]

df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别", "职业"])
print(df.groupby("职业").groups)                                                # 查看分组
print(df.groupby("职业").get_group("魔法少女"))                                  # 获取指定分组
print(df.groupby("职业")["年龄"].mean().round(2).reset_index())                  # 计算分组平均值

十、数据联合

  在 Pandas 中,我们可以使用 pandas.merge() 函数根据单个或多个键将不同 DataFrame 中的行连接起来。

dataFrame = pandas.merge(left DataFrame, right DataFrame, on=["要联合的列标签名"])

当我们用 on 参数指定要联合的列标签名必须在左右 DataFrame 对象中都找到。

import pandas as pd

person_info = [
    ["木之本樱", 10, "女", 0],
    ["高町奈叶", 9, "女", 0],
    ["菲特·泰斯特罗莎·哈拉温", 9, "女", 0],
    ["御坂美琴", 14, "女", 1],
    ["食蜂操祈", 14, "女", 1],
    ["夏娜", 15, "女", 2],
    ["桔梗", 18, "女", 3],
    ["日暮戈薇", 15, "女", 3],
]

profession_info = [
    [0, "魔法少女"],
    [1, "超能力使"],
    [2, "战士"],
    [3, "巫女"],
]

person_df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别", "职业ID"])
profession_df = pd.DataFrame(profession_info, columns=["职业ID", "职业"])
df = pd.merge(person_df, profession_df, on="职业ID")
print(df)

  如果两个对象的列名不同,也可以分别通过 left_onright_on 参数进行指定:

import pandas as pd

person_info = [
    ["木之本樱", 10, "女", 0],
    ["高町奈叶", 9, "女", 0],
    ["菲特·泰斯特罗莎·哈拉温", 9, "女", 0],
    ["御坂美琴", 14, "女", 1],
    ["食蜂操祈", 14, "女", 1],
    ["夏娜", 15, "女", 2],
    ["桔梗", 18, "女", 3],
    ["日暮戈薇", 15, "女", 3],
]

profession_info = [
    [0, "魔法少女"],
    [1, "超能力使"],
    [2, "战士"],
    [3, "巫女"],
]

person_df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别", "职业ID 1"])
profession_df = pd.DataFrame(profession_info, columns=["职业ID 2", "职业"])
df = pd.merge(person_df, profession_df, left_on="职业ID 1", right_on="职业ID 2")
print(df)

  默认情况下,pandas.merge() 做的是 “内连接”,结果中的键是交集,或者是两张表的公共集合。其他方式还有 "left"(左连接)"right"(右连接)以及 "outer"(外连接)。外连接取的是键的并集,融合了左连接和右连接的效果。在外连接中,如果左侧或右侧 DataFrame 对象的行与其它 DataFrame 中的键不匹配,则这些不匹配的行将以 NA 值的方式出现在其它 DataFrame 的列中。

  我们可以使用 how 参数指定要连接的方式。

选项 说明
how="inner" 只使用两张表都有的键
how="left" 使用左表中所有的键
how="right" 使用右表中所有的键
how="outer" 使用两张表所有的键
import pandas as pd

person_info = [
    ["木之本樱", 10, "女", 0],
    ["高町奈叶", 9, "女", 0],
    ["菲特·泰斯特罗莎·哈拉温", 9, "女", 0],
    ["御坂美琴", 14, "女", 1],
    ["食蜂操祈", 14, "女", 1],
    ["夏娜", 15, "女", 2],
    ["桔梗", 18, "女", 3],
    ["日暮戈薇", 15, "女", 3],
    ["大道寺知世", 10, "女", pd.NA]
]

profession_info = [
    [0, "魔法少女"],
    [1, "超能力使"],
    [2, "战士"],
    [3, "巫女"],
    [4, "法师"]
]

person_df = pd.DataFrame(person_info, columns=["姓名", "年龄", "性别", "职业ID"])
profession_df= pd.DataFrame(profession_info, columns=["职业ID", "职业"])
df = pd.merge(person_df, profession_df, on="职业ID", how="outer")
print(df)
posted @ 2025-11-15 22:11  星光映梦  阅读(18)  评论(0)    收藏  举报