4.1 项目背景
city_temperature.csv记录了原始的气温数据,具有覆盖地理范围广、时间跨度大、数据项目多等特点,这些特点使得其中隐藏的气温趋势不易被人察觉。例如,相对于“查询巴黎市2020年1月1日的气温”这样的细节数据查询,还有一些能更好展示气温变化趋势的查询,如查询“巴黎市2020年1月的最高气温和最低气温”“历年来巴黎市冬天的平均气湿变化趋势如何”“伦敦市的夏天高温天数有没有变化”等。上述查询以简洁易懂的方式帮助公众快速了解气温变化趋势,激发其对气温变化的关注。类似的查询举例如下。
查询广州市2019年1月1日的气温(基于时间的查询)。
查询广州市2019年夏天的气温(基于人们生活习惯的查询)。
查询广州市2019年的气温最高值和最低值(基于统计的查询)。
查询广州市2019年7~9月气温超过35℃的天数(基于统计的查询)。
查询不同年份广州市夏天气温超过35℃的天数(基于分组的统计查询)。
查询广州市7月平均气温最高的年份(基于排序的查询)。
4.2 技能图谱

数据加载
# 导入NumPy库,该库用于支持大型的、 多维数组和矩阵,以及对这些数组进行各种数学运算
import numpy as np
# 导入Pandas库,这是一个用于数据操作和分析的库,提供了数据结构和操作工具
import pandas as pd
# 导入Matplotlib库中的pyplot模块,用于绘制各种静态、动态和交互式的图形
import matplotlib.pyplot as plt
# 使用 pd.read_csv 函数读取CSV文件,并将文件加载到一个DataFrame中。【数据存放在当前工作目录下】
data = pd.read_csv('./city_temperature.csv', dtype={'State':object})
# 预览data
data【数据清洗】
4.3 列处理
4.3.1 重命名列标签
【例4-1】将“Region”列标签修改为“区域”。
data.rename(columns={'Region': '区域'}, inplace=True)
解释:
rename() 是Pandas库中用于重命名轴标签的函数。
columns={'Region': '区域'} 是一个字典,指示将“Region”这一列的名称改为“区域”。
inplace=True 参数:表示直接在原始DataFrame上进行修改,而不是返回一个新的DataFrame。如果设置为False,则原始DataFrame不会改变,而会返回一个新的DataFrame,其中包含了修改后的列名。
【例4-2】将“Country”和“State”列标签分别修改为“国家”和“州/省份”。
data.rename(columns={'Country': '国家', 'State': '州/省份'}, inplace=True)
【例4-3】同时修改所有列的列标签。
# 将 DataFrame 的列名设置为指定的新名称列表
data.columns = ['城市','区域', '国家', '州', '月', '日', '年', '日内平均气温']4.3.2 删除、合并列
【例4-4】删除“州”列数据。
data.drop (columns='州',inplace=True)
# 解释:如果要删除多列
# 语法:data.drop(columns=['列名1', '列名2'], inplace=True)【例4-5】将“年”、“月”、“日”3列的数据合并到“日期”新列中。
# 在pandas创建新列的方法:data['新列'] = 值
# 将年、月、日三列的数据类型转换为字符串,并用'/'符号连接,形成新的“日期”列
data['日期'] = (
data['年'].astype(str) + '/' +
data['月'].astype(str) + '/' +
data['日'].astype(str)
)
data.head(2)
4.3.2 转换日期数据
【例4-6】查词1995年1月1日的记录。
data.query(' 日期=="1995/1/1" ')
# 等同于
data[data['日期']=='1995/1/1']
data.loc[data['日期']=='1995/1/1']【例4-7】将“日期”列数据转换为 Pandas.DateTime类型。
# 1.查看data的各列类型
data.dtypes
# 2.将“日期”列数据格式【字符型】转换日期格式
data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d', errors='coerce')pd.to_datetime() 是Pandas库中用于将字符串转换为日期时间格式的函数。
format='%Y/%m/%d' 参数指定了输入日期数据的具体格式。这里%Y代表四位年份,%m代表月份,%d代表日期。
当errors='coerce'时,如果遇到任何无法按照指定格式解析的数据,它们会被设置为NaT(Not a Time,即“非时间”),这是Pandas中用于表示缺失日期数据的特殊值。
datetime64[ns] 是 Pandas 中用于表示日期和时间的一种数据类型。其中 [ns] 表示时间的精度是“纳秒”。
/coerce [kəʊˈɜːs] 强制/
【例4-8】查询广州市在2013年7月的数据(基于日期区间的查询)。
data.query(' 城市 == "Guangzhou" and 日期 >= "2013/7/1" and 日期 <= "2013/7/31" ')
【例4-9】查询广州市在2013年7月的数据。
方法一
data[
(data['日期'].dt.year == 2013) &
(data['日期'].dt.month == 7) &
(data['城市'] == 'Guangzhou')
]data['日期'].dt.year == 2013:使用Pandas的.dt访问器,从“日期”列中获取每个日期的年信息。
.dt:
这是Pandas中的日期时间属性访问器,用于访问日期时间类型的数据的各种属性。
通过
.dt,可以访问日期时间的年(year)、月(month)、日(day)、星期几(dayofweek)等属性
方法二:
data.query(' 日期.dt.year == 2013 and 日期.dt.month == 7 and 城市 == "Guangzhou" ')
【例4-10】查询广州市所有星期一的气温数据。
方法一:
data[(data['日期'].dt.dayofweek == 0) & (data['城市'] == 'Guangzhou')]
data['日期'].dt.dayofweek == 1:使用Pandas的.dt访问器,从“日期”列中获取每个日期的星期信息。
.dt:
这是Pandas中的日期时间属性访问器,用于访问日期时间类型的数据的各种属性。
通过
.dt,可以访问日期时间的年(year)、月(month)、日(day)、星期几(dayofweek)等属性。
.dayofweek:
这是
.dt访问器提供的一个属性,返回一周中的第几天。返回的结果是一个整数,表示星期几。
0表示星期一,1表示星期二,依次类推,6表示星期日。
方法二:
data.query(' 日期.dt.dayofweek == 0 and 城市 == "Guangzhou" ')
【例4-11】查询广州市2013年7月1日及其后面15天内【即从 2013-07-01 到 2013-07-16】的数据。
方法一:
# 导入Python标准库中的 datetime 模块及其 timedelta 类
# timedelta 用于表示两个日期之间的时间差。delta /[ˈdeltə]德尔塔/ 差量
import datetime
from datetime import timedelta
# 基准日期:将字符串 '2013-07-01' 转换为 Pandas 的日期时间对象并赋值给 base_date。
base_date = pd.to_datetime('2013-07-01')
# 这行代码用于从DataFrame data 中筛选过滤出满足以下两个条件的行:
# 日期在基准日期 2013-07-01 及其后15天之内。
# 城市为 "Guangzhou"(广州)。
data[((data['日期']-base_date) >= timedelta(days=0)) &
((data['日期']-base_date) <= timedelta(days=15)) &
(data['城市']=='Guangzhou')]方法二:
import datetime
from datetime import timedelta
# 基准日期
base_date = pd.to_datetime('2013-07-01')
end_date = base_date + timedelta(days=15)
# 使用 between 方法筛选数据
data[data['日期'].between(base_date, end_date) & (data['城市'] == 'Guangzhou')]解释:
between 是Pandas中Series对象的方法,用于检查每个元素是否在指定的范围内,包括边界值。
base_date 和 end_date 是两个日期时间对象,表示筛选的起始日期和结束日期。
between(base_date, end_date) 返回一个布尔 Series,其中每个值为 True 表示该行的日期在 base_date 和 end_date 之间(包括 base_date 和 end_date),否则为 False。
方法三:
在 query 方法中,无法直接进行日期运算,如减法。这种情况下,通常需要预先计算并存储结果,然后在查询中使用。
# 基准日期
base_date = pd.to_datetime('2013-07-01')
# 计算日期范围的上限
end_date = base_date + timedelta(days=15)
# 使用 query 方法筛选数据
data.query(' 日期 >= @base_date and 日期 <= @end_date and 城市 == "Guangzhou" ' )这段代码通过 query 方法,根据以下条件筛选DataFrame data 中的行:
日期在
2013-07-01和2013-07-16之间(包括这两天)。城市为 '
Guangzhou'。在Pandas的
query方法中,@符号用于引用方法外部的Python变量。也就是说,当在query字符串中使用变量时,必须在变量名前加上@符号,以告诉Pandas这个变量是来自方法外部的Python环境,而不是DataFrame中的列。
4.4 索引处理
什么是索引
在Pandas中,索引是DataFrame或Series中用来标识数据位置的标签。索引用于快速访问和操作数据。每个DataFrame或Series都有一个默认的整数索引,但可以根据需要设置其他列作为索引。
索引的作用:
唯一标识数据行:每个索引值唯一标识一行数据,便于数据的快速访问
快速访问数据:通过索引可以高效地查找和提取数据。
数据对齐:索引用于在不同数据结构之间对齐数据【自动根据索引匹配元素】,进行数据合并、连接操作。
标签操作:索引提供了一种基于标签的操作方式,类似于数据库中的主键。
索引的类型:
默认索引:DataFrame在创建时,如果没有指定索引,会自动分配一个从0开始的整数索引。
自定义索引:可以将DataFrame的任意列设置为索引。
多重索引:Pandas支持多重索引,可以使用多个列来进行分层管理数据。
4.4.1 设置单级索引
设置单级索引
# 查看数据结构
data.head()
# 将“城市”列设为索引并直接修改原 DataFrame
data.set_index('城市',inplace=True)
data.head()
【例4-12】查询广州市在2013年7月的数据。
# 使用 loc 根据行标签值(索引)(例如 'Guangzhou')来选择行数据
data.loc['Guangzhou']
# 使用loc 选择行标签(索引)为 'Guangzhou' 的行,再对其中的“日期”列进行查询,筛选出月份为 7 的数据
data.loc['Guangzhou'].query(' 日期.dt.month==7 and 日期.dt.year==2013 ')
# 等同于
data.loc['Guangzhou'][(data['日期'].dt.month==7) & (data['日期'].dt.year==2013) ]
4.4.2 设置多级索引
单级索引只支持基于单个索引条件的查询。如果需要支持多个查询条件,则需要设置多级索引,
第一种方法:在现有索引的基础上添加新的索引,如图4-7所示。

