資料匯入是所有數模程式設計的第一步,比你想象的更重要。
先要學會一種未必最佳,但是通用、安全、簡單、好學的方法。
『Python 數學建模 @ Youcans』帶你從數模小白成為國賽達人。
1. 資料匯入是所有數模程式設計的第一步
程式設計求解一個數模問題,問題總會涉及一些資料。
有些資料是在題目的文字描述中給出的,有些資料是通過題目的附件檔案下載或指定網址提供的,還有些資料是需要自己蒐集的。不論是哪種方式獲得的資料,也不論哪種型別的問題和演算法,首先都是要把這些資料以適當的方式和格式匯入到程式中。
如果資料格式有問題,輕則讀取資料時發生錯誤,要浪費時間去查詢和解決,在數模競賽中就會讓人非常焦躁。資料錯誤還是輕的嗎?對,重則讀取資料有錯誤,程式卻在繼續執行,得到了錯誤的結果,這在數模競賽中就更糟糕了。你可能都不知道發生了錯誤,就算感覺有問題也不會把錯誤直接鎖定到資料匯入部分,結果不停地去修改其它模組,直到把正確的模組也搞錯了,最後無可救藥。
因此,確保數模程式設計第一步“資料匯入”的順利完成,比原先的想象更重要。
Python 語言中資料匯入的方法很多。對於數學建模問題程式設計來說,選擇什麼方法最好呢?答案是:沒有最好的,只有最合適的。對於不同的問題,不同的演算法,以及所呼叫工具包的不同實現方法,對於資料就會有不同的要求。另外,賽題所給資料檔案中的資料組織方式不同,也需要使用不同的方法來匯入資料。
那麼好了,既然是要具體問題具體分析,這不跟沒說一樣嗎?這正是本文希望回答的問題,雖然針對不同問題的最佳的資料匯入方法也不同,但我們先要學會一種未必最佳,但是通用、安全、簡單、好學的方法。
歡迎關注 『Python 數學建模 @ Youcans』,每週更新數模筆記
Python數學建模-01.新手必讀
Python數學建模-02.資料匯入
Python數學建模-03.線性規劃
Python數模筆記-PuLP庫
Python數模筆記-StatsModels統計迴歸
Python數模筆記-Sklearn
Python數模筆記-NetworkX
Python數模筆記-模擬退火演算法
2. 在程式中直接向變數賦值
直接在程式中向變數賦值,是雖然笨拙但最簡單的方法,也許還是最可靠的方法——如果你沒有敲錯鍵盤的話。
確實,把直接賦值作為資料匯入方法來介紹,實在是不好意思說出口。但是,對於數模競賽這種特殊的需求,直接賦值的方法還是十分常用的,而且完全符合簡單、實用、可靠的要求。
不過,直接賦值也並非我們想的那麼簡單,還是值得認真地談一談。
2.1 為什麼直接賦值?
絕大部分數學建模教材中的例程,都是使用直接賦值的方法匯入資料。很大比例的部落格例程,包括本系列的大多數案例,也都是在程式中直接賦值的。
其原因在於,一是為了保證程式的完整性,複製貼上回車就能得到執行結果,不需要複製資料檔案等操作,就避免了由此引起的各種錯誤;二是為了把讀者的注意力聚焦在主要的知識點,避免干擾;三是使例程更加直觀易懂,便於理解例程的演算法。
這些原因也都是直接賦值的優點。那麼,這些優點不也正是數模競賽程式設計活動的痛點嗎?沒錯,這就是直接賦值方法在數學建模培訓和數模競賽程式設計的實踐中廣泛流行的原因。
2.2 直接賦值的問題與注意事項
但是,即使在數模競賽程式設計中,直接賦值也會有幾個問題。
一是某些問題不能使用直接賦值方法。這主要是大資料的問題,資料量或資料檔案的數量極大,已經不能使用直接賦值實現了。
二是一些問題雖然可以直接賦值,但很容易出錯。這主要是資料量很大,或者資料結構、型別比較複雜的問題。
例如,多元分析、時間序列、資料統計類的題目可能都有很大的資料量,在附件中提供資料檔案。這時如果在使用直接賦值匯入資料,不再是敲鍵盤了,而是從檔案中把資料複製貼上到程式中。
這時要特別注意的問題是:
- 檔案中的資料分隔符是什麼,空格還是逗號,與變數賦值的格式要求是否一致?
- 即使檔案中的資料分隔符看上去是空格,也需要檢查到底是空格還是製表符,是一個空格還是幾個空格?
- 檔案中的資料有沒有錯漏等異常?這在讀取檔案中可以通過程式檢查、識別和處理,在複製貼上時就要人工處理了。
三是資料量不大的問題,完全可以用直接賦值匯入資料,但也會由於疏忽大意而出錯。
這倒不是說敲錯鍵盤了,而是由於例程不一定是把資料賦值作為獨立模組處理的,而是分散在演算法的過程中進行賦值。同學在使用和修改例程時時,就很容易忘記修改演算法過程中的變數賦值。這種情況屢見不鮮,有時是因為對程式沒有搞明白,忽略了演算法步驟中的某個變數;更多時候是忙中出錯,在反覆除錯和更換資料時暈頭轉向,只顧了修改開始的資料而疏忽了後面的資料。
養成資料匯入模組化的習慣,才能避免這一類的疏忽:
- 將資料匯入模組作為單獨的函式。
- 如果不願意使用資料匯入函式,則要把資料匯入部分集中寫成一段,放在程式的起始部分。
- 不要把問題本身的資料匯入與演算法所需的引數賦值混淆,分為兩個獨立的函式或段落。
例程 1:將資料匯入作為單獨的函式
# 子程式:定義優化問題的目標函式
def cal_Energy(X, nVar, mk): # m(k):懲罰因子
p1 = (max(0, 6*X[0]+5*X[1]-320))**2
p2 = (max(0, 10*X[0]+20*X[1]-7027)**2
fx = -(10*X[0]+9*X[1])
return fx+mk*(p1+p2)
# 子程式:模擬退火演算法的引數設定
def ParameterSetting():
tInitial = 100.0 # 設定初始退火溫度(initial temperature)
tFinal = 1 # 設定終止退火溫度(stop temperature)
alfa = 0.98 # 設定降溫引數,T(k)=alfa*T(k-1)
nMarkov = 100 # Markov鏈長度,也即內迴圈執行次數
youcans = 0.5 # 定義搜尋步長,可以設為固定值或逐漸縮小
return tInitial, tFinal, alfa, nMarkov, youcans
例程 2:將資料匯入集中寫成一段,放在程式的起始部分
# 主程式
def main():
# 模型資料匯入
p1 = [6, 5, -320]
p2 = [10, 20, -7027]
p3 = [10, 9]
print(p1,p2,p3)
# 演算法引數設定
tInitial = 100.0 # 設定初始退火溫度(initial temperature)
tFinal = 1 # 設定終止退火溫度(stop temperature)
alfa = 0.98 # 設定降溫引數,T(k)=alfa*T(k-1)
nMarkov = 100 # Markov鏈長度,也即內迴圈執行次數
youcans = 0.5 # 定義搜尋步長,可以設為固定值或逐漸縮小
print(tInitial, tFinal, alfa, nMarkov, youcans)
3. Pandas 匯入資料
雖然很多數模競賽的問題可以通過直接賦值獲取資料,但主流的資料匯入方法還是讀取資料檔案。
數學建模中常用的資料檔案格式有文字檔案(.txt)、Excel 檔案(.xls, .xlsx)和 csv 檔案(.csv)。
在讀取文字檔案時,會遇到逗號、空格、製表符等不同的資料分割符。讀取 Excel 檔案時,首先 .xls 與 .xlsx 的格式不同,其次要考慮資料錶帶不帶標題行,有時檔案中還有多個工作表。讀取檔案時還會遇到資料缺失,非法字元。對於小白來說,特別在競賽時,處理這些問題時都會心神不寧。
Python 中讀取資料檔案的方法也很多。本文非常不推薦使用 Python 自身的檔案操作如開啟(open)、關閉(close)、讀寫(read、readline)函式,而是推薦使用 Pandas 讀取資料檔案。原因在於:
- Pandas 提供了多種常用檔案格式的讀寫函式,以上各種情況都能一行程式碼搞定。
- Pandas 是基於 NumPy 構建的資料分析工具包,便於進行資料整理與清洗,操作方便靈活。
- Pandas 提供了與其它各種資料結構的轉換工具,使用簡單靈活。
- 很多數學建模演算法的例程就是使用 Pandas 的 Series、DataFrame 資料結構,無需進行轉換。
3.1 Pandas 讀取 Excel 檔案
Pandas 使用 read_excel() 函式讀取 Excel檔案。
pd.read_excel(io, sheetname=0,header=0,index_col=None,names=None)
pd.read_excel() 的主要引數:
io : 檔案路徑(包括檔名)。
header :指定作為列名的行。預設為 0,即首行為標題行。設定 header=None,表示無標題行,首行就是資料行。
sheetname:指定工作表。預設為 sheetname=0。設定 sheetname=None 返回全表, 設定 sheetname=[0,1] 返回多表 。
index_col :指定作為行索引的列編號或列名。
names:指定列名, 型別為 list。
pd.read_excel() 使用例項:
# sheetname 表示讀取指定的工作表,header=0 表示首行為標題行,header=None 表示首行為資料行
df = pd.read_excel("data/youcans1.xls", sheetname='Sheet1', header=0)
3.2 Pandas 讀取 csv 檔案
**Pandas 使用 pandas.read_csv() 函式讀取 Excel檔案。 **
pd.read_csv( filepath ,sep=',', header='infer', names=None, index_col=None)
pd.read_csv() 的主要引數:
filepath : 檔案路徑(包括檔名)。
sep:指定分隔符。預設為逗號 ',',可根據需要設定其它分隔符。
header :指定作為列名的行。如果檔案沒有列名則預設為 0,表示首行就是資料行;設定 header=None,表示無標題行,首行就是資料行。
index_col :指定作為行索引的列編號或列名。
names:指定列名, 型別為 list。
pd.read_csv() 使用例項:
# sep=','表示間隔符為逗號,header=0表示首行為標題行,header=None 表示首行為資料行
df = pd.read_csv("data/youcans2.csv", header=0, sep=',')
3.3 Pandas 讀取文字檔案
**對於文字檔案 .txt 和 .dat,可以使用 pandas.read_table() 函式讀取 。 **
pd.read_csv( filepath ,sep='\t', header='infer', names=None, index_col=None)
pd.read_table() 的主要引數:
filepath : 檔案路徑(包括檔名)。
sep:指定分隔符。預設為 tab 製表符,可根據需要設定其它分隔符。
header :指定作為列名的行。如果檔案沒有列名則預設為 0,表示首行就是資料行;設定 header=None,表示無標題行,首行就是資料行。
index_col :指定作為行索引的列編號或列名。
names:指定列名, 型別為 list。
pd.read_table() 使用例項:
# sep='\t'表示分隔符為製表符,header=None 表示無標題行,第一行是資料
df = pd.read_table("data/youcans3.dat", sep="\t", header=None)
3.4 Pandas 讀取其它檔案格式
Pandas 還提供了讀取多種檔案格式的函式,使用方法也都類似,都是一行程式碼搞定。例如:
- pandas.read_sql,讀取 SQL 資料庫
- pandas.read_html,抓取網頁中的表格資料
- pandas.read_json,讀取 JSON 資料檔案
- pandas.read_clipboard,讀取剪貼簿內容
由於這些檔案格式中數模競賽中很少用到,本文就不進行詳細介紹了。有需要的同學可以根據函式名通過搜尋引擎搜尋參考資料,也可以查閱官方文件:
- Pandas 輸入輸出函式的說明文件 Input/output — pandas 1.2.4 documentation (pydata.org)
- https://pandas.pydata.org/pandas-docs/stable/reference/io.html
此外,對於大資料類的問題,所需處理的資料量可能非常大,必要時需對檔案進行拆分或合併,也可以用 pandas 進行處理,這將在後續文章結合具體問題進行講解。
4. 資料匯入例程
【重要說明】以上章節的內容雖然介紹了資料匯入的基本方法,但恐怕還是難以達到消化吸收,為我所用。為了解決這個問題,本文將相關內容整合為例程,以便於讀者學習收藏,也便於使用修改。
例程01:讀取資料檔案
# mathmodel01_v1.py
# Demo01 of mathematical modeling algorithm
# Read data files into DataFrame.
# Copyright 2021 Youcans, XUPT
# Crated:2021-05-27
import pandas as pd
# 讀取資料檔案
def readDataFile(readPath): # readPath: 資料檔案的地址和檔名
# readPath = "../data/youcansxupt.csv" # 檔案路徑也可以直接在此輸入
try:
if (readPath[-4:] == ".csv"):
dfFile = pd.read_csv(readPath, header=0, sep=",") # 間隔符為逗號,首行為標題行
# dfFile = pd.read_csv(filePath, header=None, sep=",") # sep: 間隔符,無標題行
elif (readPath[-4:] == ".xls") or (readPath[-5:] == ".xlsx"): # sheet_name 預設為 0
dfFile = pd.read_excel(readPath, header=0) # 首行為標題行
# dfFile = pd.read_excel(filePath, header=None) # 無標題行
elif (readPath[-4:] == ".dat"): # sep: 間隔符,header:首行是否為標題行
dfFile = pd.read_table(readPath, sep=" ", header=0) # 間隔符為空格,首行為標題行
# dfFile = pd.read_table(filePath,sep=",",header=None) # 間隔符為逗號,無標題行
else:
print("不支援的檔案格式。")
except Exception as e:
print("讀取資料檔案失敗:{}".format(str(e)))
return
return dfFile
# 主程式
def main():
# 讀取資料檔案 # Youcans, XUPT
readPath = "../data/toothpaste.csv" # 資料檔案的地址和檔名
dfFile = readDataFile(readPath) # 呼叫讀取檔案子程式
print(type(dfFile)) # 檢視 dfFile 資料型別
print(dfFile.shape) # 檢視 dfFile 形狀(行數,列數)
print(dfFile.head()) # 顯示 dfFile 前 5 行資料
return
if __name__ == '__main__': # Youcans, XUPT
main()
例程01 執行結果:
<class 'pandas.core.frame.DataFrame'>
(30, 6)
period price average advertise difference sales
0 1 3.85 3.80 5.50 -0.05 7.38
1 2 3.75 4.00 6.75 0.25 8.51
2 3 3.70 4.30 7.25 0.60 9.52
3 4 3.70 3.70 5.50 0.00 7.50
4 5 3.60 3.85 7.00 0.25 9.33
例程01 程式說明:
- 本例程需要讀取資料檔案 "../data/toothpaste.csv",該檔案儲存在 ../data/ 目錄下。讀者需要修改該資料檔案的檔案路徑和檔名,以便讀取自己需要的本地檔案。
- 本例程可以根據檔名的字尾自動識別檔案型別,呼叫相應的函式讀取檔案。
- 本例程中讀取檔案模組使用 try...except 語句進行簡單的異常處理。如果讀取失敗,可以根據丟擲的異常型別查詢錯誤。
【本節完】
版權說明:
歡迎關注『Python 數學建模 @ Youcans』 原創作品
原創作品,轉載必須標註原文連結。
Copyright 2021 Youcans, XUPT
Crated:2021-05-27
歡迎關注『Python 數學建模 @ Youcans』系列,每週持續更新
Python數學建模-01.新手必讀
Python數學建模-02.資料匯入
Python數學建模-03.線性規劃
Python數模筆記-PuLP庫(1)線性規劃入門
Python數模筆記-PuLP庫(2)線性規劃進階
Python數模筆記-PuLP庫(3)線性規劃例項
Python數模筆記-StatsModels 統計迴歸(1)簡介
Python數模筆記-StatsModels 統計迴歸(2)線性迴歸
Python數模筆記-StatsModels 統計迴歸(3)模型資料的準備
Python數模筆記-StatsModels 統計迴歸(4)視覺化
Python數模筆記-Sklearn (1)介紹
Python數模筆記-Sklearn (2)聚類分析
Python數模筆記-Sklearn (3)主成分分析
Python數模筆記-Sklearn (4)線性迴歸
Python數模筆記-Sklearn (5)支援向量機
Python數模筆記-模擬退火演算法(1)多變數函式優化
Python數模筆記-模擬退火演算法(2)約束條件的處理
Python數模筆記-模擬退火演算法(3)整數規劃問題
Python數模筆記-模擬退火演算法(4)旅行商問題
Python數模筆記-NetworkX(1)圖的操作
Python數模筆記-NetworkX(2)最短路徑
Python數模筆記-NetworkX(3)條件最短路徑
Python數模筆記-NetworkX(4)最小生成樹
Python數模筆記-NetworkX(5)關鍵路徑法