2013-12-18 37 views
2

我有一些列固定寬度的天氣數據,但長度取決於變量(見下面,來自GHCN的數據,http://www1.ncdc.noaa.gov/pub/data/ghcn/daily/readme.txt)。有沒有更快的方法將字符串拆分成給定長度的子字符串?

我想將它們拆分成data.frame,並在@GSee(How to split a string into substrings of a given length?)的建議之後編寫了一些代碼。但是,處理6000行花了大約4.3秒。

有沒有更快的方法來處理這個數據集?

感謝您的任何建議。 WITH阿南達Mahto評論

temp <- readLines(textConnection("NO000050550193801TMAX 53 I 51 I 10 I 22 I 56 I 31 I 30 I 24 I 38 I 25 I 2 I 32 I 75 I 71 I 98 I 96 I 57 I 55 I 54 I 60 I 91 I 75 I 94 I 82 I 89 I 46 I 26 I 68 I 62 I 46 I 37 I 
NO000050550193801TMIN 25 I -6 I -27 I 0 I 3 I -14 I -8 I 11 I 10 I -11 I -30 I -23 I 22 I 38 I 47 I 33 I 13 I 5 I 10 I 29 I 42 I 45 I 51 I 44 I 35 I 5 I -16 I -20 I 5 I 2 I 5 I 
NO000050550193802TMAX 69 I 58 I 71 I 90 I 77 I 70 I 56 I 46 I 58 I 32 I 32 I 22 I 25 I 30 I 29 I 29 I 34 I 88 I 58 I 50 I 45 I 62 I 38 I 40 I 59 I 112 I 92 I 77 I-9999 -9999 -9999 
NO000050550193802TMIN 11 I 26 I 16 I 35 I 44 I 21 I 19 I 22 I 20 I 6 I 6 I -16 I -22 I -39 I -28 I -35 I -33 I -21 I -13 I 15 I 26 I 17 I -1 I 9 I 18 I 38 I 58 I 28 I-9999 -9999 -9999 
NO000050550193803TMAX 81 I 84 I 89 I 86 I 86 I 74 I 54 I 74 I 83 I 64 I 75 I 77 I 66 I 91 I 82 I 84 I 89 I 84 I 94 I 85 I 82 I 89 I 74 I 84 I 81 I 58 I 72 I 58 I 86 I 84 I 89 I 
NO000050550193803TMIN 31 I 25 I 29 I 45 I 61 I 20 I 9 I 8 I 38 I 31 I 9 I 39 I 27 I 56 I 48 I 65 I 45 I 54 I 46 I 42 I 43 I 36 I 56 I 61 I 15 I -2 I -11 I -2 I 12 I 30 I 24 I")) 

temp <- rep(temp, 1000) 
system.time({ 

out <- strsplit(temp, '') 
out <- as.matrix(do.call(rbind, out)) 
pos_matrix <- matrix(c(12, 16, 18, seq(0, 30) * 8 + 22, 
    15, 17, 21, seq(0, 30) * 8 + 26), ncol = 2) 
out <- apply(out, 1, function(x) 
    { 
     apply(pos_matrix, 1, function(y) 
      paste(x[y[1]:y[2]], collapse = '')) 
    }) 
}) 

user system elapsed 
4.46 0.01 4.52 

編輯:

system.time({ 
pos_matrix <- matrix(c(12, 16, 18, seq(0, 30) * 8 + 22, 
    15, 17, 21, seq(0, 30) * 8 + 26), ncol = 2) 
pos_matrix <- lapply(seq(1, nrow(pos_matrix)), function(x) 
    { 
     sprintf('substr(V1, %s, %s) f%s', 
      pos_matrix[x,1], pos_matrix[x,2], x) 
    }) 
pos_matrix <- paste(pos_matrix, collapse = ', ') 
out <- data.frame(V1 = temp) 

out <- sqldf(sprintf('select %s from out', pos_matrix)) 
}) 

user system elapsed 
0.4  0.0  0.4 

WITH jlhoward建議編輯:

system.time({ 
pos_matrix <- matrix(c(12, 16, 18, seq(0, 30) * 8 + 22, 
    15, 17, 21, seq(0, 30) * 8 + 26), ncol = 2) 
out <- apply(pos_matrix, 1, function(x) 
    { 
     substr(temp, x[1], x[2]) 
    }) 
}) 
user system elapsed 
0.04 0.00 0.04 
+1

按照[示例6f here](http://code.google.com/p/sqldf/)中的說明使用'sqldf'和'substr'? – A5C1D2H2I1M1N2O1R2T1

+0

sqldf和substr要快得多。相同的數據集只需要0.4秒。你的男人將你的評論添加到答案中,然後我可以接受它。 – Bangyou

回答

2

分析您的代碼(?Rprof)顯示2/3的執行時間花費在paste(...),這並不令人驚訝。它看起來像是將輸入分解爲單個字符,然後根據pos_matrix(...)重新組合它們。使用具有起始位置和長度的矩陣的substr(...)可能更有效。

編輯:添加代碼來實現上述

vec <- as.vector(temp) 
pos_matrix <- matrix(c(12, 16, 18, seq(0, 30) * 8 + 22, 
         15, 17, 21, seq(0, 30) * 8 + 26), ncol = 2) 
pos <- t(pos_matrix) 
system.time(
out <- do.call(rbind,list(apply(pos,2,function(x){substr(vec,x[1],x[2])}))) 
) 
# user system elapsed 
# 0.09 0.00 0.09 
+0

感謝您的建議。相同的數據集只需要0.4秒,而與sqldf的速度相似(但不需要加載sqldf軟件包)。 – Bangyou

+0

很高興爲你效勞。我已經添加了上面的代碼,但看起來你已經明白了。 – jlhoward

1

有一個固定寬度在utils包讀取功能(默認加載):

m <- matrix(c(12, 16, 18, seq(0, 30) * 8 + 22, 
    15, 17, 21, seq(0, 30) * 8 + 26), ncol = 2) 
read.fwf(textConnection(temp), c(11,    # which you are apparently ignoring 
           m[,2]-m[,1]+1) ) 

但是對於至少我有6000個這樣的記錄需要9秒。

0

scan建議 - 這與文件或連接工作。它可以修改代碼以上面給出更方便地與temp工作:

writeLines(temp, "temp.txt") 
scan("temp.txt", what="")) 
# and now convert it to a matrix of appropriate size 

不知道這是不是基於sqldf的解決方案更快,但它看起來更直接給我。

[[備註]]您好,您問過「給定長度的子串」,所以技術上我的答案是關於其他的東西。但它看起來像這個例子中的文件可能實際上有幫助。

相關問題