2011-12-27 36 views
-2

(編輯strtime()logTime Description該條轉換:問題之一是這裏的規模,一行即什麼工作將炸燬/崩潰R於20萬* 50數據幀例如。 ,strptime必須採用逐列,不按行,避免掛。 我在找工作代碼解決方案,你居然跑20萬* 50,包括您的測量運行,而不只是隨便「這是很容易」的言論。這是很容易得到的運行時間> 12個小時,如果你選擇了錯誤的Fn鍵。接下來,我還要求你讓我零時間調整代碼快,工作還不算完,直到這樣做了。沒有人嘗試,到目前爲止。)如何向量化,加快對數據框


我想矢量化和加速以下多步數時間轉換,以毫秒的精度,涉及大量數據幀上轉換strtime()到單個數字,隨後通過減法,然後log()(200,000行* 300的cols;其他(非時間)列省略)。 下面的代碼。 除了使其向量化和快速,一個額外的問題是我不知道如何最好地在每一步例如代表(更高維)的中間值作爲來自strtime,矩陣,矢量的列表)。我已經嘗試過apply,sapply,lapply,vapply,ddply::maply(),...但中間格式(S)的不兼容性保持搞亂了我...

每行有50列time1..time50(CHR,格式=「HH:MM:SS。 sss「)表示時間爲毫秒分辨率的字符串。我需要毫秒級的準確度。 在每行內,列time1..time50處於非遞減順序,並且我想將它們轉換爲時間之前的時間日誌50。 FN parse_hhmmsecms()轉化是在底部,需要認真矢量化,加快推進,你可以看到替代版本註釋。我想通爲止:strtime()比(倍數)substr()來電快,我後來不知怎的轉換爲三個數字(hh,mm,sec.ms)列表,然後轉換成矢量假設下一個步驟應該是矢量乘用%*% c(3600,60,1)轉換爲數字秒。 這裏是我爲每一行做的僞代碼,以及每個時間字符串;完整的代碼是在底部:

for each row in dataframe { # vectorize this, loop_apply(), or whatever... 
#for each time-column index i ('time1'..'time50') { # vectorize this... 
hhmmsecms_50 <- parse_hhmmsecms(xx$time50[i]) 
# Main computation 
xx[i,Clogtime] <- -10*log10(1000*(hhmmsecms_50 - parse_hhmmsecms(xx[i,Ctime]))) 
# Minor task: fix up all the 'zero-time' events to be evenly spaced between -3..0 
#} 
} 

所以有五個子問題涉及:

  1. 如何向量化處理以strtime()返回列表?因爲它返回3個項目的列表,當傳遞2D數據框或1D行時間字符串時,我們將獲得3D或2D中間對象。 (我們內部是否使用list-of-list?列表矩陣?列表陣列?)
  2. 如何矢量化整個函數parse_hhmmsecms()
  3. 然後做減法和日誌
  4. 矢量化零時間修正代碼以及(這是目前最慢的部分由遠)
  5. 如何加快步驟1 ... 4?下面使用10分例子列