第一种方法:
# 将 '日期' 列追加设置为索引
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
# 参数 append=True 表示将 '日期' 列追加为多级索引,而不是替换现有索引
data.set_index('日期', inplace=True, append=True)
# 查看 DataFrame 的前5行
data.head()
第二种方法:先去掉所有索引,然后一次性设詈多级索引,如图45所示。

# 重置索引,将索引列恢复为普通列
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
data.reset_index(inplace=True)
# 将 '城市' 和 '日期' 列设置为多级索引
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
data.set_index(['城市', '日期'], inplace=True)
# 查看 DataFrame 的前5行
data.head()
设置多级索引之后,为了更快地访问和处理数据,运行下面代码,对索引进行排序。
索引排序
# 按照 '城市' 索引级别排序
# 参数 level='城市' 表示根据 '城市' 级别进行排序
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
data.sort_index(level='城市', inplace=True)4.4.3查询索引
单级索引查询
【例4-13】查询Guangzhou的数据。
data.loc['Guangzhou']
【例4-14】查询Paris 的数据。
data.loc['Paris']
【例4-15】查询Shanghai 和 Guangzhou的数据。
# 单级索引,选择多个行标签的数据。
data.loc[['Shanghai','Guangzhou']]【例4-16】查询广州市在2013年7月1日的数据。
# 多级索引,选择特定层级组合的行数据。
# 使用元组表示多级索引,选择索引为 'Guangzhou' 和 '2013/7/1' 的行数据。
data.loc[('Guangzhou','2013/7/1'),]
# 在 data.loc[...] 语法中,最后的逗号用来分隔行索引和列索引。可以省略【例4-17】查询广州市在2013年7月的数据。
data.loc['Guangzhou'][(data.loc['Guangzhou'].index.month == 7) & \
(data.loc['Guangzhou'].index.year == 2013)]data.loc['Guangzhou']:选择 城市 为 Guangzhou 的所有记录。
data.loc['Guangzhou'].index.month == 7:获取这些记录的 日期 索引的月份,并筛选出月份为 7 的记录。
data.loc['Guangzhou'].index.year == 2013:获取这些记录的 日期 索引的年份,并筛选出年份为 2013 的记录。
组合条件 &:同时满足月份为 7 和年份为 2013 的记录。
【例4-18】查询广州市在2013年7月1日的数据
index1 = 'Guangzhou'
index2 = '2013/7/1'
data.loc[(index1, index2), :] #使用元组表示多级索引:('Guangzhou','2013/7/1')【例4-19】查询广州市、上海市在2013年7月的数据
index1 = ['Guangzhou','Shanghai']
index2 = '2013/7'
data.loc[(index1, index2), :]【例4-20】查询广州市在2013年7月1日和2014年7月1日的数据
# 定义第一个索引级别的值 'Guangzhou'(表示城市)
index1 = 'Guangzhou'
# 定义第二个索引级别的值列表,包含两个特定的日期
index2 = ['2013/7/1', '2014/7/1']
# 使用 loc 根据指定的多级索引条件来选择数据
# (index1, index2) 是一个元组,第一个元素是城市,第二个元素是日期列表
# 行索引为 (index1, index2),列索引未指定,默认选择所有列
data.loc[(index1, index2), :]【例4-21】查询广州市在2013年7月和2014年8月的数据
index1 = 'Guangzhou'
index2 = ['2013/7', '2014/8']
data.loc[(index1, index2), :]解释: 在 Pandas 中,当使用日期字符串(如 '2013/7' 或 '2014/8')作为索引进行查询时,Pandas 会自动将这些字符串解释为该月的所有数据。这是因为 Pandas 的 DatetimeIndex 支持“部分字符串匹配”,即可以使用年、月甚至部分的日期字符串来查询指定范围的数据。
【例4-22】查询广州市、上海市在2013年7月和2014年8月的数据
index1 = ['Guangzhou','Shanghai']
index2 = ['2013/7','2014/8']
data.loc[(index1, index2), :]多级索引查询
注意:【例4-23】 ~ 【例4-27】使用的是Pandas 多级索引(MultiIndex)的操作。
经实验,slice切片在Jupyter最新版本的Python内核或Pandas高版本中运行会报错,故不使用此方法.
数据准备
# 导入NumPy库,该库用于支持大型的、 多维数组和矩阵,以及对这些数组进行各种数学运算
import numpy as np
# 导入Pandas库,这是一个用于数据操作和分析的库,提供了数据结构和操作工具
import pandas as pd
# 导入Matplotlib库中的pyplot模块,用于绘制各种静态、动态和交互式的图形
import matplotlib.pyplot as plt
# 使用 pd.read_csv 函数读取CSV文件,并将文件加载到一个DataFrame中。【数据存放在当前路径/data目录下】
data = pd.read_csv('./city_temperature.csv', dtype={'State':object})
data.columns = ['城市','区域', '国家', '州', '月', '日', '年', '日内平均气温']
# 将年、月、日三列的数据类型转换为字符串,并用'/'符号连接,形成新的“日期”列
data['日期'] = data['年'].astype(str) + '/' + data['月'].astype(str) + '/' + data['日'].astype(str)
data.head(2)
data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d', errors='coerce')
# 重置索引,将索引列恢复为普通列
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
data.reset_index(inplace=True)
# 将 '城市' 和 '日期' 列设置为多级索引
# 参数 inplace=True 表示在原 DataFrame 上进行操作,不创建新的 DataFrame
data.set_index(['城市', '日期'], inplace=True)
# 查看 DataFrame 的前5行
data.head()【例4-23】查询广州市在2013年7月1日至2013年7月15日的数据。
# pd.IndexSlice:Pandas 提供的工具,用于在多级索引的 DataFrame 中简化切片操作
# 定义 pd.IndexSlice 的别名 idx,便于后续引用
idx = pd.IndexSlice
# 指定第一个索引级别的值(例如城市)
index1 = 'Guangzhou'
# 创建一个包含特定日期范围(从 2013 年 7 月 1 日至 2013 年 7 月 15 日)的日期索引
index2 = pd.date_range('2013/7/1', '2013/7/15')
# 使用 pd.IndexSlice 创建一个多级索引的切片对象
index = idx[index1, index2]
# 使用 loc 根据多级索引的标签(行索引和列索引)来选择数据
# 行索引用 pd.IndexSlice 构建的切片对象来选择特定的行数据,列索引没有特别指定,默认选择所有列
data.loc[index, ]【例4-24】查询广州市和上海市在2013年7月1日至2013年7月15日的数据。
# 定义 pd.IndexSlice 的别名 idx,用于简化多级索引的切片操作
idx = pd.IndexSlice
# 指定第一个索引级别的值(多个城市:'Guangzhou' 和 'Shanghai')
index1 = ['Guangzhou', 'Shanghai']
# 创建一个包含特定日期范围(从 2013 年 7 月 1 日至 2013 年 7 月 15 日)的日期索引
index2 = pd.date_range('2013/7/1', '2013/7/15')
# 使用 pd.IndexSlice 创建一个多级索引的切片对象,包含两个索引级别的条件
index = idx[index1, index2]
# 使用 loc 根据指定的多级索引切片对象 index 选择数据
# 行索引使用 pd.IndexSlice 构建的切片对象来筛选数据,列索引没有特别指定,默认选择所有列
data.loc[index, ]【例4-25】查询广州市和上海市在2013年7月1日至2013年7月15日的数据,只显示"日内平均气温"列。
# 定义 pd.IndexSlice 的别名 idx,用于简化多级索引的切片操作
idx = pd.IndexSlice
# 指定第一个索引级别的值(多个城市:'Guangzhou' 和 'Shanghai')
index1 = ['Guangzhou', 'Shanghai']
# 创建一个包含特定日期范围(从 2013 年 7 月 1 日至 2013 年 7 月 15 日)的日期索引
index2 = pd.date_range('2013/7/1', '2013/7/15')
# 使用 pd.IndexSlice 创建一个多级索引的切片对象,包含两个索引级别的条件
index = idx[index1, index2]
# 使用 loc 根据指定的多级索引切片对象 index 来选择数据
# 行索引使用 pd.IndexSlice 构建的切片对象 index 来筛选数据
# 列索引指定为 "日内平均气温",选择该列的数据
data.loc[index, "日内平均气温"]【例4-26】查询广州市和上海市的所有的数据。
# 定义 pd.IndexSlice 的别名 idx,用于简化多级索引的切片操作
idx = pd.IndexSlice
# 指定第一个索引级别的值(多个城市:'Guangzhou' 和 'Shanghai')
index1 = ['Guangzhou', 'Shanghai']
# 使用冒号 ':' 作为第二级索引的条件,表示选择所有日期
index = idx[index1, :]
# 使用 loc 根据指定的多级索引切片对象 index 来选择数据
# 行索引使用 pd.IndexSlice 构建的切片对象 index 来筛选数据,列索引没有特别指定,默认选择所有列
data.loc[index, ]【例4-27】查询2020年1月1日和2020年5月1日的所有数据(省略第一级索引,第二级索引 为单值集合)
# 定义 pd.IndexSlice 的别名 idx,用于简化多级索引的切片操作
idx = pd.IndexSlice
# 创建一个包含特定日期的列表,使用 pd.to_datetime 确保日期格式正确
index2 = pd.to_datetime(['2020-01-01', '2020-05-01'])
# 使用 pd.IndexSlice 创建一个多级索引的切片对象
# 第一级索引使用冒号 ':' 表示选择所有城市,第二级索引指定为特定日期列表
index = idx[:, index2]
# 使用 loc 根据多级索引切片对象 index 来选择数据
# 行索引使用 pd.IndexSlice 构建的切片对象 index 来筛选数据,列索引未指定,默认选择所有列
data.loc[index, :]解释:
idx[:, index2]:使用 pd.IndexSlice 创建一个切片对象,选择所有城市(用 : 表示)在 index2 中指定的日期(即 2020-01-01 和 2020-05-01)的数据。
:表示选择所有列。
4.5 统计分析
4.5.1 实现数据排序
为了方便后续实践内容的开展,重新读入city_temperature.csv的数据,并将其整理为下图所示的数据
import numpy as np
import pandas as pd
# 读取CSV文件,指定State列的数据类型为object(即字符串类型)
data = pd.read_csv('./city_temperature.csv',dtype={'State':object})
# 将温度从华氏度转换为摄氏度,转换公式为 (华氏度 - 32) / 1.8
data['AvgTemperature'] =(data['AvgTemperature']-32)/1.8
# 设置 data DataFrame 的列名
data.columns=['城市', '区域', '国家', '州', '月', '日', '年', '日内平均气温']
# 将年、月、日三列的数据类型转换为字符串,并用'/'符号连接,形成新的“日期”列
data['日期'] = data['年'].astype(str) + '/' + data['月'].astype(str) + '/' + data['日'].astype(str)
# 将字符串格式的日期转换为Pandas的DateTime类型,便于进行日期和时间的操作
data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d',errors='coerce')
data.head()
【例 4-28】按“日内平均气温”列排序。【默认升序】
# 使用 sort_values 对 DataFrame 按指定列进行排序
# by=['日内平均气温']:指定按“日内平均气温”列的值进行排序
# inplace=True:直接在原 DataFrame 上进行排序,不创建新的副本
data.sort_values(by=['日内平均气温'], inplace=True)
# 输出排序后的 DataFrame
data
解释
sort_values: Pandas DataFrame的一个方法,用于对数据进行排序。by: 指定排序的列,可以是一个或多个列。inplace: 是否在原DataFrame上进行修改,True表示直接修改原DataFrame。ascending: 指定排序顺序,默认是升序,True表示升序,False表示降序。当有多个列时,可以传递一个布尔值列表以分别指定每列的排序顺序。
这些习题展示了如何使用Pandas中的sort_values方法对DataFrame数据按单列或多列进行升序或降序排序。
【例 4-29】按“日内平均气温”列排序(降序)。
data.sort_values(by=['日内平均气温'], inplace=True, ascending=False)
# inplace=True 意味着会对原 DataFrame 进行排序,而不会返回一个新的 DataFrame。
# ascending [əˈsendɪŋ] 呃森丁 (上升的)
# ascending=False 意味着按降序排序(从大到小)。如果设为 True,则按升序排序(从小到大)。
【例 4-30】按“日期”和“日内平均气温”列排序。
# 使用 sort_values 对 DataFrame 按多个列进行排序
# by=['日期', '日内平均气温']:指定先按“日期”列进行排序,再按“日内平均气温”列进行排序
# inplace=True:直接在原 DataFrame 上进行排序,不创建新的副本
data.sort_values(by=['日期', '日内平均气温'], inplace=True)
【例 4-31】按“日期”和“日内平均气温”列排序(“日期”列按降序排列,“日内平均气温”列按升序排列)。
data.sort_values(by=['日期', '日内平均气温'], inplace=True, ascending=[False, True])

