我想使用data. table根据另外两列中的值有条件地生成一列中的输出。这是我想使用一个包含'if'语句的函数来实现的,因为我只是想学习如何使用data. table。if语句包含shift()
,我认为这可能是我的问题的原因。
到目前为止,我所尝试的是以下内容:
library(data.table)
#Data
DT <- data.table(V1 = sample(LETTERS[1:3], 20, replace = TRUE),
V2 = sample(1:5, 20, replace = TRUE))
#function
fun1 <- function(x, y){
if(x == "C" & shift(y, type = "lead") > y){
return("Greater")
} else if(x == "C" & shift(y, type = "lead") < y){
return("Lesser")
} else{
return(NA)
}
}
#function implementation
DT.v1 <- DT[, V3 := mapply(fun1, x = V1, y = V2)]
如果我运行上面的代码,我会得到错误:
Error in if (x == "C" & shift(y, type = "lead") > y) { :
missing value where TRUE/FALSE needed
我有一个暗示,这个错误可能是由于在最后一次迭代中与NA
进行比较而导致的,因为shift(y, type = "lead")
将等于NA
。在“if”语句中添加条件!is.na(shift(y, type = "lead"))
确实阻止了错误的出现,但导致仅生成NULL
值。
我已经能够生成我想要的输出(见下面的脚本),但也想学习如何在函数中使用“if”语句来实现这一点。
DT.v2 <- DT[V1 == "C" & shift(V2, type = "lead") > V2, V3 := "Greater"][
V1 == "C" & shift(V2, type = "lead") < V2, V3 := "Lesser"]
#or an alternative way to generate the desired output:
DT.v3 <- DT[, V3 := ifelse(V1 == "C" & shift(V2, type = "lead") > V2, "Greater",
ifelse(V1 == "C" & shift(V2, type = "lead") < V2, "Lesser", NA))]
有人能帮助我理解如何以正确的方式实现函数吗?感谢您抽出时间来帮助!
2条答案
按热度按时间z9smfwbn1#
mapply
的使用包含了shift
查看正在处理的行周围数据的功能。顺便说一句,我将
if
语句中的单个-&
替换为&&
,您永远不应该在那里使用&
,除非它是聚合的,例如,在sum
,any
,all
等中。(有关差异的讨论,请参见Difference between Boolean operators && and & and between || and | in R。)一种方法是将移位后的数据作为参数传递给函数:
在这个
fun2
中使用isTRUE
是为了说明shifty
将是NA
的条件;避免这种情况的另一种方法是使用shifty=shift(V3, type="lead", fill=0)
,其中0
是对数据和分析的上下文有意义的数字。如果你不需要使用函数,另一个选择是使用
fcase
:使用
fcase
与基本if
语句相比有一个有趣的事情:对于if
,如果任何一个操作数是NA
,并且您没有显式地考虑到这一点,那么条件本身将是NA
,从而导致if
语句失败(参见Error in if/while (condition) {: missing Value where TRUE/FALSE needed)。但对于fcase
,情况并非如此:相关地,虽然
ifelse
不会失败,但它也不一定能像我们想要的那样工作,而fifelse
为我们提供了显式处理NA
条件的选项:这是由格式建议的(并记录在文档中):
flvlnr442#
最主要的问题,在NA问题之上,你正确地指出了if语句需要长度为1的条件
fun1
正在传递一个向量- update fun 1没有传递一个向量,请参见下面的注解。在我看来,你的第二种选择是做这项工作的正确方法。
这是不太容易出错的。如果你真的需要使用if else语句,我建议检查
?fcase
。