代碼片段time41..50(如果你想有一個更大的樣本使用random_hhmmsecms()

我盡力跟着these recommendations,這是可複製的,我可以得到它六小時的工作:

# Each of 200,000 rows has 50 time strings (chr) like this...  
xx <- structure(list(time41 = c("08:00:41.465", "08:00:50.573", "08:00:50.684" 
), time42 = c("08:00:41.465", "08:00:50.573", "08:00:50.759"), 
    time43 = c("08:00:41.465", "08:00:50.573", "08:00:50.759" 
    ), time44 = c("08:00:41.465", "08:00:50.664", "08:00:50.759" 
    ), time45 = c("08:00:41.465", "08:00:50.684", "08:00:50.759" 
    ), time46 = c("08:00:42.496", "08:00:50.684", "08:00:50.759" 
    ), time47 = c("08:00:42.564", "08:00:50.759", "08:00:51.373" 
    ), time48 = c("08:00:48.370", "08:00:50.759", "08:00:51.373" 
    ), time49 = c("08:00:50.573", "08:00:50.759", "08:00:54.452" 
    ), time50 = c("08:00:50.573", "08:00:50.759", "08:00:54.452" 
    )), .Names = c("time41", "time42", "time43", "time44", "time45", 
"time46", "time47", "time48", "time49", "time50"), row.names = 3:5, class = "data.frame") 

# Handle millisecond timing and time conversion 
options('digits.secs'=3) 

# Parse "HH:MM:SS.sss" timestring into (numeric) number of seconds (Very slow) 
parse_hhmmsecms <- function(t) { 
    as.numeric(substr(t,1,2))*3600 + as.numeric(substr(t,4,5))*60 + as.numeric(substr(t,7,12)) # WORKS, V SLOW 

    #c(3600,60,1) %*% sapply((strsplit(t[1,]$time1, ':')), as.numeric) # SLOW, NOT VECTOR 

    #as.vector(as.numeric(unlist(strsplit(t,':',fixed=TRUE)))) %*% c(3600,60,1) # WANT TO VECTORIZE THIS 
} 

random_hhmmsecms <- function(n=1, min=8*3600, max=16*3600) { 
# Generate n random hhmmsecms objects between min and max (8am:4pm) 
xx <- runif(n,min,max) 
ss <- xx %% 60 
mm <- (xx %/% 60) %% 60 
hh <- xx %/% 3600 
sprintf("%02d:%02d:%05.3f", hh,mm,ss) 
} 

xx$logtime45 <- xx$logtime44 <- xx$logtime43 <- xx$logtime42 <- xx$logtime41 <- NA 
xx$logtime50 <- xx$logtime49 <- xx$logtime48 <- xx$logtime47 <- xx$logtime46 <- NA 

# (we pass index vectors as the dataframe column ordering may change) 
Ctime <- which(colnames(xx)=='time41') : which(colnames(xx)=='time50') 
Clogtime <- which(colnames(xx)=='logtime41') : which(colnames(xx)=='logtime50') 
for (i in 40:nrow(xx)) { 
    #if (i%%100==0) { print(paste('... row',i)) } 

    hhmmsecms_50 <- parse_hhmmsecms(xx$time50[i]) 
    xx[i,Clogtime] <- -10*log10(1000*(hhmmsecms_50 - parse_hhmmsecms(xx[i,Ctime]))) 

    # Now fix up all the 'zero-time' events to be evenly spaced between -3..0 
    Czerotime.p <- which(xx[i,Clogtime]==Inf | xx[i,Clogtime]>-1e-9) 
    xx[i,Czerotime.p] <- seq(-3,0,length.out=length(Czerotime.p)) 
} 
+0

看看矢量化內置的strptime函數和相關的POSICct和POSIXlt類。您實際上可以將矢量應用於矢量並將其轉換爲數字。有許多內置時間處理功能。 – John 2011-12-27 21:29:57

+0

約翰,不,我在幾周前試過,*'as.POSIXlt()'*轉換放棄了毫秒(chron和zoo似乎不可用)。 – smci 2011-12-27 22:34:22

+0

我在第一次Google搜索嘗試中發現[this](http://stackoverflow.com/questions/2150138/how-to-parse-milliseconds-in-r)。 (事實上​​,這是第一個結果)。 – joran 2011-12-27 22:40:31

回答

2

您可能會過於複雜的事情。

與基類這 毫秒非常好(和適當的操作系統甚至微秒),但要注意

  1. 需要設置options("digits.secs"=7)(這是一個可以顯示的最大值)看到

    開始他們顯示

  2. 你需要額外的解析字符strptime

所有這些都在文檔中,以及在這裏的無數例子。

簡單的例子:

R> someTime <- ISOdatetime(2011, 12, 27, 2, 3, 4.567) 
R> someTime 
[1] "2011-12-27 02:03:04.567 CST" 
R> now <- Sys.time() 
R> now 
[1] "2011-12-27 16:48:20.247298 CST"  # microsecond display on Linux 
R> 
R> txt <- "2001-02-03 04:05:06.789123" 
R> strptime(txt, "%Y-%m-%d %H:%M:%OS") # note the %0S for sub-seconds 
[1] "2001-02-03 04:05:06.789123" 
R> 

和關鍵功能,如strptimeas.POSIXct都矢量化,你可以扔在他們整個列。

+0

謝謝,但數據集來作爲CSV,如果你在日期閱讀,並在colClasses做strptime我似乎記得巨大的內存爆炸。我會用切片重試它。第二個原因是不希望用假日期來存儲時間,例如, 「2001-02-03」是因爲我打印他們,比較他們(< > ==),操縱他們,由他們聚合,使用他們作爲圖形或直方圖標籤等。但是,我可以使用*'as.numeric(strptime( ...) - origin_date)'* – smci 2011-12-27 23:12:20

+0

你*可能*也許*應該*對'Date'和'POSIXct'類進行算術運算。如果你只有幾個小時:分鐘:秒,也許將它們追加到名義基準日期2001-01-01之類的東西上。記憶力的問題是衆所周知的,可悲的是似乎是我們必須爲'strptime'的普遍可用性付出代價。 – 2011-12-27 23:16:19

+0

零時間修正代碼現在是緩慢的部分,您是否也請解決這個問題?進行零時間修正行方式需要> 12小時。請將您的實際運行時間發佈在200,000 * 50數據幀或類似的地方。 – smci 2011-12-28 18:54:25