问题描述
我有一个包含两列的数据框,Q10_headache_tibble:
structure(list(df_questionaire.headaches = c(0L,2L,0L,NA,0L),df_questionaire.headaches_covid = c(0L,774L,774L)),row.names = c(NA,-175L),class = c("tbl_df","tbl","data.frame"))
我创建了一个函数,该函数应该返回一个与 nrow(df_headache_tibble) 长度相同的字符向量 (Q10_incidence),它基于应应用于数据帧的嵌套条件,逐行。 Q10_incidence[i] 应该是将函数应用于 df_headache_tibble[i,1] 和 df_headache_tibble[i,2] 的结果,我打算使用 mapply。
incidence_headaches<-function(x,y){
if (is.na(x)|is.na(y)){
output<-NA
}
else if (x==2){
if (y==2){
output<-'prevIoUs_headache_maintained'
}else if(y==0){
output<-'prevIoUs_headache_ceased'
}
}else if(x %in% c(0,774,775,776)){
if (y==2){
output<-'new_onset_headache'
}else if (y %in% c(0,776)){
output<-'no_headache'
}
}
}
Q10_incidence<-mapply(incidence_headaches,Q10_headache_tibble[,1],2])
当我打电话
mapply(incidence_headaches,2])
我在几个警告中得到了可怕的“条件长度 > 1,并且只会使用第一个元素”。我怎么能处理这个? 虽然我发现了几个关于相同的“条件具有长度(...)”警告的问题,但我仍然觉得这个话题很混乱。欢迎“傻瓜”演练。
好像跟向量化有关系,可以用嵌套的ifelse()结构代替函数来解决,可能会很乱。
我可能需要在很多情况下使用类似的功能,但不确定最好的解决方法是什么。
解决方法
1) 就我个人而言,我尝试尽可能多地使用 R 的许多命令中的一小部分。也许一个简单的 apply
是一种更简单的管理方法。 apply
和 MARGIN = 1
会将您的 data.frame 中的每一行分配给一个函数。所以我对你的函数做了一些小改动(这里只对前 3 行感兴趣,其余的是复制和粘贴):
incidence_headaches<-function(row){
x <- row[1]
y <- row[2]
if (is.na(x)|is.na(y)){
output<-NA
}
else if (x==2){
if (y==2){
output<-'previous_headache_maintained'
}else if(y==0){
output<-'previous_headache_ceased'
}
}else if(x %in% c(0,774,775,776)){
if (y==2){
output<-'new_onset_headache'
}else if (y %in% c(0,776)){
output<-'no_headache'
}
}
}
然后您可以像这样使用简单的 apply
:
apply(df_headache_tibble,MARGIN = 1,incidence_headaches)
要得到这样的东西:
> apply(df_headache_tibble,incidence_headaches)
[1] "no_headache" "previous_headache_ceased" "previous_headache_maintained"
[4] "previous_headache_maintained" "new_onset_headache" "no_headache"
[7] "no_headache" "no_headache" "previous_headache_ceased"
[10] "new_onset_headache" "previous_headache_ceased" "previous_headache_maintained"
[13] "no_headache" "previous_headache_ceased" "no_headache"
...
2) mapply
显然是一个完美的工作函数,没有理由不使用它。您的问题是:小标题是 data.frames,但它们的行为不像 data.frames。这很有效:
mapply(incidence_headaches,as.data.frame(df_headache_tibble)[,1],2])
当你只从 data.frame 中提取一行时,它会给你一个向量,当你只从一个 tibble 中提取一行时,它会给你一个 tibble。哈德利对事情应该如何运作与发明 R data.frame 的人有不同的看法。有很多方法可以解决这个问题,例如
mapply(incidence_headaches,df_headache_tibble[,1,drop = TRUE],2,drop = TRUE])
在此处阅读详细信息,但要始终注意,尽管小标题是 data.frames,但它们的行为与 data.frames 并不完全相同:https://tibble.tidyverse.org/reference/subsetting.html
,这是一个完全矢量化的解决方案,不需要 *apply
循环。
incidence_headaches <- function(x,y){
# create the return vector
output <- rep('no_headache',NROW(x))
# conditions for 'x'
x_2 <- x == 2
x_vec <- x %in% c(0,776)
# conditions for 'y'
y_2 <- y == 2
y_vec <- y %in% c(0,776)
# assign the return values given a combination
# of the conditions above. Note that the
# condition y == 0 is only used once and
# therefore a logical vector is not needed
output[is.na(x) | is.na(y)] <- NA_character_
output[x_2 & y_2] <- 'previous_headache_maintained'
output[x_2 & y == 0] <- 'previous_headache_ceased'
output[x_vec & y_2] <- 'new_onset_headache'
output[x_vec & y_vec] <- 'no_headache'
# return to caller
output
}
Q10_incidence <- incidence_headaches(Q10_headache_tibble[,Q10_headache_tibble[,2])
head(Q10_incidence)
#[1] "no_headache" "previous_headache_ceased"
#[3] "previous_headache_maintained" "previous_headache_maintained"
#[5] "no_headache" "no_headache"