4.5.2 实现简单统计
简单统计用于完成不需要细分组的查询。例如,广州市的最高气温是哪一天、2020年5月13日的最高气温和最低气温分别是多少。这些查询通常是比较常见的统计任务,并不限定于一个计数值。Pandas 总共支持13个统计方法,包括 mean()、max()、min()、count()、sum()、size() 等,其中多数在名称上具有相应的含义。下面是一个具体的例子。
【例 4-33】查询历年来的最高气温。
data['日内平均气温'].max()
# 运行结果:43.333333333333336【例 4-34】 查询广州市在2019年的平均气温。
data.query("城市=='Guangzhou'").query("年==2019")['日内平均气温'].mean()
# 运行结果:22.337899543378995
# 计算广州市2019年“日内平均气温”的平均值,并保留两位小数
mean_temp = data.query("城市=='Guangzhou'").query("年==2019")['日内平均气温'].mean()
mean_temp_rounded = round(mean_temp, 2)
print(mean_temp_rounded)例 4-34 解释

该例子使用了Pandas里的query方法来实现查询。其逻辑步骤如图4-13所示:
首先运行
data.query("城市=='Guangzhou'"),获取城市为“Guangzhou”的所有记录。其结果再运行
.query("年==2019"),再筛选出2019年的记录,即Guangzhou在2019年的记录。计算这些记录中“日内平均气温”的平均值,
最后使用
mean()方法计算平均值。
【例 4-35】 查询 Guangzhou 在 2019 年的最高气温及其日期。
# 1.计算 Guangzhou 在 2019 年的最高气温
guangzhou_max = data.query('城市 == "Guangzhou" and 年 == 2019')['日内平均气温'].max()
# 2.查找 Guangzhou 在 2019 年最高气温对应的日期
data.query('城市 == "Guangzhou" and 年 == 2019 and 日内平均气温 == @guangzhou_max')
4.5.3 实现分组统计
【例 4-36】新建一个 DataFrame,并按照 "A" 列统计各组平均值。
test_df = pd.DataFrame([[1,2],[2,3],[2,0],[3,10],[1,6],[3,3]], columns=['A','B'])
test_df.groupby(by='A').mean()
其分组统计过程如图 4-14 所示,包括拆分、计算、组合 3 个过程。

【例 4-37】查询广州市 2019 年每个月的日内平均气温。
# 查询2019年广州的数据子集
guangzhou_2019 = data.query('城市=="Guangzhou" and 年==2019')
# 对筛选出的广州2019年数据按月份分组,并计算每月的日平均气温
guangzhou_2019_group = guangzhou_2019.groupby(by='月')['日内平均气温'].mean()
或使用如下代码(使用链式运算符则将上面的代码组合为一条代码):
data.query('城市=="Guangzhou" and 年==2019').groupby(by='月')['日内平均气温'].mean()

【例 4-38】按 “区域” 统计日平均气温。
data.groupby('区域')['日内平均气温'].mean()

【例 4-39】按 “区域” 统计日平均气温,只保留与日内气温相关的列。
data[['区域', '日内平均气温']].groupby('区域').mean()

【例 4-40】按 “区域” 统计气温平均值,
下面的代码演示了当统计字段与分组字段无关时的操作:
data.groupby('区域', as_index=False).agg({'日内平均气温':'mean'})
解释:
在使用 Pandas 的
groupby()方法进行分组后,默认情况下,分组字段会成为结果数据框的索引。这是因为 Pandas 会将分组键作为索引来返回聚合后的结果,以便于清晰表示每个分组的聚合数据。data.groupby('区域', as_index=False): 这部分代码将数据集按照“区域”列进行分组。参数as_index=False表示在结果DataFrame中,分组列“区域”将作为普通列显示,而不是作为索引。.agg({'日内平均气温':'mean'}): 这部分代码使用agg函数(聚合函数)来指定对每个分组进行何种计算。这里,它指定对“日内平均气温”列计算每个区域的平均值(mean)。结果是每个区域的平均日内平均气温。
总结起来,整行代码的功能是:计算数据集中每个区域的平均日内平均气温,并返回一个包含每个区域以及其对应的平均日内平均气温的新DataFrame,其中“区域”列不是索引,而是一个普通的列。

