简化 R 中的代码
Simplify a code in R
我编写了一个遍历数据框列的代码,returns如果其中任何一个有数字 1,则为 TRUE,并将该值发送到与列大小相同的向量的数据框。我想知道是否有一种方法可以简化下面的代码片段,因为我将不得不重复几个数字。
n1 <- (tab[, 2]==1| tab[, 3]==1 | tab[, 4]==1 | tab[, 5]==1 |
tab[, 6]==1 | tab[, 7]==1 | tab[, 8]==1 | tab[, 9]==1 |
tab[, 10]==1 | tab[, 11]==1 | tab[, 12]==1 | tab[, 13]==1 |
tab[, 14]==1 | tab[, 15]==1 | tab[, 16]==1)
一种可能的解决方案如下:您在数据框中搜索 == 1 个数字,然后使用 |
运算符减少其行数:
tab <- data.frame(a = 1:10, b = 2:11)
apply(tab == 1, 1, function(x) {
Reduce("|", x)
})
对于这个例子,它会给你输出:
[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
或者一个更简单的解决方案是:
apply(tab, 1, function(x) {
any(x == 1)
})
其他评论和答案可以工作,但我建议他们在处理 data.frame
时鼓励不良行为。首先也是最重要的是 apply
和 rowSums
期望 matrix
作为数据,并且如果给定 data.frame
将很乐意强制转换为这样的数据。如果任何 data.frame
列是 character
,则所有列都将转换为 character
。某些操作可能仍会按预期工作(例如,== 1
,因为它实际上是 == "1"
... 尽管一些舍入错误可能会导致不良影响),但任何数学运算都不起作用。
例如,
n <- 20
set.seed(2)
tab <- data.frame(
a = as.character(sample(n, replace = FALSE)),
b1 = sample(5, size = n, replace = TRUE),
b2 = sample(5, size = n, replace = TRUE),
stringsAsFactors = FALSE
)
str(tab)
# 'data.frame': 20 obs. of 3 variables:
# $ a : chr "4" "14" "11" "3" ...
# $ b1: int 4 2 5 1 2 3 1 2 5 1 ...
# $ b2: int 5 2 1 1 5 4 5 2 3 5 ...
apply(tab, 1, function(y) any(y == 1))
# [1] FALSE FALSE TRUE TRUE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE
apply(tab, 1, sum)
# Error in FUN(newX[, i], ...) : invalid 'type' (character) of argument
rowSums(tab == 1)
# [1] 0 0 1 2 0 0 1 0 0 1 2 2 0 0 0 0 0 1 0 1
rowSums(tab)
# Error in rowSums(tab) : 'x' must be numeric
有一些简单的方法可以解决这个问题。鉴于您的示例, 2:16
列似乎是数字,并且是您所关心的。如果是这种情况,那么您可以安全地使用以下任一方法:
rowSums(tab[,2:16] == 1) # Frank's comment
apply(tab[,2:16], 1, function(y) any(y == 1)) # suggested by You-leee's answer
(前者相当具体,后者可以扩展到其他功能)。如果只有一个非numeric
,一次总能做到
rowSums(tab[,-1,drop=FALSE] == 1)
apply(tab[,-1,drop=FALSE], 1, function(y) any(y == 1))
第三种技术是在 运行 时确定选择哪些列:
isnum <- sapply(tab, is.numeric)
Reduce(`|`, lapply(tab[isnum], function(y) any(y == 1)))
这有点复杂,因为 lapply
中的 return 是 list
,但它仍然可以正常工作。意识到 isnum
的使用也可以基于列名,使用类似 grepl
的东西。此方法也相当稳健,因为如果 none 列匹配,它不会出错。
我编写了一个遍历数据框列的代码,returns如果其中任何一个有数字 1,则为 TRUE,并将该值发送到与列大小相同的向量的数据框。我想知道是否有一种方法可以简化下面的代码片段,因为我将不得不重复几个数字。
n1 <- (tab[, 2]==1| tab[, 3]==1 | tab[, 4]==1 | tab[, 5]==1 |
tab[, 6]==1 | tab[, 7]==1 | tab[, 8]==1 | tab[, 9]==1 |
tab[, 10]==1 | tab[, 11]==1 | tab[, 12]==1 | tab[, 13]==1 |
tab[, 14]==1 | tab[, 15]==1 | tab[, 16]==1)
一种可能的解决方案如下:您在数据框中搜索 == 1 个数字,然后使用 |
运算符减少其行数:
tab <- data.frame(a = 1:10, b = 2:11)
apply(tab == 1, 1, function(x) {
Reduce("|", x)
})
对于这个例子,它会给你输出:
[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
或者一个更简单的解决方案是:
apply(tab, 1, function(x) {
any(x == 1)
})
其他评论和答案可以工作,但我建议他们在处理 data.frame
时鼓励不良行为。首先也是最重要的是 apply
和 rowSums
期望 matrix
作为数据,并且如果给定 data.frame
将很乐意强制转换为这样的数据。如果任何 data.frame
列是 character
,则所有列都将转换为 character
。某些操作可能仍会按预期工作(例如,== 1
,因为它实际上是 == "1"
... 尽管一些舍入错误可能会导致不良影响),但任何数学运算都不起作用。
例如,
n <- 20
set.seed(2)
tab <- data.frame(
a = as.character(sample(n, replace = FALSE)),
b1 = sample(5, size = n, replace = TRUE),
b2 = sample(5, size = n, replace = TRUE),
stringsAsFactors = FALSE
)
str(tab)
# 'data.frame': 20 obs. of 3 variables:
# $ a : chr "4" "14" "11" "3" ...
# $ b1: int 4 2 5 1 2 3 1 2 5 1 ...
# $ b2: int 5 2 1 1 5 4 5 2 3 5 ...
apply(tab, 1, function(y) any(y == 1))
# [1] FALSE FALSE TRUE TRUE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE
apply(tab, 1, sum)
# Error in FUN(newX[, i], ...) : invalid 'type' (character) of argument
rowSums(tab == 1)
# [1] 0 0 1 2 0 0 1 0 0 1 2 2 0 0 0 0 0 1 0 1
rowSums(tab)
# Error in rowSums(tab) : 'x' must be numeric
有一些简单的方法可以解决这个问题。鉴于您的示例, 2:16
列似乎是数字,并且是您所关心的。如果是这种情况,那么您可以安全地使用以下任一方法:
rowSums(tab[,2:16] == 1) # Frank's comment
apply(tab[,2:16], 1, function(y) any(y == 1)) # suggested by You-leee's answer
(前者相当具体,后者可以扩展到其他功能)。如果只有一个非numeric
,一次总能做到
rowSums(tab[,-1,drop=FALSE] == 1)
apply(tab[,-1,drop=FALSE], 1, function(y) any(y == 1))
第三种技术是在 运行 时确定选择哪些列:
isnum <- sapply(tab, is.numeric)
Reduce(`|`, lapply(tab[isnum], function(y) any(y == 1)))
这有点复杂,因为 lapply
中的 return 是 list
,但它仍然可以正常工作。意识到 isnum
的使用也可以基于列名,使用类似 grepl
的东西。此方法也相当稳健,因为如果 none 列匹配,它不会出错。