本篇以實際的美國飛機航班延誤紀錄資料,示範在實務上如何處理與分析巨量資料。
飛機航班的延誤會直接對旅客造成不便,因此我們會希望藉著分析班機誤點的資料,找出可能造成誤點的原因,進而嘗試降低航班延誤的頻率,不過這類的資料量通常都非常龐大,比較難以傳統的方式來處理。
以下我們將使用各種巨量資料處理工具,分析美國的航班誤點資料。
Airline on-time performance 資料集
美國統計協會(ASA)在 2009 年發布了一份 Airline on-time performance 資料集(亦可從 BTS 的網站篩選欄位與下載),裡面包含了全美國從 1987 年 10 月份至 2008 年 4 月份的航班延誤紀錄,這份資料集相當龐大,壓縮後的資料就有 1.6 GB,而未壓縮的話則有 12 GB。
Airline on-time performance 原始的資料來源是美國統計協會的網站,但是目前該網站已經關閉了,想要取得這份資料,可以從 kaggle 的網站下載。
每個 CSV 檔案都有 29 個欄位,以下是少部分的範例資料:
ActualElapsedTime,AirTime,ArrDelay,ArrTime,CRSArrTime,CRSDepTime,CRSElapsedTime,CancellationCode,Cancelled,CarrierDelay,DayOfWeek,DayofMonth,DepDelay,DepTime,Dest,Distance,Diverted,FlightNum,LateAircraftDelay,Month,NASDelay,Origin,SecurityDelay,TailNum,TaxiIn,TaxiOut,UniqueCarrier,WeatherDelay,Year
53,32,-8,1642,1650,1545,65,NA,0,NA,4,10,4,1549,PIT,205,0,209,NA,10,NA,DCA,NA,N443US,7,14,US,NA,2002
164,155,-11,1754,1805,1610,175,NA,0,NA,4,2,0,1610,MCI,1072,0,109,NA,12,NA,MCO,NA,N755,2,7,WN,NA,1999
60,NA,15,2005,1950,1850,60,NA,0,NA,5,10,15,1905,CLT,227,0,1276,NA,12,NA,ATL,NA,NA,NA,NA,DL,NA,1993
51,NA,-5,1818,1823,1728,55,NA,0,NA,4,28,-1,1727,BNA,200,0,961,NA,9,NA,MEM,NA,NA,NA,NA,AA,NA,1989
45,29,2,1120,1118,1030,48,,0,0,1,19,5,1035,CMH,116,0,5873,0,6,0,CVG,0,N785CA,3,13,OH,0,2006
49,37,2,1137,1135,1048,47,NA,0,NA,4,2,0,1048,CLT,156,0,353,NA,1,NA,MYR,NA,N934VJ,6,6,US,NA,1997
61,40,-3,1537,1540,1440,60,,0,NA,7,20,-4,1436,LAW,140,0,3281,NA,7,NA,DFW,NA,N286AE,7,14,MQ,NA,2008
150,126,-19,2015,2034,1745,169,NA,0,NA,4,15,0,1745,ATL,903,0,1521,NA,10,NA,PVD,NA,N919DE,14,10,DL,NA,1998
115,103,-5,735,740,640,120,NA,0,NA,2,16,0,640,SEA,689,0,1678,NA,6,NA,SLC,NA,N346,2,10,WN,NA,1998
NA,NA,NA,NA,730,605,85,B,1,0,7,10,NA,NA,SLC,391,0,4117,0,4,0,DEN,0,N705EV,0,0,EV,0,2005
各個欄位的說明請參考 kaggle 網站上的敘述,接下來我們就可以開始分析裡面的資料了。
由於本文在撰寫時是從美國統計協會的網站取得原始資料,目前該網站已經關閉,而 kaggle 所提供的資料是將所有年份混在一起的 CSV 檔案,本文中部分程式碼是處理依照年份拆開的 CSV 檔案,在使用上就必須先將資料調整一下。
基本統計問題
由於 Airline on-time performance 的資料量相當大,直接以 Excel 看原始的資料是沒有太大的意義的,一般來說我們都會使用各種工具來分析資料的各種統計資訊,至於要看那些統計資訊就因人而異了,以下我們示範幾種常見的基本統計量的計算方式:
- 每一年的資料筆數是多少?
- 一週當中每一天的資料總筆數是多少?(所有年份)。
- 每一年中,
TailNum欄位為NA的資料筆數是多少?。 - 哪一年的班機誤點情況最嚴重?
- 一週當中,星期幾的班機誤點情況最嚴重?
可用來計算這些統計量的工具有很多種,我們這裡分別以 R 語言、Linux 指令以及 SQLite 資料庫等方式來計算這些統計數值,大家可以比較各種工具的差異。
不過若僅以單一工具來分析資料,通常都會有些限制,比較好的方式是善用各種工具的長處,總合起來分析資料。
R 語言
若要在 R 中計算每一年的資料筆數,直覺作法就是把 CSV 的資料讀進來,再計算每一年的資料筆數:
# 計算每一年的資料筆數
for(year in 1987:2008) {
x <- read.csv(paste0(year, ".csv"))
cat(year, "年:", nrow(x), "\n")
# 刪除不用的資料
rm(x)
# 回收記憶體
gc()
}
1987 年: 1311826 1988 年: 5202096 1989 年: 5041200 1990 年: 5270893 1991 年: 5076925 1992 年: 5092157 1993 年: 5070501 1994 年: 5180048 1995 年: 5327435 1996 年: 5351983 1997 年: 5411843 1998 年: 5384721 1999 年: 5527884 2000 年: 5683047 2001 年: 5967780 2002 年: 5271359 2003 年: 6488540 2004 年: 7129270 2005 年: 7140596 2006 年: 7141922 2007 年: 7453215 2008 年: 7009728
若要計算一週當中每一天的資料總筆數,可以這樣寫:
# 計算一週當中每一天的資料總筆數
dayCount <- rep(0, 7)
for(year in 1987:2008) {
x <- read.csv(paste0(year, ".csv"))
for(i in 1:7) {
dayCount[i] <- dayCount[i] + sum(x[,"DayOfWeek"] == i)
}
# 刪除不用的資料
rm(x)
# 回收記憶體
gc()
}
dayCount
[1] 18136111 18061938 18103222 18083800 18091338 15915382 17143178
若要計算每一年中 TailNum 欄位為 NA 的資料筆數,可以這樣寫:
# 計算每一年中 TailNum 欄位為 NA 的資料筆數
for(year in 1987:2008) {
x <- read.csv(paste0(year, ".csv"))
cat(year, "年:", sum(is.na(x[,"TailNum"])), "\n")
# 刪除不用的資料
rm(x)
# 回收記憶體
gc()
}
1987 年: 1311826 1988 年: 5202096 1989 年: 5041200 1990 年: 5270893 1991 年: 5076925 1992 年: 5092157 1993 年: 5070501 1994 年: 5180048 1995 年: 0 1996 年: 0 1997 年: 0 1998 年: 0 1999 年: 0 2000 年: 0 2001 年: 0 2002 年: 0 2003 年: 0 2004 年: 0 2005 年: 0 2006 年: 0 2007 年: 0 2008 年: 0
若要計算每一年班機平均的起飛與到達延遲時間,可以這樣寫:
# 計算每一年班機平均的起飛與到達延遲時間
for(year in 1987:2008) {
x <- read.csv(paste0(year, ".csv"))
cat(year, "年:", mean(x[,"ArrDelay"], na.rm = TRUE), "/",
mean(x[,"DepDelay"], na.rm = TRUE), "\n")
# 刪除不用的資料
rm(x)
# 回收記憶體
gc()
}
1987 年: 9.446699 / 8.063638 1988 年: 6.54735 / 6.706768 1989 年: 8.406396 / 8.202822 1990 年: 6.809947 / 6.909441 1991 年: 4.736445 / 5.753782 1992 年: 4.879558 / 5.688272 1993 年: 5.344062 / 6.122581 1994 年: 5.66249 / 6.659922 1995 年: 7.024064 / 8.278766 1996 年: 9.673284 / 9.991075 1997 年: 7.490578 / 8.235566 1998 年: 7.586968 / 9.024561 1999 年: 8.246601 / 9.337101 2000 年: 10.47289 / 11.28068 2001 年: 5.528249 / 8.154837 2002 年: 3.191244 / 5.532276 2003 年: 3.596694 / 5.248231 2004 年: 6.508066 / 7.892314 2005 年: 7.181343 / 8.674313 2006 年: 8.68284 / 10.09364 2007 年: 10.19218 / 11.39914 2008 年: 8.168452 / 9.97257
若要計算一週當中每一天班機平均的起飛與到達延遲時間,則可這樣寫:
# 計算一週當中每一天班機平均的起飛與到達延遲時間
arrDelaySum <- rep(0, 7)
arrDelayCount <- rep(0, 7)
depDelaySum <- rep(0, 7)
depDelayCount <- rep(0, 7)
for(year in 1987:2008) {
x <- read.csv(paste0(year, ".csv"))
for(i in 1:7) {
idx <- x[,"DayOfWeek"] == i
arr <- x[idx, "ArrDelay"]
arr <- arr[!is.na(arr)]
dep <- x[idx, "DepDelay"]
dep <- dep[!is.na(dep)]
arrDelaySum[i] <- arrDelaySum[i] + sum(arr)
arrDelayCount[i] <- arrDelayCount[i] + length(arr)
depDelaySum[i] <- depDelaySum[i] + sum(dep)
depDelayCount[i] <- depDelayCount[i] + length(dep)
}
# 刪除不用的資料
rm(x)
# 回收記憶體
gc()
}
arrDelaySum / arrDelayCount
depDelaySum / depDelayCount
[1] 6.669515 5.960421 7.091502 8.945047 9.606953 4.187419 6.525040 [1] 7.850057 6.855870 7.651197 9.246910 10.151539 6.887023 8.409293
Linux 指令
由於 CSV 檔中的資料是一筆一行,所以若要在 Linux 的 shell 中計算每一年的資料筆數,可以使用 wc 指令計算每個 CSV 檔案的行數,再自己扣掉第一行的標頭行即可:
# 計算每一個 CSV 檔的行數
wc -l *.csv
1311827 1987.csv
5202097 1988.csv
5041201 1989.csv
5270894 1990.csv
5076926 1991.csv
5092158 1992.csv
5070502 1993.csv
5180049 1994.csv
5327436 1995.csv
5351984 1996.csv
5411844 1997.csv
5384722 1998.csv
5527885 1999.csv
5683048 2000.csv
5967781 2001.csv
5271360 2002.csv
6488541 2003.csv
7129271 2004.csv
7140597 2005.csv
7141923 2006.csv
7453216 2007.csv
7009729 2008.csv
123534991 total在計算一週當中每一天的資料總筆數之前,我們先把所有資料放進一個 CSV 檔案中,並去掉標頭行,這樣可以讓後續的處理比較方便一些:
# 將所有資料放進一個 CSV 檔案中,並去掉標頭行
for year in {1987..2008}
do
tail -n+2 $year.csv >> AirlineDataNoHeader.csv
done
若要計算一週當中每一天的資料總筆數,可以使用 cut 指令將星期幾的欄位切出來,經過 sort 指令排序,最後交給 uniq 指令計算出線次數:
# 計算一週當中每一天的資料總筆數
cut -d, -f4 AirlineDataNoHeader.csv | sort | uniq -c
18136111 1 18061938 2 18103222 3 18083800 4 18091338 5 15915382 6 17143178 7
如果只要計算其中一天的資料總筆數,可以改用 grep 指令,這樣會比較快一些:
# 計算其中一天的資料總筆數
cut -d, -f4 AirlineDataNoHeader.csv | grep 6 | wc -l
15915382
若要計算每一年中 TailNum 欄位為 NA 的資料筆數,可以用 cut 指令將年份與 TailNum 欄位切出來,再用類似的方式計算:
# 計算每一年中 TailNum 欄位為 NA 的資料筆數
cut -d, -f1,11 AirlineDataNoHeader.csv | grep ',NA$' | sort | uniq -c
1311826 1987,NA 5202096 1988,NA 5041200 1989,NA 5270893 1990,NA 5076925 1991,NA 5092157 1992,NA 5070501 1993,NA 5180048 1994,NA
其餘比較複雜的計算在 Linux 的 shell 中就比較不好處理了,如果要更進一步分析的話,建議改用其他的工具。
SQLite 資料庫
資料庫可以協助我們管理較為龐大的資料,並且可以使用 SQL 的語法從大量的資料中取出有用的資訊,這裡我們以 SQLite 這個輕量級的資料庫來進行示範基本的操作方式,而這裡的 SQL 語法也可以套用在任何其他的 SQL 資料庫上。
在 AirlineDataNoHeader.csv 這個 CSV 檔的所在目錄下,建立一個 SQLite 資料庫檔案:
sqlite3 AirlineDelay.sqlite3
進入 SQLite shell 環境之後,先建立一個名稱為 AirlineDelay 的資料表:
CREATE TABLE AirlineDelay (
Year int,
Month int,
DayofMonth int,
DayOfWeek int,
DepTime int,
CRSDepTime int,
ArrTime int,
CRSArrTime int,
UniqueCarrier varchar(5),
FlightNum int,
TailNum varchar(8),
ActualElapsedTime int,
CRSElapsedTime int,
AirTime int,
ArrDelay int,
DepDelay int,
Origin varchar(3),
Dest varchar(3),
Distance int,
TaxiIn int,
TaxiOut int,
Cancelled int,
CancellationCode varchar(1),
Diverted varchar(1),
CarrierDelay int,
WeatherDelay int,
NASDelay int,
SecurityDelay int,
LateAircraftDelay int
);
接著再將 AirlineDataNoHeader.csv 的資料匯入 AirlineDelay 這個資料表:
.mode csv
.import AirlineDataNoHeader.csv AirlineDelay
資料匯入完成後,就可以使用 SQL 的語法查詢各種資訊了。為了讓輸出的結果更容易閱讀,我們啟用欄位標頭,並以表格的方式輸出資料:
.header on
.mode column
若要計算每一年的資料筆數,可以在 SQLite shell 環境中執行以下 SQL 查詢指令:
-- 計算每一年的資料筆數
SELECT Year, COUNT(*) FROM AirlineDelay GROUP BY Year;
Year COUNT(*) ---------- ---------- 1987 1311826 1988 5202096 1989 5041200 1990 5270893 1991 5076925 1992 5092157 1993 5070501 1994 5180048 1995 5327435 1996 5351983 1997 5411843 1998 5384721 1999 5527884 2000 5683047 2001 5967780 2002 5271359 2003 6488540 2004 7129270 2005 7140596 2006 7141922 2007 7453215 2008 7009728
若要計算一週當中每一天的資料總筆數,則執行:
-- 計算一週當中每一天的資料總筆數
SELECT DayOfWeek, COUNT(*) FROM AirlineDelay GROUP BY DayOfWeek;
DayOfWeek COUNT(*) ---------- ---------- 1 18136111 2 18061938 3 18103222 4 18083800 5 18091338 6 15915382 7 17143178
若要計算每一年中 TailNum 欄位為 NA 的資料筆數,則執行:
-- 計算每一年中 TailNum 欄位為 NA 的資料筆數
SELECT Year, COUNT(*) FROM AirlineDelay WHERE TailNum = "NA" GROUP BY Year;
Year COUNT(*) ---------- ---------- 1987 1311826 1988 5202096 1989 5041200 1990 5270893 1991 5076925 1992 5092157 1993 5070501 1994 5180048
-- 計算每一年班機平均的起飛與到達延遲時間
SELECT Year, AVG(ArrDelay), AVG(DepDelay) FROM AirlineDelay GROUP BY Year;
Year AVG(ArrDelay) AVG(DepDelay) ---------- ---------------- ---------------- 1987 9.27747124999809 7.94263644721175 1988 6.46604580153846 6.64209541692426 1989 8.25797806077918 8.08214393398397 1990 6.72155951562667 6.84067557432868 1991 4.68411627116808 5.70447721800105 1992 4.818018965244 5.62925082631977 1993 5.27009816189761 6.05031869631817 1994 5.57630045126995 6.57411475723777 1995 6.88905674118971 8.13594647330282 1996 9.41544302364189 9.75112383578199 1997 7.33854234130591 8.08679353780219 1998 7.36481370158268 8.78236996865762 1999 7.99617539007693 9.07645547554905 2000 10.1011063255328 10.9085196726334 2001 5.30212038647537 7.83891061667823 2002 3.14674773620996 5.46390883261793 2003 3.53413911295916 5.16615771806909 2004 6.37885828422826 7.75088347053766 2005 7.03274222487871 8.51185923415917 2006 8.51491993331767 9.92131347836059 2007 9.94886756923019 11.1532895535685 2008 7.9881812817844 9.77873620773873
若要計算一週當中,每一天班機平均的起飛與到達延遲時間,可執行:
-- 計算一週當中每一天班機平均的起飛與到達延遲時間
SELECT DayOfWeek, AVG(ArrDelay), AVG(DepDelay) FROM AirlineDelay GROUP BY DayOfWeek;
DayOfWeek AVG(ArrDelay) AVG(DepDelay) ---------- ---------------- ---------------- 1 6.52783559827132 7.70100216082709 2 5.82249258080722 6.71302021964642 3 6.93274048122483 7.49766168696379 4 8.74715087536912 9.06447627158009 5 9.40303503256641 9.96035776900526 6 4.10892732577829 6.77322046055822 7 6.41214715264579 8.28289019690515
若要離開 SQLite shell 環境,則執行:
.exit
這裡在 SQLite shell 環境中計算的結果,跟上面 R 的計算結果有些差異,主要的原因在於對缺失值(NA)的處理方式不同,在 SQLite 中若遇到文字時,會直接當作 0 處理。除此之外是否還有其他的因素,我也不確定,但我想大部分的問題都是因為原始資料不完整或是格式問題所造成的。
R 與 SQLite
有時候我們需要使用資料庫來管理資料,同時以 R 進行複雜的統計分析,這種狀況我們就可以將資料放進 SQL 資料庫之後,再從 R 中存取 SQL 資料庫的資料。
以 SQLite 資料庫來說,我們可以使用 R 的 RSQLite 套件來連接 SQLite 資料庫,使用前請先安裝:
install.packages("RSQLite")
安裝好之後,載入 RSQLite 套件:
library(RSQLite)
一開始必須先建立一個 SQLite 資料庫的連線:
# 建立 SQLite 資料庫連線
delay.db <- dbConnect(RSQLite::SQLite(), dbname = "AirlineDelay.sqlite3")
接著即可以 SQL 語法來查詢資料庫:
# 以 SQL 查詢資料庫
sql <- "SELECT Year, COUNT(*) FROM AirlineDelay GROUP BY Year;"
count <- dbGetQuery(delay.db, sql)
count
Year COUNT(*) 1 1987 1311826 2 1988 5202096 3 1989 5041200 4 1990 5270893 5 1991 5076925 6 1992 5092157 7 1993 5070501 8 1994 5180048 9 1995 5327435 10 1996 5351983 11 1997 5411843 12 1998 5384721 13 1999 5527884 14 2000 5683047 15 2001 5967780 16 2002 5271359 17 2003 6488540 18 2004 7129270 19 2005 7140596 20 2006 7141922 21 2007 7453215 22 2008 7009728
資料庫使用完之後,記得要將連線關閉:
# 關閉 RSQLite 資料庫連線
dbDisconnect(delay.db)
透過 RSQLite 套件,我們可以使用任何的 SQL 語法從資料庫取得想要的資料,再使用 R 做進一步的統計分析,這樣會比只使用 R 來管理資料更方便。
R 少量記憶體與巨量資料
透過資料庫來處理巨量資料是一個不錯的方式,但前提是必須熟悉 SQL 資料庫指令的語法,若對於 SQL 指令的使用不熟稔的話,使用上也不是很方便,這種狀況下就可以考慮改用 bigmemory 套件。
R 的 bigmemory 套件可以讓記憶體不夠大的電腦也可以處理巨量的資料,而其資料操作的方式就跟 R 基本的矩陣一樣,所以對於熟悉 R 語言的人可以立即上手使用。
由於 bigmemory 套件在處理資料時,必須將所有的資料轉成相同的類型,所以我們這裡先把文字的資料捨棄,只留下數值的欄位,再將所有的資料放進一個 CSV 檔案中。在 Linux 的 shell 中執行以下指令:
# 將所有資料放進一個 CSV 檔案中,並只留下數值的欄位
FIELDS=1,2,3,4,5,6,7,8,12,13,14,15,16,19,20,21,22,24,25,26,27,28,29
cut -d, -f $FIELDS 1987.csv > AirlineDataNum.csv
for year in {1988..2008}
do
tail -n+2 $year.csv | cut -d, -f $FIELDS >> AirlineDataNum.csv
done
另一種做法是將那些文字的欄位改為數值的代號,這樣就可以直接透過 bigmemory 來處理。
接著安裝 bigmemory 套件,並載入之:
install.packages("bigmemory")
library(bigmemory)
直接將所有的航班延誤資料載入至 R 中,載入後會得到一個 big.matrix 物件:
# 載入所有航班延誤資料
airline.all <- read.big.matrix("AirlineDataNum.csv",
header = TRUE,
backingfile = "airline.bin",
descriptorfile = "airline.desc",
type = "integer")
這裡的 backingfile 參數是指定後端快取檔案的名稱,而 descriptorfile 參數是指定 descriptor 檔案的名稱(可用來快速建立 big.matrix 物件),type 參數是指定資料類型。
載入後,查看矩陣的大小:
# 查看矩陣大小
dim(airline.all)
[1] 123534969 24
這個 big.matrix 的操作方式就跟一般的矩陣相同,我們可用索引查看部分資料:
# 查看部分資料
airline.all[1:5,1:7]
Year Month DayofMonth DayOfWeek DepTime CRSDepTime ArrTime [1,] 1987 10 14 3 741 730 912 [2,] 1987 10 15 4 729 730 903 [3,] 1987 10 17 6 741 730 918 [4,] 1987 10 18 7 729 730 847 [5,] 1987 10 19 1 749 730 922
計算每一年的資料筆數:
# 計算每一年的資料筆數
for(year in 1987:2008) {
cat(year, "年:", sum(airline.all[,"Year"] == year), "\n")
}
1987 年: 1311826 1988 年: 5202096 1989 年: 5041200 1990 年: 5270893 1991 年: 5076925 1992 年: 5092157 1993 年: 5070501 1994 年: 5180048 1995 年: 5327435 1996 年: 5351983 1997 年: 5411843 1998 年: 5384721 1999 年: 5527884 2000 年: 5683047 2001 年: 5967780 2002 年: 5271359 2003 年: 6488540 2004 年: 7129270 2005 年: 7140596 2006 年: 7141922 2007 年: 7453215 2008 年: 7009728
計算一週當中每一天的資料總筆數:
# 計算一週當中每一天的資料總筆數
for(day in 1:7) {
cat(day, ":", sum(airline.all[,"DayOfWeek"] == day), "\n")
}
1 : 18136111 2 : 18061938 3 : 18103222 4 : 18083800 5 : 18091338 6 : 15915382 7 : 17143178
建立一個 big.matrix 物件需要等待比較久的時間,在建立好 big.matrix 物件之後,如果後續想要再次建立這個 big.matrix 物件時,就可以使用先前建立好的 descriptor 檔案,這樣就可以不用再等那麼久:
# 使用 descriptor 檔案建立 big.matrix 物件
airline.all.2 <- attach.big.matrix("airline.desc")
R 平行運算
上面我們使用迴圈的方式來計算各種統計數值,而各個統計數值之間其實是獨立的(例如週一的資料筆數不會跟週二的資料筆數有關),所以我們可以把迴圈內的計算分散至多個 CPU 核心,加速計算。
R 的 parallel 套件是一個內建的平行計算套件,我們可以用它來加速上面的迴圈計算。
若要將程式平行化,第一步就是要把程式以 lapply 的方式改寫,以計算一週當中每一天的資料總筆數為例,可以改成這樣:
# 計算一週當中每一天的資料總筆數
lapply(1:7, function(day) sum(airline.all[,"DayOfWeek"] == day))
[[1]] [1] 18136111 [[2]] [1] 18061938 [[3]] [1] 18103222 [[4]] [1] 18083800 [[5]] [1] 18091338 [[6]] [1] 15915382 [[7]] [1] 17143178
也可以使用 sapply,以這個例子來說,這樣會比較方便:
# 計算一週當中每一天的資料總筆數
sapply(1:7, function(day) sum(airline.all[,"DayOfWeek"] == day))
[1] 18136111 18061938 18103222 18083800 18091338 15915382 17143178
確認結果正確之後,接著載入 parallel 套件:
library(parallel)
接著使用 makeForkCluster 建立 cluster,建立時要指定欲使用的 CPU 核心數,這裡我們用 detectCores 自動偵測系統的 CPU 核心數,使用所有的核心:
# 偵測 CPU 核心數
cores <- detectCores()
# 建立 cluster
cl <- makeForkCluster(cores)
接著將上面寫好的 lapply 或 sapply 改為 parLapply 或 parSapply,即可將工作分散至多個 CPU 核心進行平行計算:
# 計算一週當中每一天的資料總筆數
parSapply(cl, 1:7, function(day) sum(airline.all[,"DayOfWeek"] == day))
[1] 18136111 18061938 18103222 18083800 18091338 15915382 17143178
正常來說,計算的結果會相同,但是速度卻快很多。
計算完畢之後,記得要關閉 cluster:
# 關閉 cluster
stopCluster(cl)
R 巨量資料回歸分析
若在資料量很大的情況下想做迴歸分析,沒有辦法以普通的 lm 來處理,必須改用 biglm 套件,它的原理是每次只拿部分的資料作計算,逐步更新模型參數。
如果想要拿 big.matrix 的資料放進 biglm 做迴歸,可以用 biganalytics 這個包裝套件,它可以簡化資料轉換的流程,使用起來更簡單。
首先安裝 biganalytics 套件:
install.packages("biganalytics")
library(biganalytics)
接著就可以使用 biglm.big.matrix 進行迴歸分析了:
# 迴歸分析
blm <- biglm.big.matrix(ArrDelay ~ Distance, data = airline.all)
最後輸出配適的迴歸模型:
# 輸出結果
summary(blm)
Large data regression model: biglm(formula = formula, data = data, ...)
Sample size = 120748239
Coef (95% CI) SE p
(Intercept) 6.9707 6.9616 6.9798 0.0045 0
Distance 0.0001 0.0001 0.0001 0.0000 0練習題
- 請使用 R 的
parallel平行計算套件,解決以下問題:- 哪一年的班機誤點情況最嚴重?
- 一週當中,星期幾的班機誤點情況最嚴重?
- 以迴歸分析檢查
ArrDelay與DepDelay兩者之間是否有關係?
