在 R 中执行 lapply 时忽略特定级别 编辑

问题描述

我在 R 中有一个数据框(40000 个变量的 500 个 obs),其中所有列都由一个或两个散布着“1”和“3”的字母组成。例如,mydata[45:50,20:25]

45             C             A             3             T             C             C
46             C             G             T             C             C             A
47             C             A             G             T             C             C
48             1             A             T             3             C             3
49             C             A             G             T             C             C
50             T             A             T             C             C             A

我只想替换字母而不是数字。我的目标是将字母替换为“0”或“2”,具体取决于它们的频率。因此,出现频率最高的字母变为“0”,而出现频率最低的字母变为“2”。如果只有一个字母,那就是'0'。

我可以在不忽略穿插的“1”和“3”的情况下使用:

data.frame(lapply(mydata[45:50,20:25],function(x){as.numeric(factor(x,levels = names(sort(-table(x)))))}))

产生:

1             1             1             3             1             1             1
2             1             2             1             2             1             2
3             1             1             2             1             1             1
4             2             1             1             3             1             3
5             1             1             2             1             1             1
6             3             1             1             2             1             2

但是,我希望能够在忽略原始数据框中的“1”和“3”的同时做到这一点。

任何帮助表示赞赏。谢谢。

解决方法

我会在这里使用 matrix

使用 grep,我们制作 table 的频率,我们对它们的负值 rank 并减去一得到零。由于我不确定在平局的情况下您想要什么,因此我选择了 "first" 来获取整数(有关选项,请参阅 ?rank)。

然后我们 match 频率上的字母。最后,我们使用 type.convert 转换回数据框以获得数字格式。

m <- as.matrix(d)

ftb <- table(grep("[\\p{Lu}]",m,perl=TRUE,value=TRUE))
ftb <- rank(-ftb,ties.method="first") - 1

m.res <- apply(m,1:2,function(x) ifelse(x %in% names(ftb),ftb[match(x,names(ftb))],x))
d.res <- type.convert(as.data.frame(m.res))
d.res
#   V1 V2 V3 V4 V5 V6 V7
# 1 45  0  1  3  2  0  0
# 2 46  0  3  2  0  0  1
# 3 47  0  1  3  2  0  0
# 4 48  1  1  2  3  0  3
# 5 49  0  1  3  2  0  0
# 6 50  2  1  2  0  0  1

编辑

由于您想查看列频率,我们可以在 lapply 中使用该方法(不进行矩阵转换)。我们可以将排名乘以因子 2。

f <- 2
d[-1] <- lapply(d[-1],function(x) {
  ftb <- (rank(-table(grep("[\\p{Lu}]",x,value=TRUE)),ties.method="first") - 1)*f
  stopifnot(length(ftb) <= 2)
  x <- ifelse(x %in% names(ftb),x)
  as.numeric(x)
})
d
#   V1 V2 V3 V4 V5 V6 V7
# 1 45  0  0  3  0  0  0
# 2 46  0  2  0  2  0  2
# 3 47  0  0  2  0  0  0
# 4 48  1  0  0  3  0  3
# 5 49  0  0  2  0  0  0
# 6 50  2  0  0  2  0  2

数据:

d <- structure(list(V1 = 45:50,V2 = c("C","C","1","T"
),V3 = c("A","G","A","A"),V4 = c("3","T","T"),V5 = c("T","3","C"),V6 = c("C",V7 = c("C","A"
)),class = "data.frame",row.names = c(NA,-6L))