Re: [問題] read.table 多個sep 遺失值miss

作者: celestialgod (天)   2016-05-01 02:16:08
※ 引述《f496328mm (為什麼會流淚)》之銘言:
: 問題一
: 我要讀的是筆記本txt檔
: 檔案太大無法先用excel處理
: 我的分隔符號有多個 請問要怎麼寫??
: 我的code
: read.table("d:\\xxx.txt" ,sep=";", fill=T, quote="")
: 我想要用 ; 和 空格 當作分隔符號 未來可能再增加
假設你資料長這樣,可以先用regex把分隔符號抓出來,再用fread處理:
sam 18; boy
paul; 20 boy
charlotte; 21; girl
christy 17 girl
好讀版:http://pastebin.com/QjwNiyNK
備註很長,不想看就轉下一頁吧,無所謂的murmur XD
(備註:library後面註解是該套件會用到的函數,我盡量減少使用奇怪的函數,
%>>%部分,我這裡用法幾乎都跟%>%一樣,去看magrittr介紹即可,
有興趣了解更多,再到作者網站看,%>>%多了不少好用的功能,
data.table主要是用fread,data.table跟setnames都可以分別用
data.frame, `names<-`這兩個函數取代,rlply可以用replicate取代
mutate也可以用base的transform取代,str_c跟paste一樣,
str_replace_all只是把gsub原本放字串的位置移到第一個,方便pipe,
還有其他問題或是不會取代函數的話,再推文或是回文發問吧,
至於為什麼要用其他函數,其函數有其他好處加上習慣,甚至只是因為style問題,
就不在程式中做取代了)
code:
library(data.table) # fread, data.table, setnames
library(pipeR) # %>>%
library(plyr) # rlply
library(dplyr) # mutate
library(stringr) # str_replace_all, str_c
readLines(textConnection('sam 18; boy
paul; 20 boy
charlotte; 21; girl
christy 17 girl')) %>>%
str_replace_all("([a-zA-Z0-9]);? ", "\\1,") %>>%
# str_replace_all比gsub適合用在pipeR
str_c(collapse = "\n") %>>% fread %>>% # str_c = paste
setnames(c("name", "age", "sex")) %>>%
mutate(age = as.integer(age))
# name age sex
# 1 sam 18 boy
# 2 paul 20 boy
# 3 charlotte 21 girl
# 4 christy 17 girl
用兩百萬個row測試看看:
# data generation
textData <- raply(5e5, 'sam 18; boy
paul; 20 boy
charlotte; 21; girl
christy 17 girl') %>>% str_c(collapse = "\n")
library(microbenchmark) # microbenchmark
microbenchmark(test = textData %>>%
str_replace_all("([a-zA-Z0-9]);? ", "\\1,") %>>%
str_c(collapse = "\n") %>>% fread %>>%
setnames(c("name", "age", "sex")) %>>%
mutate(age = as.integer(age)), times = 10L)
# Unit: seconds
# expr min lq mean median uq max neval
# test 4.489137 4.520529 4.528179 4.529275 4.543055 4.557189 10
平均一次4.5秒左右,全距也很小,所以兩百萬列不是問題
: ==========================================================
: 問題二
: 我的資料中 有些地方沒有值 所以當初在存的時候就直接忽略 連空白都沒留
: 像這樣:
: sam;16;boy; 2015:00:09:59
: green;18;gril
: paul;20; 2015:00:09:59
: 第一行是name
: 第二行是age
: 第三行是性別
: 但是paul沒有記錄到 所以直接記錄到第四行的time
: green的time也沒記錄到
: 想問有沒有什麼方法解決 我目前只想到比較笨的方法
: 給它特定範圍去判斷 像性別不是boy就是gril 出現其他就給他NA
: 還有
: 這樣讀資料也會因為每列資料col都不一樣 有的時候會出現問題
: 是可以讀成文字再去慢慢拆開 不過有點笨就是了
: 最後想問如果讀資料量上百萬筆
: 還是用read.table嗎?
: 有沒有比較好的函數專門處理large data?
: 謝謝
一樣用regex處理即可,速度也是相當快:
pattern <- str_c("([a-z]*);?\\s*", "(\\d*)?;?\\s*", "(boy|girl)?;?\\s*",
"(\\d{4}:\\d{2}:\\d{2}:\\d{2})?")
# 第一個是第一欄位,第二個是第二欄位,依此類推
readLines(textConnection('sam;16;boy; 2015:00:09:59
green;18;girl;
paul;20; 2015:00:09:59
charlotte; 21;')) %>>% str_replace_all(pattern, "\\1, \\2, \\3, \\4") %>>%
str_replace_all(", , , ", "") %>>% str_c(collapse = "\n") %>>%
fread(na.string="") %>>% setnames(c("name", "age", "sex", "time")) %>>%
mutate(age = as.integer(age))
# name age sex time
# 1 sam 16 boy 2015:00:09:59
# 2 green 18 girl <NA>
# 3 paul 20 <NA> 2015:00:09:59
# 4 charlotte 21 <NA> <NA>
# 這裡要為什麼要取代", , , ",我暫時想不出來為什麼
# 這裡不知道為什麼經過regex後,每一列會多出三個逗號,讓我匪夷所思QQ
# 用兩百萬個row測試看看:
# data generation
textData <- raply(5e5, 'sam;16;boy; 2015:00:09:59
green;18;girl;
paul;20; 2015:00:09:59
charlotte; 21;') %>>% str_c(collapse = "\n")
library(microbenchmark)
microbenchmark(test = readLines(textConnection(textData)) %>>%
str_replace_all(pattern, "\\1, \\2, \\3, \\4") %>>%
str_replace_all(", , , ", "") %>>% str_c(collapse = "\n") %>>%
fread(na.string="") %>>%
setnames(c("name", "age", "sex", "time")) %>>%
mutate(age = as.integer(age)), times = 10L)
# Unit: seconds
# expr min lq mean median uq max neval
# test 10.93214 10.9493 10.9683 10.96072 10.98294 11.04314 10
平均一次11秒左右,全距也很小,所以兩百萬列不是問題
最後murmur,這個資料真的長得很醜,我花了一小時才把這篇打完
還在測試不用regular expression的方法,能多快
發現讀一次檔案還是要80秒,實在太慢,最後就不PO上來了
這裡推薦一個網站學regex: http://regexone.com/
題外話:這一篇文章值 185 Ptt幣 XDD
作者: f496328mm (為什麼會流淚)   2016-05-01 10:58:00
感謝!這應該算是高階寫法吧,又學到新東西啦

Links booklink

Contact Us: admin [ a t ] ucptt.com