2017-08-14 63 views
1

很多人似乎有這個問題,但我無法找到滿意的答案。如果你放縱我,我想確定明白髮生了什麼如果功能在dplyr :: mutate:條件長度> 1

我在數據框中有各種格式的日期(也是一個常見問題),所以我建立了一個小函數來處理它:

dateHandler <- function(inputString){ 
    if(grepl("-",inputString)==T){ 
    lubridate::dmy(inputString, tz="GMT") 
    }else{ 
    as.POSIXct(as.numeric(inputString)*60*60*24, origin="1899-12-30", tz="GMT") 
    } 
} 

當使用它一個元素,它工作正常:

myExample <-c("18-Mar-11","42433") 

> dateHandler(myExample[1]) 
[1] "2011-03-18 GMT" 
> dateHandler(myExample[2]) 
[1] "2016-03-04 GMT" 

但是使用上一整列,當它不工作:

myDf <- as.data.frame(myExample) 
> myDf <- myDf %>% 
+ dplyr::mutate(dateClean=dateHandler(myExample)) 
Warning messages: 
1: In if (grepl("-", inputString) == T) { : 
    the condition has length > 1 and only the first element will be used 
2: 1 failed to parse. 

從論壇上閱讀,我目前的理解是,R將具有myDf $ myExample所有元素的向量傳遞給該函數,該函數不是爲了處理長度大於1的向量而構建的。如果這是正確的,下一步就是從那裏理解要做什麼。許多人建議使用ifelse而不是if,但我不明白這將如何幫助我。另外我讀了ifelse返回與輸入格式相同格式的東西,在這種情況下這對我不起作用。

非常感謝您在第10000次回答這個問題。

Nicolas

回答

1

你有兩種選擇,從哪裏去。一種是使用lapply將當前函數應用於列表。如:

myDf$dateClean <- lapply(myDf$myExample, function(x) dateHandler(x))

另一個選項是構建被設計爲採取一個向量作爲輸入,而不是單個數據點的矢量的功能。下面是一個簡單的例子:

dateHandlerVectorized <- function(inputVector){ 

    output <- rep(as.POSIXct("1/1/11"), length(inputVector)) 
    UseLuridate <- grepl("-", inputVector) 
    output[UseLuridate] <- lubridate::dmy(inputVector[UseLuridate], tz="GMT") 
    output[!UseLuridate] <- as.POSIXct(as.numeric(inputVector[!UseLuridate])*60*60*24, origin="1899-12-30", tz="GMT") 
    output 

} 

myDf <- myDf %>% dplyr::mutate(dateClean=dateHandlerVectorized(myDf$myExample)) 
+1

這將會是更容易在我看來閱讀,如果你指定'grepl(「 - 」,inputVector)'一個變量和使用的,而不是重寫好幾次。可能也更有效一點。 – Frank

+1

感謝您的提示! - 更新代碼 –

+2

將inputVector強制轉換爲字符也是有用的,以防萬一它是一個因素。當我嘗試myDf上的代碼時,「18-Mar-11」結果沒問題,但「42333」成爲1900年1月1日。 –