agg() 基本用法
agg() 是 Pandas 中的一个方法,用于对 groupby() 对象进行自定义聚合操作。它允许对每个分组应用多个不同的聚合函数,甚至是用户自定义的函数。通过 agg(),可以对不同的列应用不同的聚合函数,从而实现更灵活的分析。
sum():计算每组的总和。
mean():计算每组的平均值。
median():计算每组的中位数。
min():计算每组的最小值。
max():计算每组的最大值。
count():计算每组的非缺失值数量。
size():计算每组的总大小(包括缺失值)。
agg() 可以接收多种形式的输入来指定聚合操作:
单个聚合函数:对所有列应用相同的聚合函数。
多个聚合函数列表:对指定的列应用多个聚合函数。
字典形式:指定不同的列使用不同的聚合函数。
示例
1. 单个聚合函数
import pandas as pd
# 创建示例数据框
data = pd.DataFrame({
'城市': ['A', 'B', 'A', 'B', 'C'],
'人口': [1000, 850, 1000, 1300, 950],
'收入': [50000, 60000, 50000, 65000, 70000]
})
# 按城市分组,计算人口和收入的平均值
result = data.groupby('城市').agg('mean')
print(result)
# 输出
人口 收入
城市
A 1000.0 50000.0
B 1075.0 62500.0
C 950.0 70000.02. 多个聚合函数列表
# 对每个分组应用多个聚合函数
result = data.groupby('城市').agg(['mean', 'sum'])
print(result)输出
人口 收入
mean sum mean sum
城市
A 1000 2000 50000 100000
B 1075 2150 62500 125000
C 950 950 70000 700003. 使用字典指定列的聚合函数
# 使用字典为不同列指定不同的聚合函数
result = data.groupby('城市').agg({'人口': 'sum', '收入': 'mean'})
print(result)输出
人口 收入
城市
A 2000 50000
B 2150 62500
C 950 700004. 自定义聚合函数
你可以在 agg() 中使用自定义的聚合函数,例如,计算每个分组中最大值和最小值的差异:
# 自定义聚合函数:最大值减去最小值
def range_diff(x):
return x.max() - x.min()
# 对每个分组使用自定义函数
result = data.groupby('城市').agg({'人口': range_diff, '收入': 'mean'})
print(result)输出
人口 收入
城市
A 0 50000
B 450 62500
C 0 70000使用 agg() 的关键点
灵活性:能够对不同的列应用不同的聚合函数,也可以在同一列上应用多个聚合函数。
自定义聚合:允许使用用户自定义的函数来计算聚合结果,增强了数据分析的灵活性和功能性。
返回结果:
agg()的结果是一个数据框,包含了每个分组的聚合计算结果。
通过 agg(),你可以在 Pandas 中实现复杂的分组统计分析,从而满足各种数据处理需求。
【例 4-41】按 “区域” 和 “年” 统计日内平均气温平均值。
data.groupby(by=['区域', '年']).agg({'日内平均气温':'mean'})

【例4-42】按“年”统计广州市1月的日均气温的最高值、最低值、平均值。
data.query('城市=="Guangzhou" and 月==1').groupby(by=['年']).agg({'日内平均气温':['max','min','mean']})

【例4-43】按年份统计广州市日均气温高于30℃的天数。
data.query('城市=="Guangzhou" and 日内平均气温>30').groupby(by=['年']).agg({'日内平均气温':'count'})

