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 下载源列表:
- 阿里云 https://mirrors.aliyun.com/pypi/simple
- 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
- 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
- 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple
二、 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)” 是指一个或多个以下步骤的过程:
- 根据某些标准将数据 拆分 成组。
- 独立地对每个组 应用 一个函数。
- 将结果 合并 成一个数据结构。
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_on 和 right_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)

浙公网安备 33010602011771号