我有一个有150行值的df,我想让R对df中的每一行和每一列重复以下内容。
数据的例子
df <- data.frame('criteria1' = c('x','1', 'X', '', 'X'), "criteria2" = c('y','3', '', 'X', ''), "criteria3" = c('y','7', '', 'X', 'X'))
如果一行中出现了一个X,我想让函数从前两行中取值,然后用'='将它们粘贴在一起。下面的操作对于第一行来说是很好的。
df$criteria1 <- ifelse(df$criteria1 == 'X', paste(df$criteria1 [1], '=', df$criteria1 [2]),'')
head(df)
问题是,当我尝试对数据框中的所有colomns做这件事时
df[] <- lapply(df, function(x) ifelse(df$x== 'X', paste(x[1], '=', x[2]),''))
所有单元格都变成了NA。我已经尝试了上面不同版本的代码,但没有任何东西给出预期的输出,这就是。
head(data.frame('criteria1' = c('x','1', 'x=1', '', 'x=1'), "criteria2" = c('y','3', '', 'y=3', ''), "criteria3" = c('y','7', '', 'y=7', 'y=7')))
使用 sapply
而不是 lapply
... 有很多参考文献来说明两者之间的区别,但我相信问题来自于ifelse适用于一个向量,而不是一个列表,所以你不能把它传递给lapply。
sapply(df, function(x) ifelse(x == 'X', paste(x[[1]], '=', x[[2]]),''))
A dplyr
解决办法。
编辑:
根据 @Chuk P 的评论(见下文),以下是对答案的编辑。
df %>%
mutate_all(~ifelse(.=="X",paste0(.[[1]],"=",.[[2]]),""))
criteria1 criteria2 criteria3
1
2
3 x=1
4 y=3 y=7
5 x=1 y=7
这与下面的输出相当。
ifelse(df$criteria1 == 'X', paste(df$criteria1 [1], '=', df$criteria1 [2]),'')
[1] "" "" "x = 1" "" "x = 1"
原始答案(见评论,答案留在这里是为了防止将来有用)
df %>%
mutate_all(~ifelse(.%in%c(letters,LETTERS),paste0(.,"=",.[grep("\\d",.)]),.))
或使用 dplyr
>=0.8.89.9000。
df %>%
mutate(across(everything(),~ifelse(.%in%c(letters,LETTERS),
paste0(.,"=",.[grep("\\d",.)]),.)))
结果:
criteria1 criteria2 criteria3
1 x=1 y=3 y=7
2 1 3 7
3 X=1
4 X=3 X=7
5 X=1 X=7
如果你想用空白代替。
df %>%
mutate_all(~ifelse(.%in%c(letters),paste0(.,"=",.[grep("\\d",.)]),.[!.%in%LETTERS]))
criteria1 criteria2 criteria3
1 x=1 y=3 y=7
2 1 3 7
3
4 x y
5 1 y 7
注意::
可能存在更简单的方法。这是为了增加答案的多样性。
您需要使用 mapply
这里,即
df[] <- mapply(function(x, y)replace(x, x == 'X', y), df, paste(df[1,], df[2,], sep = '='))
其中给出:
criteria1 criteria2 criteria3 1 x y y 2 1 3 7 3 x=1 4 y=3 y=7 5 x=1 y=7