r - l/sapply 忽略条件替换
问题描述
我有一个有点复杂的数据结构,有一个列表列表——每个列表都有不同长度的数字向量。我需要根据与主列表长度相同的单独向量,用 NA 替换向量中的一些值。但是,R 不是仅替换特定值,而是替换整个向量。贝娄,一个例子:
> ## Minimal example with a list of vectors
> # Creating list
> mylist = rep(list(1:3), 3)
>
> # Vector on which I will base the replacement
> myvec = 1:3
>
> # Replacing 1s by NA
> for(i in 1:length(mylist)){
+ mylist[[i]] = sapply(mylist[[i]], function(x) x[x ==myvec[i]] = NA)
+ }
>
> # But I get NAs for every observation
> mylist
[[1]]
[1] NA NA NA
[[2]]
[1] NA NA NA
[[3]]
[1] NA NA NA
>
> # This is what I wanted:
> list(c(NA, 2, 3), c(1, NA, 3), c(1, 2, NA))
[[1]]
[1] NA 2 3
[[2]]
[1] 1 NA 3
[[3]]
[1] 1 2 NA
>
>
> ## More complex example, with a list of lists of vectors that more closely approximates my data structure
> # Creating list of lists
> mynewlist = rep(list(rep(list(1:3), 3)), 3)
>
> # Replacing 1s by NAs
> for(i in 1:length(mynewlist)){
+ mynewlist[[i]] = lapply(mynewlist[[i]], function(x) x[x ==myvec[i]] = NA)
+ }
>
> # But now each vector becomes a single NA
> mynewlist
[[1]]
[[1]][[1]]
[1] NA
[[1]][[2]]
[1] NA
[[1]][[3]]
[1] NA
[[2]]
[[2]][[1]]
[1] NA
[[2]][[2]]
[1] NA
[[2]][[3]]
[1] NA
[[3]]
[[3]][[1]]
[1] NA
[[3]][[2]]
[1] NA
[[3]][[3]]
[1] NA
>
> # What I wanted:
> list(rep(list(c(NA, 2, 3)), 3), rep(list(c(1, NA, 3)), 3), rep(list(c(1, 2, NA)), 3))
[[1]]
[[1]][[1]]
[1] NA 2 3
[[1]][[2]]
[1] NA 2 3
[[1]][[3]]
[1] NA 2 3
[[2]]
[[2]][[1]]
[1] 1 NA 3
[[2]][[2]]
[1] 1 NA 3
[[2]][[3]]
[1] 1 NA 3
[[3]]
[[3]][[1]]
[1] 1 2 NA
[[3]][[2]]
[1] 1 2 NA
[[3]][[3]]
[1] 1 2 NA
请注意,无论替换的具体值如何,都会发生同样的情况(例如,如果我将替换更改为 0,而不是 NA,那么无论条件如何,0 都会替换所有值)。
这是怎么回事?为什么 lapply/sapply 忽略条件?
顺便说一句,我欢迎在没有任何 for 循环的情况下执行此操作的建议。
编辑:除了编辑上面的代码以明确我将替换基于一个单独的向量(因此是 for 循环)之外,我还能够使用 ifelse 获得我想要的东西。不过,我仍然不明白,为什么 l/sapply 不能识别括号的选择和替换。我很感激对此的任何解释,以及如何在没有循环的情况下做到这一点。
带有 ifelse 的代码:
> # Creating list of lists
> mynewestlist = rep(list(rep(list(1:3), 3)), 3)
>
> # Replacing 1s by NAs
> for(i in 1:length(mynewestlist)){
+ mynewestlist[[i]] = lapply(mynewestlist[[i]], function(x) ifelse(x ==myvec[i], NA, x))
+ }
>
> # That's better:
> mynewestlist
[[1]]
[[1]][[1]]
[1] NA 2 3
[[1]][[2]]
[1] NA 2 3
[[1]][[3]]
[1] NA 2 3
[[2]]
[[2]][[1]]
[1] 1 NA 3
[[2]][[2]]
[1] 1 NA 3
[[2]][[3]]
[1] 1 NA 3
[[3]]
[[3]][[1]]
[1] 1 2 NA
[[3]][[2]]
[1] 1 2 NA
[[3]][[3]]
[1] 1 2 NA
> list(rep(list(c(NA, 2, 3), 3), rep(list(1, NA, 3), 3), rep(list(1, 2, NA), 3))
解决方案
无需sapply
在元素的每个元素上运行,list
因为我们可以以矢量化形式执行此操作。
lapply(mylist, function(x) replace(x, x <=1, NA))
或带有for
循环
for(i in seq_along(mylist)) mylist[[i]] <- replace(mylist[[i]],
mylist[[i]] <=1, NA)
请注意,OP 更改了条件,即创建一个与“mylist”长度相同的向量(“myvec”),并希望将那些与“mylist”的相应元素匹配的值替换为 NA。它可以通过很多方式完成。一种选择是Map
遍历 和 的每个元素list
以及vector
与replace
NA 匹配的值。
Map(function(x, y) replace(x, x == y, NA), mylist, myvec)
#[[1]]
#[1] NA 2 3
#[[2]]
#[1] 1 NA 3
#[[3]]
#[1] 1 2 NA
或使用for
循环
for(i in seq_along(mylist)) mylist[[i]] <- replace(mylist[[i]],
mylist[[i]] == myvec[i], NA)
或者lapply
通过遍历序列来使用
lapply(seq_along(mylist) function(i)
replace(mylist[[i]], mylist[[i]] == myvec[i], NA))
关于为什么 OP 只获得 NA,在 中sapply
,返回值是对对象的赋值,NA
而不是对象本身。检查lapply/sapply
这里的输出
lapply(mylist[[1]], function(x) x[x==myvec[1]] <- NA)
#[[1]]
#[1] NA
#[[2]]
#[1] NA
#[[3]]
#[1] NA
它是赋值,而不是“x”。返回 'x' 以获得 'x' 的输出(正如@user20650 评论的那样)
lapply(mylist[[1]], function(x) {x[x==myvec[1]] <- NA; x})
#[[1]]
#[1] NA
#[[2]]
#[1] 2
#[[3]]
#[1] 3
推荐阅读
- ssl - 钱包通行证推送通知 APNs
- python - 如何使用 Selenium 登录全球速卖通
- c# - EF 核心工作单元模式中的事务
- sql - SQL Server 记录行访问最佳实践
- outlook - Outlook.js onSend 支持 Office 2016/2019(未连接到 365)
- javascript - 列标题居中但列体右对齐
- windows - 如何将命令的多行输出存储到批处理变量中?
- java - java泛型:形式类型“?扩展MyClass”不能用于调用“T get(Class
一类) - python-3.x - 使用大数据库中的日期按步骤(刻度)标记 x 轴
- flutter - 诊断 Flutter 版本解决问题