想要看更加舒服的排版、更加準時的推送
關注公衆號“不太靈光的程序員”
每日八點有乾貨推送
公衆號“不太靈光的程序員” 同時發佈《手把手教你完成課設作業使用Pandas對海平面溫度異常進行分析,小白也能看的懂》
最近諮詢課設問題的同學越來越多了,大部分都是用Pandas做數據統計的問題,我就找一個相對比較簡單的課設題目講下解題過程。
其中涉及的知識點還是挺多的,上來第一題的用到了逆向透視表,csv文件的讀寫,數據映射、數據聚合方法、數據可視化等等。
想要源碼及附件請在留言板寫下你的郵箱!
我們現在做點準備工作,首先檢查下你的python版本、需要注意作者使用的是python3。
使用pip freeze命令查看你的環境是否安裝有matplotlib、pandas,沒有的話使用pip install matplotlib和pip install pandas命令安裝。
題目:1870-2018年Nino1+2區海平面溫度異常分析
【背景】
厄爾尼諾事件是指赤道中、東太平洋海表大範圍持續異常偏暖的現象,其 評判標準在國際上還存在一定差別。
一般將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 區海平面溫度 異常滑動平均值
【任務1】
用 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。
我們先把任務拆解下:
- 我們首先要以Year爲基準將多列的月份和異常平均值合併到成兩列數據;
- 再將Month替換成數值字符串;
- 然後把Year和Month拼接成Date格式
- 取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)
【任務2】
重新讀取新的數據集“nino12_dropnan.txt”,選擇 Nino12 字段,統計最大 值 maxValue、最小值 minValue、平均值 meanValue。
解析:
任務二是對pandas聚合操作的使用,pandas支持以下聚合操作。
- count 計算分組中非NA值的數量
- sum 計算非NA值的和
- mean 計算非NA值的平均值
- median 計算非NA值的算術中位數
- std 計算非NA值標準差
- var 計算非NA值標方差
- min 獲得非NA值的最小值
- max 獲得非NA值的最大值
- prod 計算非NA值的積
- first 獲得第一個非NA值
- last 獲得最後一個非NA值
源代碼:
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())
【任務3】
重新讀取文件“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()
餅狀圖:
【任務4】
重新讀取文件“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)
解析:
任務四,我們先把任務拆解下:
- 我是想先把根據參考代碼把Lable 中連續大於5次的Temp找出來;
- 再根據返回值中的初始索引去獲取對應的時期。
源代碼:
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)
到這裏就把所有題目就全部接完了,是不是還不盡興
後面還有一個關於《無車承運人平臺線路定價問題》的題目,敬請期待