【例4-44】按国家统计平均气温,只显示平均气温高于25℃的国家。
# 自定义函数
def my_filter(x):
return x['日内平均气温'].mean()>25
data.groupby('国家').filter(my_filter).groupby('国家').agg({'日内平均气温':['mean']})
分步解释
第一步:定义过滤函数
def my_filter(x):
return x['日内平均气温'].mean() > 25定义函数:我们定义了一个名为
my_filter的函数。函数my_filter是专门设计来接收一个分组的数据框(DataFrame)的参数
x:这个函数接受一个参数x,这个x是一个 DataFrame 分组。返回值:函数返回一个布尔值(
True或False)。具体来说,它计算x这个 DataFrame 中日内平均气温列的平均值,如果平均值大于 25,就返回True,否则返回False。
第二步:按国家分组并过滤
data.groupby('国家').filter(my_filter)
分组:
data.groupby('国家')将数据按照国家列进行分组,每个分组包含该国家的所有数据。过滤:在使用
groupby方法分组后,每个组都会被传递给filter方法,作为一个独立的数据框来处理。.filter(my_filter)对每个分组应用我们定义的my_filter函数。只有那些日内平均气温平均值大于 25 的国家的分组会被保留,其他分组会被过滤掉。在
groupby().filter()方法中,my_filter不需要手动传入参数。Pandas 会自动将分组的数据传递给my_filter,作为x参数。
第三步:对过滤后的数据再次按国家分组并聚合
.groupby('国家').agg({'日内平均气温': ['mean']})
再次分组:对过滤后的数据再次按
国家列进行分组。聚合计算:使用
agg方法计算每个国家的日内平均气温列的平均值。
详细流程
分组:将数据按
国家列分成多个小组,每组代表一个国家。过滤:对于每个国家,检查其
日内平均气温的平均值是否大于 25。只有满足条件的国家会被保留下来。聚合:对保留下来的每个国家,计算其
日内平均气温的平均值。
示例
假设我们有如下数据:
| 国家 | 日内平均气温 |
|---|---|
| 中国 | 26 |
| 美国 | 24 |
| 中国 | 27 |
| 美国 | 26 |
| 法国 | 28 |
| 法国 | 30 |
分组并过滤后:
中国:26, 27(平均值 26.5,大于 25,保留)
美国:24, 26(平均值 25,不大于 25,过滤掉)
法国:28, 30(平均值 29,大于 25,保留)
过滤后的数据:
| 国家 | 日内平均气温 |
|---|---|
| 中国 | 26 |
| 中国 | 27 |
| 法国 | 28 |
| 法国 | 30 |
再次分组并计算平均值后:
| 国家 | 日内平均气温 |
|---|---|
| 中国 | 26.5 |
| 法国 | 29 |
【例4-45】统计2019年广州市月均气温高于20℃的月份。
def my_filter2(x):
return x['日内平均气温'].mean() > 20
grouped_data = data.query('年==2019 and 城市=="Guangzhou"').groupby('月')
grouped_data.filter(my_filter2).groupby('月').agg({'日内平均气温': 'mean'})
解析:
定义过滤函数 (
my_filter2):def my_filter2(x):
return x['日内平均气温'].mean() > 20这个函数
my_filter2接受一个 DataFramex作为参数,返回一个布尔值。它会计算输入 DataFrame 中日内平均气温列的平均值,并检查该平均值是否大于 20。如果大于 20,则返回True,否则返回False。筛选数据并按月分组 (
groupby):grouped_data = data.query('年==2019 and 城市=="Guangzhou"').groupby('月')data.query('年==2019 and 城市=="Guangzhou"')筛选出2019年广州市的数据。.groupby('月')将筛选出的数据按照月份进行分组。过滤并计算平均值:
grouped_data.filter(my_filter2).groupby('月').agg({'日内平均气温': 'mean'})grouped_data.filter(my_filter2)对每个分组应用my_filter2函数,保留那些日内平均气温平均值大于 20 的分组。.groupby('月').agg({'日内平均气温': 'mean'})对过滤后的数据再次按照月份分组,并计算每个月的日内平均气温平均值。
详细流程
筛选数据:首先从
data中筛选出2019年广州市的数据。按月分组:将筛选出的数据按照月份分组,每个分组包含该月的所有数据。
过滤:对于每个月的数据,检查其
日内平均气温的平均值是否大于 20。只有满足条件的月份会被保留下来。计算平均值:对保留下来的每个月的数据计算其
日内平均气温的平均值。
示例
假设我们有如下数据:
| 年 | 城市 | 月 | 日内平均气温 |
|---|---|---|---|
| 2019 | Guangzhou | 1 | 18 |
| 2019 | Guangzhou | 1 | 22 |
| 2019 | Guangzhou | 2 | 19 |
| 2019 | Guangzhou | 2 | 21 |
| 2019 | Guangzhou | 3 | 23 |
| 2019 | Guangzhou | 3 | 24 |
筛选和分组后:
1月:18, 22(平均值 20,大于 20,保留)
2月:19, 21(平均值 20,不大于 20,过滤掉)
3月:23, 24(平均值 23.5,大于 20,保留)
过滤后的数据:
| 年 | 城市 | 月 | 日内平均气温 |
|---|---|---|---|
| 2019 | Guangzhou | 1 | 18 |
| 2019 | Guangzhou | 1 | 22 |
| 2019 | Guangzhou | 3 | 23 |
| 2019 | Guangzhou | 3 | 24 |
再次分组并计算平均值后:
| 月 | 日内平均气温 |
|---|---|
| 1 | 20 |
| 3 | 23.5 |
这样我们就统计出了2019年广州市月均气温高于20℃的月份,并计算出了这些月份的平均气温。
实验
数据准备
1.导入数据
【注意:数据在当前目录/date】
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 读取CSV文件,指定State列的数据类型为object(即字符串类型)
data = pd.read_csv('./city_temperature.csv',dtype={'State':object})
data.head()运行结果:
City Region Country State Month Day Year AvgTemperature
0 Algiers Africa Algeria NaN 1 1 1995 64.2
1 Algiers Africa Algeria NaN 1 2 1995 49.4
2 Algiers Africa Algeria NaN 1 3 1995 48.8
3 Algiers Africa Algeria NaN 1 4 1995 46.4
4 Algiers Africa Algeria NaN 1 5 1995 47.92.温度转换
# 将温度从华氏度转换为摄氏度,转换公式为 (华氏度 - 32) / 1.8
data['AvgTemperature'] =(data['AvgTemperature']-32)/1.8运行结果:
City Region Country State Month Day Year AvgTemperature
0 Algiers Africa Algeria NaN 1 1 1995 17.888889
1 Algiers Africa Algeria NaN 1 2 1995 9.666667
2 Algiers Africa Algeria NaN 1 3 1995 9.333333
3 Algiers Africa Algeria NaN 1 4 1995 8.000000
4 Algiers Africa Algeria NaN 1 5 1995 8.8333333.设置 DataFrame 的列名
# 设置 data DataFrame 的列名
data.columns=['城市', '区域', '国家', '州', '月', '日', '年', '日内平均气温']
data.head()运行结果
城市 区域 国家 州 月 日 年 日内平均气温
0 Algiers Africa Algeria NaN 1 1 1995 17.888889
1 Algiers Africa Algeria NaN 1 2 1995 9.666667
2 Algiers Africa Algeria NaN 1 3 1995 9.333333
3 Algiers Africa Algeria NaN 1 4 1995 8.000000
4 Algiers Africa Algeria NaN 1 5 1995 8.8333334.创建新的“日期”列
# 1.将年、月、日三列的数据类型转换为字符串,并用'/'符号连接,形成新的“日期”列
data['日期'] = data['年'].astype(str) + '/' + data['月'].astype(str) + '/' + data['日'].astype(str)
data.head(2)运行结果
城市 区域 国家 州 月 日 年 日内平均气温 日期
0 Algiers Africa Algeria NaN 1 1 1995 17.888889 1995/1/1
1 Algiers Africa Algeria NaN 1 2 1995 9.666667 1995/1/2# 2.将字符串格式的日期转换为Pandas的DateTime类型,便于进行日期和时间的操作
## format='%Y/%m/%d' 参数告诉函数,输入的日期字符串是以 年/月/日 的形式组织的。
## errors='coerce' 参数的作用是,如果遇到无法转换为日期格式的字符串,不会抛出错误,而是将这些无效的日期转换为 NaT(Not a Time,Pandas中的缺失日期数据类型)。
data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d',errors='coerce')
data.head(2)运行结果
城市 区域 国家 州 月 日 年 日内平均气温 日期
0 Algiers Africa Algeria NaN 1 1 1995 17.888889 1995-01-01
1 Algiers Africa Algeria NaN 1 2 1995 9.666667 1995-01-02实验内容一:
【练习4-1】 创建一个“年”列的备份列,列名为“年_备份”。
data['年_备份'] = data['年']
data.head()
运行结果:
城市 区域 国家 州 月 日 年 日内平均气温 日期 年_备份
0 Algiers Africa Algeria NaN 1 1 1995 17.888889 1995-01-01 1995
1 Algiers Africa Algeria NaN 1 2 1995 9.666667 1995-01-02 1995【练习4-2】 删除数据集里面的“月”、“日”列。
data.drop(['月','日'], axis=1,inplace=True)
# axis=0:表示沿着行方向【从上到下】操作,即删除行。
# axis=1:表示沿着列方向【从左到右】操作,即删除列。data.head(2)
运行结果:
城市 区域 国家 州 年 日内平均气温 日期 年_备份
0 Algiers Africa Algeria NaN 1995 17.888889 1995-01-01 1995
1 Algiers Africa Algeria NaN 1995 9.666667 1995-01-02 1995【练习4-3】 创建一个新列“星期几”,里面存储对应日期的星期信息。
data['星期几'] = data['日期'].dt.dayofweek
# .dt:这是 Pandas 提供的一个用于访问日期时间属性的接口。它允许你在日期时间列上进行各种日期相关的操作。
# .dayofweek:这是一个日期时间属性,它返回一个整数,表示日期是星期几:0 表示星期一data.head(2)
运行结果:
城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
0 Algiers Africa Algeria NaN 1995 17.888889 1995-01-01 1995 6.0
1 Algiers Africa Algeria NaN 1995 9.666667 1995-01-02 1995 0.0【练习4-5】 从 data DataFrame 中移除所有 '年_备份' 列值为 201 的行(注意:删除行,非删除列)。
# 查询data中'年_备份'列值为201的所有行
filtered_rows = data[data['年_备份'] == 201]
filtered_rows运行结果
城市 地区 国家 州 年 日内平均气温 日期 年_备份 星期几
58178 Addis Ababa Africa Ethiopia NaN 201 -72.777778 NaT 201 NaN
58179 Addis Ababa Africa Ethiopia NaN 201 -72.777778 NaT 201 NaN
58180 Addis Ababa Africa Ethiopia NaN 201 -72.777778 NaT 201 NaN
58181 Addis Ababa Africa Ethiopia NaN 201 -72.777778 NaT 201 NaN
58182 Addis Ababa Africa Ethiopia NaN 201 -72.777778 NaT 201 NaN
... ... ... ... ... ... ... ... ... ...
1212427 Guadalajara North America Mexico NaN 201 -72.777778 NaT 201 NaN
1212428 Guadalajara North America Mexico NaN 201 -72.777778 NaT 201 NaN
1212429 Guadalajara North America Mexico NaN 201 -72.777778 NaT 201 NaN
1212430 Guadalajara North America Mexico NaN 201 -72.777778 NaT 201 NaN
1212431 Guadalajara North America Mexico NaN 201 -72.777778 NaT 201 NaN
351 rows × 9 columns# 删除data中'年_备份'列值为201的所有行
data.drop(data[data['年_备份']==201].index,axis=0,inplace=True)
'''
解释:
data[data['年_备份'] == 201]: 筛选出 '年_备份' 列中值为 201 的行。
.index: 获取这些行的索引。
data.drop(...): 删除这些索引对应的行。
axis=0: 指定操作是删除行(axis=1 时表示删除列)。
inplace=True: 指定在原地修改原DataFrame,不创建新的DataFrame副本。
'''
data运行结果:
区域 国家 州 城市 年 日内平均气温 日期 年_备份 星期几
0 Algiers Africa Algeria NaN 1995 17.888889 1995-01-01 1995 6.0
1 Algiers Africa Algeria NaN 1995 9.666667 1995-01-02 1995 0.0
2 Algiers Africa Algeria NaN 1995 9.333333 1995-01-03 1995 1.0
3 Algiers Africa Algeria NaN 1995 8.000000 1995-01-04 1995 2.0
4 Algiers Africa Algeria NaN 1995 8.833333 1995-01-05 1995 3.0
... ... ... ... ... ... ... ... ... ...
2906322 San Juan Puerto Rico North America US Additional Territories 2013 28.000000 2013-07-27 2013 5.0
2906323 San Juan Puerto Rico North America US Additional Territories 2013 27.555556 2013-07-28 2013 6.0
2906324 San Juan Puerto Rico North America US Additional Territories 2013 29.000000 2013-07-29 2013 0.0
2906325 San Juan Puerto Rico North America US Additional Territories 2013 28.777778 2013-07-30 2013 1.0
2906326 San Juan Puerto Rico North America US Additional Territories 2013 28.666667 2013-07-31 2013 2.0
2905976 rows × 9 columns【练习4-6】 查询New York City在2000年1月数据。
查询"城市" 列所有唯一值
print(data['城市'].unique())
运行结果
['Algiers' 'Bujumbura' 'Cotonou' 'Bangui' 'Brazzaville' 'Cairo'
'Addis Ababa' 'Libreville' 'Banjul' 'Conakry' 'Bissau' 'Abidjan'
'Nairobi' 'Rabat' 'Antananarivo' 'Nouakchott' 'Lilongwe' 'Maputo'
'Windhoek' 'Niamey' 'Lagos' 'Dakar' 'Freetown' 'Capetown' 'Lome' 'Tunis'
'Dar Es Salaam' 'Kampala' 'Lusaka' 'Dhaka' 'Beijing' 'Chengdu'
'Guangzhou' 'Shanghai' 'Shenyang' 'Hong Kong' 'Bombay (Mumbai)'
'Calcutta' 'Chennai (Madras)' 'Delhi' 'Jakarta' 'Osaka' 'Sapporo' 'Tokyo'.................查询New York 在2000年1月数据
# 方法一
data[ (data['城市'] == 'New York City') & (data['年']==2000) & (data['日期'].dt.month==1)]
# 方法二
data.query("城市 == 'New York City' and 年 == 2000 and 日期.dt.month == 1") 城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2293389 New York City North America US New York 2000 4.277778 2000-01-01 2000 5.0
2293390 New York City North America US New York 2000 8.833333 2000-01-02 2000 6.0
2293391 New York City North America US New York 2000 14.333333 2000-01-03 2000 0.0
2293392 New York City North America US New York 2000 11.333333 2000-01-04 2000 1.0
2293393 New York City North America US New York 2000 6.444444 2000-01-05 2000 2.0
2293394 New York City North America US New York 2000 1.055556 2000-01-06 2000 3.0
2293395 New York City North America US New York 2000 5.777778 2000-01-07 2000 4.0
2293396 New York City North America US New York 2000 2.055556 2000-01-08 2000 5.0
2293397 New York City North America US New York 2000 6.000000 2000-01-09 2000 6.0
2293398 New York City North America US New York 2000 8.500000 2000-01-10 2000 0.0
2293399 New York City North America US New York 2000 9.888889 2000-01-11 2000 1.0
2293400 New York City North America US New York 2000 6.388889 2000-01-12 2000 2.0
2293401 New York City North America US New York 2000 2.444444 2000-01-13 2000 3.0
2293402 New York City North America US New York 2000 -6.666667 2000-01-14 2000 4.0
2293403 New York City North America US New York 2000 -6.055556 2000-01-15 2000 5.0
2293404 New York City North America US New York 2000 2.388889 2000-01-16 2000 6.0
2293405 New York City North America US New York 2000 -7.444444 2000-01-17 2000 0.0
2293406 New York City North America US New York 2000 -11.888889 2000-01-18 2000 1.0
2293407 New York City North America US New York 2000 -7.111111 2000-01-19 2000 2.0
2293408 New York City North America US New York 2000 -2.944444 2000-01-20 2000 3.0
2293409 New York City North America US New York 2000 -6.666667 2000-01-21 2000 4.0
2293410 New York City North America US New York 2000 -10.111111 2000-01-22 2000 5.0
2293411 New York City North America US New York 2000 -5.611111 2000-01-23 2000 6.0
2293412 New York City North America US New York 2000 -1.055556 2000-01-24 2000 0.0
2293413 New York City North America US New York 2000 -1.222222 2000-01-25 2000 1.0
2293414 New York City North America US New York 2000 -2.388889 2000-01-26 2000 2.0
2293415 New York City North America US New York 2000 -6.777778 2000-01-27 2000 3.0
2293416 New York City North America US New York 2000 -8.944444 2000-01-28 2000 4.0
2293417 New York City North America US New York 2000 -4.444444 2000-01-29 2000 5.0
2293418 New York City North America US New York 2000 -1.777778 2000-01-30 2000 6.0
2293419 New York City North America US New York 2000 1.055556 2000-01-31 2000 0.0【练习4-7】 查询New York City在2000年1月到3月的数据。
# 方法一
data[
(data['城市'] == 'New York City') & # 筛选城市为纽约
(data['年'] == 2000) & # 筛选年份为2000
(data['日期'].dt.month >= 1) & # 筛选月份开始于1月
(data['日期'].dt.month <= 3) # 筛选月份结束于3月
]
# 方法二
data.query(
"城市 == 'New York City' and 年 == 2000 and 日期.dt.month >= 1 and 日期.dt.month <= 3"
) 城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2293389 New York City North America US New York 2000 4.277778 2000-01-01 2000 5.0
2293390 New York City North America US New York 2000 8.833333 2000-01-02 2000 6.0
2293391 New York City North America US New York 2000 14.333333 2000-01-03 2000 0.0
2293392 New York City North America US New York 2000 11.333333 2000-01-04 2000 1.0
2293393 New York City North America US New York 2000 6.444444 2000-01-05 2000 2.0
... ... ... ... ... ... ... ... ... ...
2293475 New York City North America US New York 2000 11.111111 2000-03-27 2000 0.0
2293476 New York City North America US New York 2000 12.277778 2000-03-28 2000 1.0
2293477 New York City North America US New York 2000 10.333333 2000-03-29 2000 2.0
2293478 New York City North America US New York 2000 9.777778 2000-03-30 2000 3.0
2293479 New York City North America US New York 2000 8.833333 2000-03-31 2000 4.0
91 rows × 9 columns【练习4-8】 查询New York City在2000年8月最后一天的数据(要求计算8月最后一天的日期)。
import datetime
# 从datetime模块中导入timedelta类,用于表示两个时间点之间的差异。
from datetime import timedelta
# 使用Pandas筛选特定条件的数据
data[
(data['城市'] == 'New York City') & # 筛选城市为纽约市
(data['日期'] == pd.to_datetime('2000/9/1') - timedelta(days=1)) # 筛选日期为2000年8月31日
]
'''
解释
data['城市'] == 'New York City':从DataFrame中筛选出城市列('城市')等于"New York City"的行。
pd.to_datetime('2000/9/1'):将字符串"2000/9/1"转换为Pandas datetime对象,这是一个常见的日期转换方法,用于确保日期格式正确。
timedelta(days=1):创建一个表示一天时间差的timedelta对象。
pd.to_datetime('2000/9/1') - timedelta(days=1):计算2000年9月1日前一天的日期,即2000年8月31日。
'''import datetime
from datetime import timedelta
# 计算目标日期
target_date = pd.to_datetime('2000/9/1') - timedelta(days=1)
# 使用 query 方法进行过滤
data.query(
"城市 == 'New York City' and 日期 == @target_date"
)
【练习4-9】 查询New York City在2000年第47周的数据。
# 方法一
data[
(data['城市'] == 'New York City') &
(data['年'] == 2000) &
(data['日期'].dt.isocalendar().week == 47)
]
# .isocalendar() 方法返回一个 DataFrame,其中包含 ISO 年、ISO 周、ISO 周几等信息,
# .week 则表示提取 ISO 周数。# 方法二
data.query(
"城市 == 'New York City' and 年 == 2000 and 日期.dt.isocalendar().week == 47"
) 城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2293713 New York City North America US New York 2000 3.944444 2000-11-20 2000 0.0
2293714 New York City North America US New York 2000 2.555556 2000-11-21 2000 1.0
2293715 New York City North America US New York 2000 -0.055556 2000-11-22 2000 2.0
2293716 New York City North America US New York 2000 -0.666667 2000-11-23 2000 3.0
2293717 New York City North America US New York 2000 -0.944444 2000-11-24 2000 4.0
2293718 New York City North America US New York 2000 1.444444 2000-11-25 2000 5.0
2293719 New York City North America US New York 2000 7.611111 2000-11-26 2000 6.0【练习4-10】 查询New York City在2000年7月1号前后15天的数据(总共是31天数据)。
# 方法一
import pandas as pd
from datetime import timedelta
start_date = pd.to_datetime('2000/7/1') - timedelta(days=15)
end_date = pd.to_datetime('2000/7/1') + timedelta(days=15)
filtered_data = data[
(data['城市'] == 'New York City') & # 城市为纽约市
(data['年'] == 2000) & # 年份为2000年
(data['日期'] >= start_date) & # 日期在起始日期之后
(data['日期'] <= end_date) # 日期在结束日期之前
]# 方法二
import pandas as pd
from datetime import timedelta
# 计算起始和结束日期
start_date = pd.to_datetime('2000/7/1') - timedelta(days=15)
end_date = pd.to_datetime('2000/7/1') + timedelta(days=15)
# 使用 query 方法进行过滤
filtered_data = data.query(
"城市 == 'New York City' and 年 == 2000 and 日期 >= @start_date and 日期 <= @end_date"
)运行结果
城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2293556 New York City North America US New York 2000 23.833333 2000-06-16 2000 4.0
2293557 New York City North America US New York 2000 27.944444 2000-06-17 2000 5.0
2293558 New York City North America US New York 2000 21.444444 2000-06-18 2000 6.0
2293559 New York City North America US New York 2000 19.333333 2000-06-19 2000 0.0
2293560 New York City North America US New York 2000 22.555556 2000-06-20 2000 1.0
2293561 New York City North America US New York 2000 23.611111 2000-06-21 2000 2.0
2293562 New York City North America US New York 2000 24.666667 2000-06-22 2000 3.0
2293563 New York City North America US New York 2000 25.277778 2000-06-23 2000 4.0
2293564 New York City North America US New York 2000 24.000000 2000-06-24 2000 5.0
2293565 New York City North America US New York 2000 25.055556 2000-06-25 2000 6.0
2293566 New York City North America US New York 2000 26.833333 2000-06-26 2000 0.0
2293567 New York City North America US New York 2000 27.222222 2000-06-27 2000 1.0
2293568 New York City North America US New York 2000 23.722222 2000-06-28 2000 2.0
2293569 New York City North America US New York 2000 21.388889 2000-06-29 2000 3.0
2293570 New York City North America US New York 2000 21.666667 2000-06-30 2000 4.0
2293571 New York City North America US New York 2000 23.277778 2000-07-01 2000 5.0
2293572 New York City North America US New York 2000 25.000000 2000-07-02 2000 6.0
2293573 New York City North America US New York 2000 25.222222 2000-07-03 2000 0.0
2293574 New York City North America US New York 2000 24.000000 2000-07-04 2000 1.0
2293575 New York City North America US New York 2000 25.888889 2000-07-05 2000 2.0
2293576 New York City North America US New York 2000 22.333333 2000-07-06 2000 3.0
2293577 New York City North America US New York 2000 21.333333 2000-07-07 2000 4.0
2293578 New York City North America US New York 2000 20.611111 2000-07-08 2000 5.0
2293579 New York City North America US New York 2000 23.833333 2000-07-09 2000 6.0
2293580 New York City North America US New York 2000 26.666667 2000-07-10 2000 0.0
2293581 New York City North America US New York 2000 24.666667 2000-07-11 2000 1.0
2293582 New York City North America US New York 2000 23.722222 2000-07-12 2000 2.0
2293583 New York City North America US New York 2000 25.166667 2000-07-13 2000 3.0
2293584 New York City North America US New York 2000 23.277778 2000-07-14 2000 4.0
2293585 New York City North America US New York 2000 21.000000 2000-07-15 2000 5.0
2293586 New York City North America US New York 2000 21.888889 2000-07-16 2000 6.0【练习4-11】 查询New York City在2000年7月1号所处周的整周数据(2000年7月1号是星期六,因此显示2000年6月26日至2000年7月2日之间数据,要求通过计算获取所在周的开始和结束日期)。
import pandas as pd
from datetime import timedelta
# 指定日期
target_date = pd.to_datetime('2000/7/1')
# 计算目标日期所在周的开始和结束日期
current_dayofweek = target_date.dayofweek # '2000/7/1'是星期几,结果是5,星期六
week_begin = target_date - timedelta(days=current_dayofweek) # '2000/7/1'所在周的周一的日期
week_end = target_date + timedelta(days=6-current_dayofweek) # '2000/7/1'所在周的周日的日期
# 使用布尔索引筛选数据
data[
(data['城市'] == 'New York City') & # 城市为纽约市
(data['年'] == 2000) & # 年份为2000年
(data['日期'] >= week_begin) & # 日期不早于该周开始
(data['日期'] <= week_end) # 日期不晚于该周结束
]解释
计算当前星期几: 使用
target_date.dayofweek获取目标日期(2000 年 7 月 1 日)是星期几(0 表示周一,6 表示周日)。这里结果为 5,表示星期六。计算周开始和结束日期:
week_begin是从目标日期减去当前星期几的天数,得到该周的周一。week_end是从目标日期加上距离周日的天数(6-current_dayofweek),得到该周的周日。使用布尔索引筛选数据: 通过条件过滤
data,选择城市为 New York City,年份为 2000,且日期在计算出的该周范围内的数据。
import pandas as pd
from datetime import timedelta
# 指定目标日期
target_date = pd.to_datetime('2000/7/1')
# 计算目标日期所在周的开始和结束日期
current_dayofweek = target_date.dayofweek
week_begin = target_date - timedelta(days=current_dayofweek) # 周一
week_end = target_date + timedelta(days=6 - current_dayofweek) # 周日
# 使用 query 方法进行过滤
data.query(
"城市 == 'New York City' and 年 == 2000 and 日期 >= @week_begin and 日期 <= @week_end"
)运行结果
城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2293566 New York City North America US New York 2000 26.833333 2000-06-26 2000 0.0
2293567 New York City North America US New York 2000 27.222222 2000-06-27 2000 1.0
2293568 New York City North America US New York 2000 23.722222 2000-06-28 2000 2.0
2293569 New York City North America US New York 2000 21.388889 2000-06-29 2000 3.0
2293570 New York City North America US New York 2000 21.666667 2000-06-30 2000 4.0
2293571 New York City North America US New York 2000 23.277778 2000-07-01 2000 5.0
2293572 New York City North America US New York 2000 25.000000 2000-07-02 2000 6.0【练习4-12】 查询New York City在2000年7月1号所处周的工作日数据。
方法一:
# 计算给定日期(2000年7月1日)在该年的第几周
weekofyear = pd.to_datetime('2000/7/1').weekofyear
print(weekofyear) # 结果:26
# 使用布尔索引筛选数据
data[
(data['城市'] == 'New York City') & # 筛选城市为 New York City
(data['日期'].dt.isocalendar().week == weekofyear) & # 筛选特定 ISO 周的数据
(data['日期'].dt.year == 2000) # 筛选特定年份的数据
][:5] # 只取前 5 行结果【否则就是显示整周的数据】方法二:
# 计算给定日期(2000年7月1日)在该年的第几周
weekofyear = pd.to_datetime('2000/7/1').weekofyear
print(weekofyear)
# 使用 query 方法进行过滤
data.query(
"城市 == 'New York City' and "
"日期.dt.isocalendar().week == @weekofyear and "
"日期.dt.year == 2000"
)[:5] # 只取前 5 行结果
运行结果
城市 区域 国家 州 年 日内平均气温 日期 年_备份 星期几
2291739 New York City North America US New York 1995 22.500000 1995-06-26 1995 0.0
2291740 New York City North America US New York 1995 20.666667 1995-06-27 1995 1.0
2291741 New York City North America US New York 1995 17.222222 1995-06-28 1995 2.0
2291742 New York City North America US New York 1995 19.444444 1995-06-29 1995 3.0
2291743 New York City North America US New York 1995 22.777778 1995-06-30 1995 4.0【练习4-13】 查询New York在2020/1/1的记录。
# 方法一
data.loc[('New York','2020/1/1'),]
# 方法二
data.query("City == 'New York' and Date == '2020/1/1'") 区域 国家 州 年 日内平均气温 年_备份 星期几
日期
2020-01-01 Europe France NaN 2020 2.166667 2020 2.0【练习4-14】 查询Paris在2020/1/1的记录,只显示“日内平均气温”列。
data.loc[('New York','2020/1/1'),'日内平均气温']
日期
2020-01-01 2.166667
Name: 日内平均气温, dtype: float64【练习4-15】 查询Florida和New York City在2020/1/1的记录。
data.loc[(['Paris','New York City'], '2020/1/1'), ]
区域 国家 州 年 日内平均气温 年_备份 星期几
城市 日期
Paris 2020-01-01 Europe France NaN 2020 2.166667 2020 2.0
New York City 2020-01-01 North America US New York 2020 4.333333 2020 2.0【练习4-16】 查询2020/1/1的所有记录。
idx = pd.IndexSlice
index1 = slice(None)
index2 = '2020/1/1'
index = idx[index1, index2]
data.loc[index,]
【练习4-17】 查询2020/1/1的所有亚洲城市的记录。
idx = pd.IndexSlice
index1 = slice(None)
index2 = '2020/1/1'
index = idx[index1, index2]
data.loc[index,].query('区域=="Asia"')
【练习4-18】 查询London在2020/3/1到2020/4/1之间的所有数据。
idx = pd.IndexSlice
index1 = 'London'
index2 = slice('2020/3/1', '2020/4/1')
index = idx[index1, index2]
data.loc[index,] 区域 国家 州 年 日内平均气温 年_备份 星期几
城市 日期
London 2019-05-03 Europe United Kingdom NaN 2019 9.666667 2019 4.0
2020-05-03 Europe United Kingdom NaN 2020 11.944444 2020 6.0【练习4-19】 查询London和Zurich在2019/5/3和2020/5/3的数据,只显示“日内平均气温”列。
idx = pd.IndexSlice
index1 = ['London', 'Zurich']
index2 = ['2019/5/3', '2020/5/3']
index = idx[index1, index2]
data.loc[index,'日内平均气温'] 城市 日期
London 2019-05-03 9.666667
2020-05-03 11.944444
Zurich 2019-05-03 8.555556
2020-05-03 10.777778
Name: 日内平均气温, dtype: float64【练习4-20】 使用reset_index()复原所有多级索引,并将“区域” “国家”“州”“城市”“日期”设置为多级索引,如图4-11所示。【练习4-21】—【练习4-31】基于图4-11所示的5级索引。

# 重置 Data 的索引
data.reset_index(inplace=True)data.head()

# 将 '区域', '国家', '州', '城市', '日期' 五列设置为 DataFrame 的多层索引,直接修改原始数据
data.set_index(['区域','国家','州','城市','日期'],inplace=True)# 按照多层索引中的 '区域' 层级对 DataFrame 进行排序,并直接在原数据上修改
data.sort_index(level='区域',inplace=True)data.head

【练习4-21】 查询所有亚洲的城市记录。
data.loc['Asia']

【练习4-22】 查询所有亚洲城市在2020/5/1的记录。
idx = pd.IndexSlice
index1 = 'Asia'
index2 = slice(None)
index3 = slice(None)
index4 = slice(None)
index5 = '2020/5/1'
index = idx[index1, index2,index3,index4,index5]
data.loc[index,'日内平均气温']
【练习4-24】 查询France和US的所有城市在2020/4/7、2020/4/13、2020/5/3的记录。
idx = pd.IndexSlice
index1 = slice(None)
index2 = ['France','US']
index3 = slice(None)
index4 = slice(None)
index5 = ['2020/4/7','2020/4/13','2020/5/3']
index = idx[index1, index2,index3,index4,index5]
data.loc[index,'日内平均气温']
【练习4-25】 查询US的Utah州、Iowa州在2018/11的所有记录。
idx = pd.IndexSlice
index1 = slice(None)
index2 = 'US'
index3 = ['Utah','Iowa']
index4 = slice(None)
index5 = '2018/11'
index = idx[index1, index2,index3,index4,index5]
data.loc[index,'日内平均气温']
【练习4-26】 将“日内平均气温”列的华氏温度转换为摄氏温度℃(转换公式为:C=(F-32)÷1.8)。
data['日内平均气温'] = (data['日内平均气温'] - 32) / 1.8
data.head()

【练习4-27】 查询在2019/8/3气温高于35℃的所有Asia、Europe、North America城市记录。
idx = pd.IndexSlice
index1 = ['Asia','Europe','North American']
index2 = slice(None)
index3 = slice(None)
index4 = slice(None)
index5 = '2019/8/3'
index = idx[index1, index2,index3,index4,index5]
data.loc[index,].query('日内平均气温>30')
【练习4-28】 查询Guangzhou在2019年气温位于25℃和35℃之间的所有记录。
idx = pd.IndexSlice
index1 = slice(None)
index2 = slice(None)
index3 = slice(None)
index4 = 'Guangzhou'
index5 = '2019'
index = idx[index1, index2,index3,index4,index5]
data.loc[index,].query('日内平均气温>=25 and 日内平均气温<=35')
【练习4-29】 查询2020/1/1气温低于0℃的Asia的城市记录。
idx = pd.IndexSlice
index1 = 'Asia'
index2 = slice(None)
index3 = slice(None)
index4 = slice(None)
index5 = '2020/1/1'
index = idx[index1, index2,index3,index4,index5]
data.loc[index,].query('日内平均气温<0')
【练习4-30】 查询Paris、London在2019/5/1及2020/1/1到2020/5/1的记录。
from datetime import date, timedelta
idx = pd.IndexSlice
index1 = slice(None)
index2 = slice(None)
index3 = slice(None)
index4 = ['Paris','London']
begin_date = date(2020,1,1)
end_date = date(2020,5,1)
index5 = pd.date_range(begin_date, end_date, freq='d')
index5 = index5.insert(0, '2019/5/1')
index = idx[index1, index2,index3,index4,index5]
data.loc[index,] 
【练习4-31】 查询Paris和所有US城市在2019/5/1及2020/1/1到2020/5/1的记录。
from datetime import date, timedelta
idx = pd.IndexSlice
index1 = slice(None)
index2 = slice(None)
index3 = slice(None)
index4 = ['Paris','London']
begin_date = date(2020,1,1)
end_date = date(2020,5,1)
index5 = pd.date_range(begin_date, end_date, freq='d')
index5 = index5.insert(0, '2019/5/1')
index = idx[index1, index2,index3,index4,index5]
data.loc[index,]
实验内容二:
# 重新加载、处理数据
data = pd.read_csv('./city_temperature.csv',dtype={'State':object})
data.columns=['城市', '区域', '国家', '州', '月', '日', '年', '日内平均气温']
data['日内平均气温'] = (data['日内平均气温']-32)/1.8
data['日期'] = pd.to_datetime(data['年'].astype(str) + '/' +data['月'].astype(str) + '/' + data['日'].astype(str), format='%Y/%m/%d', errors='coerce')
data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d',errors='coerce')
data.head()
【练习4-32】 按“区域”进行排序。
data.sort_values(by='区域')

【练习4-33】 按“区域”“国家”“州”进行排序。
data.sort_values(by=['区域','国家','州'])

【练习4-34】 按“区域”(升序)、“国家”(降序)、“州”(降序)进行排序。
data.sort_values(by=['区域','国家','州'], ascending=[True,False,False])

【练习4-35】 查询“Asia”的最高气温。
data.query('区域=="Asia"')['日内平均气温'].max()
39.833333333333336
【练习4-36】 查询“US”在2020年1月–3月的所有城市的平均气温。
data.query('国家 == "US" and 年 == 2020 and 日期.dt.month >= 1 and 日期.dt.month <= 3')['日内平均气温'].mean()
6.380134389938312
【练习4-37】 查询全球2000–2010年的最高温度和最低气温。
data.query('年>=2000 and 年<=2010')['日内平均气温'].max()
43.27777777777778
data.query('年>=2000 and 年<=2010')['日内平均气温'].min()
-72.77777777777777
【练习4-38】 查询“US”的“New York City”在2019年气温小于0度的日期的数量。
data.query('城市=="New York City" and 年==2019 and 日内平均气温<0')['日期'].count()
30
【练习4-39】 查询“Europe”的2019年最低气温及出现的城市和日期(仅限于2019年)。
# 查找2019年欧洲地区的最低日内平均气温
europe_2019_min = data.query('区域=="Europe" and 年==2019')['日内平均气温'].min()# 查找在2019年欧洲地区具有最低日内平均气温的城市和日期
data.query('区域=="Europe" and 年==2019 and 日内平均气温==@europe_2019_min')[['城市','日期']]
【练习4-40】 查询2020/1/1最低气温及出现的城市。
world_min = data.query('日期=="2020/1/1"')['日内平均气温'].min()
world_min
-23.444444444444446
data.query('日期=="2020/1/1" and 日内平均气温==@world_min')[['城市','日期']]

【练习4-41】 查询“Beijing”市在2000年的平均气温。
data.query('城市=="Beijing" and 年==2000')['日内平均气温'].mean()
12.652398299939282
【练习4-42】 查询“Beijing”市气温比2000年平均温度高的日期(仅限于2000年)的数量。
bj_min = data.query('城市=="Beijing" and 年==2000')['日内平均气温'].mean()
data.query('城市=="Beijing" and 年==2000 and 日内平均气温>@bj_min')['日期'].count()189
【练习4-43】 计算“Paris”市2019年7月的平均气温和2018年7月平均气温之差。
data.query('城市=="Paris" and 年==2019 and 月==7')['日内平均气温'].mean()
21.801075268817197
data.query('城市=="Paris" and 年==2018 and 月==7')['日内平均气温'].mean()
-5.487455197132616
data.query('城市=="Paris" and 年==2019 and 月==7')['日内平均气温'].mean() -data.query('城市=="Paris" and 年==2018 and 月==7')['日内平均气温'].mean()
27.288530465949812
【练习4-44】 统计各国家的气温平均值。
data.groupby(by='国家')['日内平均气温'].mean()

【练习4-45】 统计各国家的气温平均值,并按照气温平均值降序显示。
data.groupby(by='国家')['日内平均气温'].mean().sort_values()

【练习4-46】 按年统计各国家的年均气温平均值。
data.groupby(by=['年','国家'])['日内平均气温'].mean()

【练习4-47】 统计2019年美国各州的气温最高值、最低值、平均值。
data.query('国家=="US" and 年==2019').groupby(by='州').agg({'日内平均气温':[max, min, np.mean]})

【练习4-48】 查询2019年2月美国月均气温最低的5个州。
data.query('国家=="US" and 年==2019 and 月==2')[['州','日内平均气温']].groupby(by='州').mean().sort_values(by='日内平均气温')[:5]

【练习4-49】 统计“Paris”市2000年每月的温差。和【练习4-50】 统计“Paris”市2000年每月的温差,并将统计数据列命名为“月均温差”。
paris_max = data.query('城市=="Paris" and 年==2000')[['月','日内平均气温']].groupby(by='月').max()
paris_max

paris_min = data.query('城市=="Paris" and 年==2000')[['月','日内平均气温']].groupby(by='月').min()
paris_min

paris_max - paris_min

(paris_max - paris_min).rename({'日内平均气温':"月均温差"},axis=1)

【练习4-51】 统计美国California在2019年7月日均气温高于30℃的天数。
data.query('国家=="US" and 州=="California" and 年==2019 and 月==7 and 日内平均气温>30')['日期'].shape[0]
12
【练习4-52】 统计美国各州1995–2019期间月均气温高于20℃的的月份数量。
month_mean = data.query('国家=="US" and 年>=1995 and 年<=2019').groupby(by=['年','月'])['日内平均气温'].mean().reset_index()
month_mean

month_mean.query('日内平均气温>20').groupby(by='年')['月'].count()

【练习4-53】 统计2019年美国California高温天数(日均气温高于30℃)大于15的月份及当月高温天数。
def my_filter(x):
return (x['日期'].count())>15
grouped_data = data.query('州=="California" and 年==2019 and 日内平均气温>20').groupby(by=['城市','月'])
grouped_data.filter(my_filter).groupby(by=['城市','月']).agg({'日内平均气温':['count']})
data.query('州=="California" and 年==2019 and 日内平均气温>20').groupby(by=['城市','月']).count()

【练习4-54】 查询2017–2019年期间美国年均气温逐步升高(2019年均气温>2018年均气温>2017年均气温>2016年均气温)的州名。
def my_filter(x):
temp = x.groupby('年')['日内平均气温'].mean().values
if (all(temp[i] < temp[i+1] for i in range(len(temp)-1))):
return True
else:
return False
data.query('国家=="US" and 年>=2017 and 年<=2019').groupby(by=['州']).filter(my_filter)['州'].unique()array(['Alaska', 'Hawaii', 'Massachusetts'], dtype=object)
【练习4-55】筛选出城市为广州、月份为7月的数据,按年份分组,计算每年7月的平均温度,然后按温度降序排序
# 筛选出城市为广州、月份为7月的数据,按年份分组,计算每年7月的平均温度,然后按温度降序排序
# 筛选广州市7月份的数据
# 按年份分组并选取平均温度列
# 计算每个年份的平均温度
# 结果按平均温度降序排序
data.query('City=="Guangzhou" and Month==7')\
.groupby(by='Year')['AvgTemperature'] \
.mean()\
.sort_values(ascending=False)【练习4-56】筛选出城市为广州、月份为7月的数据,按年份分组,计算每年7月的平均温度,然后按温度降序排序
# 筛选出城市为广州,月份在7月至9月之间,并且平均温度至少为32摄氏度的数据
# 按年份分组,计算每年满足条件的天数,然后按天数降序排序
data.query('City=="Guangzhou" and Month>=7 and Month<=9 and AvgTemperature>=32')\
.groupby(by='Year')['AvgTemperature']\
.count()\
.sort_values(ascending=False)