總結第一次自己寫R進行資料處理和練習實際使用正則表達式, 分享一些自己實際碰到問題的心得。
(還有非常非常多要改進的地方ΩДΩ。)
2008~2017年全臺一般空氣品質測站資料整理成openair套件可以用的格式。
windows version 1803 (10.0.17134) , R version 3.5.1 , RStudio version 1.1.453
utils , XML , magrittr , readr , xlsx , plyr , tidyr , lubridate
代表.zip的字串出現一次以上,
注意.本身為正則表達式的指令,需要兩個反斜線(\)以指定此符號而非使用此指令。
setwd("D:/r/taqmn/zip")
getwd()
zipfiles<-list.files(getwd(),"\\.zip{1,}",full.names =T)
dir.create("D:/r/taqmn/unzip")#解壓縮的原始檔案的資料夾
dir.create("D:/r/taqmn/raw")#輸出csv和xls檔案的資料夾
path.list<-lapply(zipfiles,function(i){
utils::unzip(i,exdir="D:/r/taqmn/unzip")
})
方法一(慢)
流程:使用lapply以刪除D:/r/taqmn/unzip下的ods,odt,doc和txt檔,再把剩下的csv和xls檔複製到raw資料夾。
用正則表達式篩出解壓縮後的檔名路徑(path.list)中不是csv或xls的檔案。
總共判別三個條件,使用或(|)連接,符合其中一個條件就取出字串,
皆設定條件字尾前方有任何字串(其實只是.*的意思)。
第一個條件:結尾不要是csv的。
第二個條件:結尾是doc的。
第三個條件:結尾是ods中,以三個字母出現的任意兩個字母的組合。
regexpr():判別字串是否符合正則表達式。
regmatches():取出符合正則表達式的字串。
perl=TRUE 是為了加快讀取正則表達式的運算速度
lapply(fname,file.remove):使用lapply把所有非csv和xls檔利用file.remove刪除。
file.copy(path.list[[i]],“D:/r/taqmn/raw”)
複製unzip資料夾剩下的檔案(csv和xls檔)到 D:/r/taqmn/raw。
#辨別檔名,以刪除doc,odt,ods,txt檔,而剩下csv和xls檔
lapply(1:length(path.list),function(i){
fname<-regmatches(path.list[[i]],regexpr(".*([^csv]{1}$)|.*([doc]$)|.*([ods]{2,}$)",path.list[[i]],perl=TRUE))
lapply(fname,file.remove)
file.copy(path.list[[i]],"D:/r/taqmn/raw")
})
方法二(快)
流程:使用lapply取得D:/r/taqmn/unzip下的csv和xls檔後,再複製到raw資料夾。
用正則表達式篩出解壓縮後的檔名路徑(path.list)中是csv或xls的檔案。
總共判別兩個條件,使用或(|)連接,符合其中一個條件就取出字串,
皆設定條件字尾前方有任何字串(其實只是.*的意思)。
第一個條件:結尾是csv的。
第二個條件:結尾是xls的。
regexpr():判別字串是否符合正則表達式。
regmatches():取出符合正則表達式的字串。
perl=TRUE 是為了加快讀取正則表達式的運算速度
#辨別檔名,只取得csv和xls檔
lapply(1:length(zipfiles),function(i){
fname<-regmatches(path.list[[i]],regexpr(".*(csv|xls){1}$",path.list[[i]],perl=TRUE))
# unzip的xls csv copy 到raw
file.copy(fname,"D:/r/taqmn/raw")
})
原因:中文檔名會造成一堆問題(套件讀不懂,讀取速度變慢…等)。
取出D:/r/taqmn/raw下的所有檔名,放到raw.filename。
取出raw.filename檔名中年 , 站 , .字串的位置。
原因:例如要把97年大里站_20090301.xls改為西元年+英譯地名四字縮寫+副檔名。
取出檔名民國年份字串轉為數字,加上1911後,轉為字串。
raw.filename<-list.files("D:/r/taqmn/raw")
year.place<-regexpr("年",raw.filename)
site.place<-regexpr("站",raw.filename)
fexten.place<-regexpr("\\.",raw.filename)
distinct.year<-sapply(1:length(raw.filename),function(i){as.character(1911+as.numeric(substring(raw.filename[i],1,year.place[i]-1)))})
1.由opendata空氣品質監測站基本資料網址以二進位模式下載xml檔
(中文地名和英文翻##譯,緯度等等資料),放入D:/r/taqmn/zip/,取名為distinct.xml。
2.讀取xml檔,轉為dataframed而放入distinct1。
3.取得distinct1中,中文地名(dc)與英譯地名(da)。
- 字串轉為向量,原英文字串縮寫為四個字母,並設定both.sides避免相同縮寫產生。
4.取得D:/r/taqmn/raw下的所有檔案名中地區名稱EX:97年大里站_20090301.xls中的大里。
5.匯出逗點分隔csv檔,check.csv(地區中文,地區英文,地區英文簡稱)和distinct.csv(空氣品質監測站基本資料)
download.file("http://opendata.epa.gov.tw/ws/Data/AQXSite/?$format=xml","D:/r/taqmn/zip/distinct.xml",mode="wb")
library("XML")
distinct<- xmlParse("D:/r/taqmn/zip/distinct.xml")
distinct1<-xmlToDataFrame(nodes=getNodeSet(distinct,"//Data"))
library("magrittr")
dc<-unlist(distinct1[1], use.names=FALSE) %>% as.vector()
da<-unlist(distinct1[2], use.names=FALSE) %>% as.vector()
dabb<-toupper(abbreviate(da,4,method="both.sides"))%>% unlist() %>% as.vector()
files.c<-sapply(1:length(raw.filename),function(x){
substring(raw.filename[x],year.place[x]+1,site.place[x]-1)})
check.df<-data.frame(dc,da,dabb)
colnames(check.df)<-c("地區中文","地區英文","地區英文簡稱")
#.....匯出以儲存檔案紀錄.......
write.table(check.df,file="check.csv",sep=",",row.names =FALSE)
write.table(distinct1,file="distinct.csv",sep=",",row.names =FALSE)
1.比較檔名和空氣品質監測站基本資料中的中文地區名稱,如果為NA(代表無對應名稱),則顯示檔名中的中文地區名稱。
2.刪除阿里山或崇倫或泰山的檔案。
3.進行檔名除錯:台改臺。
4.取出檔名中的副檔名。
5.取得舊檔名的完整路徑。
6.結合西元年和大寫英文縮寫地名檔名為新檔名的完整路徑。
7.重新命名檔名。
na.name<-data.frame(ifelse(is.na(match(files.c,dc)),files.c ,""))
delet.filename<-paste("D:/r/taqmn/raw",list.files("D:/r/taqmn/raw","阿里山|崇倫|泰山"),sep="/")
file.remove(delet.filename)
files.csub<-gsub("台","臺",files.c)
file.extension<-sapply(1:length(raw.filename),function(x){substring(raw.filename[x],fexten.place[x],fexten.place[x]+4)})
old.filename<-paste0("D:/r/taqmn/raw/",raw.filename)
new.filename<-paste0("D:/r/taqmn/raw/",distinct.year,dabb[match(files.csub,dc)],file.extension)
file.rename(old.filename,new.filename)
由於讀xls檔的xlsx套件是使用java撰寫,而xlsx::read.xlsx2一次讀取好幾個xls檔時,需要提高jvm的記憶體,
不然無法使用套件(須Restart R 後設定)。
注意取縮寫四個字母名稱的函數設定為both.sides,可能因四字縮寫名稱相同而出現五個字的英文縮寫,
所以需要加上.符號於取出的字母縮寫之後,確定英文縮寫長度,不然使用正則表達式時,以為只選擇一個地區但取出兩個地區檔案就慘了。
注意2008年檔案的日期一定需要以Date屬性讀入,不然會出現神秘的數字。
其他年份檔案之所有欄位皆以字串屬性讀入,後續欄位資料處理會比較方便。
options(java.parameters = "-Xmx1024m")
choose.files<-function(choose.year,choose.distinct){
choose.year<-as.character(choose.year)
distinct.read<-readr::read_csv("D:/r/taqmn/zip/check.csv",col_types = "ccc",locale=readr::locale(encoding="BIG5"))
distinct.read1<-unlist(distinct.read[1])
choose.distinct<-as.vector(choose.distinct)
distinct<-distinct.read[match(choose.distinct,distinct.read1),3] %>% unlist()
distinct<-paste0(choose.year,distinct,"\\.")
file.list<-list.files("D:/r/taqmn/raw",distinct, full.names = TRUE)
if (substring(file.list,16,19)=="2008"){
coltype<-c("Date", rep("character",26))
}else{
coltype<-c(rep("character",27))
}
if (grepl("xls",file.list)){
lapply(1:length(file.list),function(i){
cat(file.list[i],"\n")
xlsx::read.xlsx2(file.list[i],1,colClasses =coltype )
})
}else{
col.type<-"ccccccccccccccccccccccccccc"
lapply(1:length(file.list),function(i){
cat(file.list[i],"\n")
readr::read_csv(file.list[[i]],col_types=col.type,locale=readr::locale(encoding="BIG5"))})
}
}
1.list轉為data.frame。
2.將所有欄位重新命名為英文與統一時間為0~23點。
3.將時間欄位轉置為橫列。
4.合併日期與時間。
5.轉置item(物質)為欄位,並將英文名稱轉為小寫。
6.將rainfall中NR值轉為零。
7.將物質欄位由文字轉為數字。
8.日期欄位由字串轉為Date屬性。
9.取代欄位名稱pm2.5為pm25,wind_direc為wd,wind_speed為ws。
10.最終傳回轉置完成的dataframe。
data.arrange<-function(yfile){
yfile.df<-plyr::ldply(yfile,data.frame)
col.newname<-c("date","site","item",paste(0:23,"00",sep=":"))
colnames(yfile.df)<-col.newname
yfile.tran<-tidyr::gather(yfile.df,paste(0:23,"00",sep=":"),key="time",value="conc")
yfile.tran$date<-paste(yfile.tran$date,yfile.tran$time)
yfile.spread<-tidyr::spread(yfile.tran[-c(4)],item,conc)
colnames(yfile.spread) %<>% tolower()
yfile.spread$rainfall[yfile.spread$rainfall=="NR"]<-0
yfile.spread[,3:length(colnames(yfile.spread))]<-sapply(yfile.spread[,3:length(colnames(yfile.spread))],as.numeric)
yfile.spread$date<-lubridate::ymd_hm(yfile.spread$date,tz=Sys.timezone())
colnames(yfile.spread)[grep("pm2|wind_",colnames(yfile.spread))]<- c("pm25","wd","ws")
return(yfile.spread)
}
want.area<-c("大里","西屯","沙鹿","忠明","豐原")
library("magrittr")
file.raw<-lapply(1:length(want.area),function(i){choose.files(2008,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2008DALI.xls
## D:/r/taqmn/raw/2008XITN.xls
## D:/r/taqmn/raw/2008SHAL.xls
## D:/r/taqmn/raw/2008ZHNG.xls
## D:/r/taqmn/raw/2008FNGY.xls
file.raw1<-lapply(1:length(want.area),function(i){choose.files(2009,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2009DALI.csv
## D:/r/taqmn/raw/2009XITN.csv
## D:/r/taqmn/raw/2009SHAL.csv
## D:/r/taqmn/raw/2009ZHNG.csv
## D:/r/taqmn/raw/2009FNGY.csv
file.raw2<-lapply(1:length(want.area),function(i){choose.files(2010,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2010DALI.csv
## D:/r/taqmn/raw/2010XITN.csv
## D:/r/taqmn/raw/2010SHAL.csv
## D:/r/taqmn/raw/2010ZHNG.csv
## D:/r/taqmn/raw/2010FNGY.csv
file.raw3<-lapply(1:length(want.area),function(i){choose.files(2011,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2011DALI.csv
## D:/r/taqmn/raw/2011XITN.csv
## D:/r/taqmn/raw/2011SHAL.csv
## D:/r/taqmn/raw/2011ZHNG.csv
## D:/r/taqmn/raw/2011FNGY.csv
file.raw4<-lapply(1:length(want.area),function(i){choose.files(2012,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2012DALI.xls
## D:/r/taqmn/raw/2012XITN.xls
## D:/r/taqmn/raw/2012SHAL.xls
## D:/r/taqmn/raw/2012ZHNG.xls
## D:/r/taqmn/raw/2012FNGY.xls
file.raw5<-lapply(1:length(want.area),function(i){choose.files(2013,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2013DALI.xls
## D:/r/taqmn/raw/2013XITN.xls
## D:/r/taqmn/raw/2013SHAL.xls
## D:/r/taqmn/raw/2013ZHNG.xls
## D:/r/taqmn/raw/2013FNGY.xls
file.raw6<-lapply(1:length(want.area),function(i){choose.files(2014,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2014DALI.xls
## D:/r/taqmn/raw/2014XITN.xls
## D:/r/taqmn/raw/2014SHAL.xls
## D:/r/taqmn/raw/2014ZHNG.xls
## D:/r/taqmn/raw/2014FNGY.xls
file.raw7<-lapply(1:length(want.area),function(i){choose.files(2015,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2015DALI.xls
## D:/r/taqmn/raw/2015XITN.xls
## D:/r/taqmn/raw/2015SHAL.xls
## D:/r/taqmn/raw/2015ZHNG.xls
## D:/r/taqmn/raw/2015FNGY.xls
file.raw8<-lapply(1:length(want.area),function(i){choose.files(2016,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2016DALI.xls
## D:/r/taqmn/raw/2016XITN.xls
## D:/r/taqmn/raw/2016SHAL.xls
## D:/r/taqmn/raw/2016ZHNG.xls
## D:/r/taqmn/raw/2016FNGY.xls
file.raw9<-lapply(1:length(want.area),function(i){choose.files(2017,choose.distinct=want.area[i])})
## D:/r/taqmn/raw/2017DALI.xls
## D:/r/taqmn/raw/2017XITN.xls
## D:/r/taqmn/raw/2017SHAL.xls
## D:/r/taqmn/raw/2017ZHNG.xls
## D:/r/taqmn/raw/2017FNGY.xls
mydata9<-data.arrange(file.raw9)
mydata8<-data.arrange(file.raw8)
mydata7<-data.arrange(file.raw7)
mydata6<-data.arrange(file.raw6)
mydata5<-data.arrange(file.raw5)
mydata4<-data.arrange(file.raw4)
mydata3<-data.arrange(file.raw3)
mydata2<-data.arrange(file.raw2)
mydata1<-data.arrange(file.raw1)
mydata<-data.arrange(file.raw)
mydata<-plyr::rbind.fill(mydata,mydata1,mydata2,mydata3,mydata4,mydata5,mydata6,mydata7,mydata8,mydata9)
save(mydata,file="mydata.RData")