想要看更加舒服的排版、更加准时的推送
关注公众号“不太灵光的程序员”
每日八点有干货推送
公众号“不太灵光的程序员” 同时发布《手把手教你完成课设作业使用Pandas对海平面温度异常进行分析,小白也能看的懂》
最近咨询课设问题的同学越来越多了,大部分都是用Pandas做数据统计的问题,我就找一个相对比较简单的课设题目讲下解题过程。
其中涉及的知识点还是挺多的,上来第一题的用到了逆向透视表,csv文件的读写,数据映射、数据聚合方法、数据可视化等等。
想要源码及附件请在留言板写下你的邮箱!
我们现在做点准备工作,首先检查下你的python版本、需要注意作者使用的是python3。
使用pip freeze命令查看你的环境是否安装有matplotlib、pandas,没有的话使用pip install matplotlib和pip install pandas命令安装。
厄尔尼诺事件是指赤道中、东太平洋海表大范围持续异常偏暖的现象,其 评判标准在国际上还存在一定差别。
一般将NINO 3区海温距平指数连续 6 个月达到 0.5℃以上定义为一次厄尔尼诺事件,美国则将 NINO 3.4 区海温距平 的 3 个月滑动平均值达到 0.5℃以上定义为一次厄尔尼诺事件。
为更加充分地反映赤道中、东太平洋的整体状况,目前,中国气象局国家 气候中心在业务上主要以 NINO 综合区(NINO 1 + 2 + 3 + 4 区)的海温距平 指数作为判定厄尔尼诺事件的依据,指标如下:
NINO 综合区海温距平指数持续 6 个月以上≥0.5℃(过程中间可有单个月份未达指标)为一次厄尔尼诺事 件;若该区指数持续 5 个月≥0.5℃,且 5 个月的指数之和≥4.0℃,也定义为 一次厄尔尼诺事件。
数据集为 1870-2018 年 NINO1+2 区(0-10°S, 90°W-80°W)海平面温度异 常滑动平均值,如下图所示。
字段说明:
Year 列,表示年份
列January~December分别表示对应月份的 NINO1+2 区海平面温度 异常滑动平均值
用 pandas 库读取“nino12.long.anom.data.csv”文件,将所有时间抽取为单独的列 Date(形式为 YYYY-MM-01),所有异常平均值抽取为一个单独的列 Nino12,将所有缺失值丢弃处理,并导出到新的 txt 文件 “nino12_dropnan.txt”,第一行为表头,列名分别为 Date 和 Nino12,且表 头和数据行中的不同字段信息都是用逗号分割,如下图所示。
这里你可以把csv文件看做是带分隔符的txt文件,所以可以操作csv文件的函数都是可以操作txt文件的。
在pandas可以使用read_csv来读取csv文件,并返回DataFrame对象,to_csv是将DataFrame保存到文件中,想保存成txt文件的话直接在文件名后缀中显示表现出来即可。
第一个任务的重点是在将所有时间抽取为单独的列 Date,所有异常平均值抽取为一个单独的列 Nino12。
我们先把任务拆解下:
Month替换成数值字符串使用map对映射字典进行替换。map、apply、applymap号称Pandas数据处理三板斧,分别可以实现逐行、逐列和逐元素操作。
import matplotlib.pyplot as plt
import pandas as pd
import itertools
def task1():
# 读取文件
df_nino12 = pd.read_csv("nino12.long.anom.data.csv", sep=",")
# 月份映射表
month_map = {"January": "01",
"February": "02",
"March": "03",
"April": "04",
"May": "05",
"June": "06",
"July": "07",
"August": "08",
"September": "09",
"October": "10",
"November": "11",
"December": "12"}
# 逆向透视表, 对透视表概念不了解的 科普下 pivot_table
df_nino12 = df_nino12.melt(id_vars="Year", var_name="month", value_name="Nino12")
# 使用map对映射字典进行替换
df_nino12["month"] = df_nino12["month"].map(month_map)
# Date格式拼接
df_nino12["Date"] = df_nino12["Year"].map(str) + "-" + df_nino12["month"] + "-01"
# 以Date进行排序,默认升序,降序可以使用ascending=False
df_nino12 = df_nino12.sort_values(by="Date")
# 将"Date", "Nino12"两列输出到 nino12_dropnan.txt 文件
df_nino12[["Date", "Nino12"]].to_csv('nino12_dropnan.txt', sep=',', index=False)
重新读取新的数据集“nino12_dropnan.txt”,选择 Nino12 字段,统计最大 值 maxValue、最小值 minValue、平均值 meanValue。
任务二是对pandas聚合操作的使用,pandas支持以下聚合操作。
import matplotlib.pyplot as plt
import pandas as pd
import itertools
def task2():
df = pd.read_csv("nino12_dropnan.txt", sep=",")
print(df["Nino12"].min())
print(df["Nino12"].max())
print(df["Nino12"].mean())
重新读取文件“nino12_dropnan.txt”,利用第三步统计结果最大值 maxValue、最小值 minValue,利用 category = [minValue, -0.5, 0,0.5, maxValue] 和 labels = [‘LaNinaTemp’, ‘Cold’, ‘Warm’, ‘NinoTemp’]将 Nino12 进行离散化;
并将离散化结果作为一个新的列 Label 添加到原始数据集,并保存为“nino12_dropnan_result.csv”,从左到右三个列名分别为 Date、 Nino12、Label;
根据离散化结果画出饼状图,保存为“nino12_ pie.png”, 要求分辨率不低于 300dpi。
任务三是对pandas聚合操作的使用,pandas支持一下聚合操作
在进行数据的汇总和分析时我们经常需要对连续性的数据变量进行分段汇总。
cut函数就是用来把一组数据分割成离散的区间,题目中的min~-0.5
归为LaNinaTemp,-0.5~0
归为Cold,就是这么个意思。
使用matplotlib模块画图,matplotlib的使用看源代码的注释。
import matplotlib.pyplot as plt
import pandas as pd
import itertools
def task3():
df = pd.read_csv("nino12_dropnan.txt", sep=",")
category = [df["Nino12"].min(), -0.5, 0, 0.5, df["Nino12"].max()]
lables = ['LaNinaTemp', 'Cold', 'Warm', 'NinoTemp']
# 将 Nino12 进行离散化
df['Lable'] = pd.cut(df['Nino12'], category, labels=lables)
df[["Date", "Nino12", "Lable"]].to_csv('nino12_dropnan_result.csv', sep=',', index=False)
# 创建一个画布
plt.figure()
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 声明标题
plt.title("厄尔尼诺现象离散化统计饼状图")
# 将数据载入画布
df['Lable'].value_counts().plot.pie(
explode=(0, 0, 0.1, 0), # 将某一块分割出来,值越大分割出的间隙越大
autopct='%.2f', # 每块的占比
shadow=True, # 阴影设置
startangle=140, # 逆时针起始角度设置
figsize=(6, 7) # 画布比例
)
# 保存的文件名 分辨率
plt.savefig('nino12_pie.png', dpi=300)
plt.show()
重新读取文件“nino12_dropnan_result.csv”,根据列 Lable 判断,假设若连 续出现 5 次’LaNinaTemp’则判定为出现了一次 LaNina 事件,选择 LaNina 事 件出现的开始时间存储到列表 LaNinaList 中;
假设若连续出现 5 次 NinoTemp 则认为出现了 Nino 事件,选择 Nino 事件出现的开始时间存储到 列表 NinoList 中。
最后,将列表 LaNinaList、NinoList 分别保存到文本文件 “LaNinaStartDate.txt”、“NinoStartDate.txt”中。
参考代码:计算一个列表中连续相同的元素个数,并返回连续出现 4 次及以上 的 1 所在的开始位置。
def demo():
mylist = [1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 11, 0]
num_times = [(k, len(list(v))) for k, v in itertools.groupby(mylist)]
print(num_times)
sumIndexList = []
# 存储符合要求的元素首次出现的位置
for i in range(len(num_times)):
if num_times[i][0] == 1 and num_times[i][1] >= 4:
sumIndex = 0
while i >= 1:
sumIndex += num_times[i - 1][1]
i = i - 1
sumIndexList.append(sumIndex)
print(sumIndexList)
任务四,我们先把任务拆解下:
import matplotlib.pyplot as plt
import pandas as pd
import itertools
def task4():
df = pd.read_csv("nino12_dropnan_result.csv", sep=",")
LaNinaList_index = []
NinoList_index = []
num_times = [(k, len(list(v))) for k, v in itertools.groupby(df["Lable"])]
for i in range(len(num_times)):
if num_times[i][0] == "LaNinaTemp" and num_times[i][1] >= 4:
sumIndex = 0
while i >= 1:
sumIndex += num_times[i - 1][1]
i = i - 1
LaNinaList_index.append(sumIndex)
elif num_times[i][0] == "NinoTemp" and num_times[i][1] >= 4:
sumIndex = 0
while i >= 1:
sumIndex += num_times[i - 1][1]
i = i - 1
NinoList_index.append(sumIndex)
# LaNinaList = df["Date"].iloc[LaNinaList_index].to_list()
LaNinaList = df["Date"].iloc[LaNinaList_index]
# NinoList = df["Date"].iloc[NinoList_index].to_list()
NinoList = df["Date"].iloc[NinoList_index]
LaNinaList.to_csv('LaNinaStartDate.txt', sep=',', index=False)
NinoList.to_csv('NinoStartDate.txt', sep=',', index=False)
到这里就把所有题目就全部接完了,是不是还不尽兴
后面还有一个关于《无车承运人平台线路定价问题》的题目,敬请期待