将数字值转换为二进制(0/1)

7

我有一个数据框,记录了不同人吃的不同种类水果的数量。如下所示:

    apple  banana  orange
Tim     3       0       2
Tom     0       1       1
Bob     1       2       2

如何将它转换为二进制矩阵,即如果一个人拥有至少一种水果,无论他有多少个,那么记录为1,否则记录为0。就像下面这样。
    apple  banana  orange
Tim     1       0       1
Tom     0       1       1
Bob     1       1       1

你的对象是矩阵还是数据框?如果它是一个包含所有数字信息的数据框,你可以使用 as.matrix 将其强制转换为矩阵。 - Blue Magister
这是一个带有表头的数据框。 - lolibility
5个回答

21

这是你的data.frame

x <- structure(list(apple = c(3L, 0L, 1L), banana = 0:2, orange = c(2L, 
1L, 2L)), .Names = c("apple", "banana", "orange"), class = "data.frame", row.names = c("Tim", 
"Tom", "Bob"))

你的矩阵:

as.matrix((x > 0) + 0)
    apple banana orange
Tim     1      0      1
Tom     0      1      1
Bob     1      1      1

更新

我想象不到在睡前草率地发布一个帖子会引起任何讨论,但这些讨论本身非常有趣,因此我想在这里总结一下:

我的直觉是简单地利用R中TRUEFALSE的底层数字10。如果你尝试(并不是一种很好的方法)检查等价性,例如1 == TRUE0 == FALSE,你会得到TRUE。我的快捷方式(结果证明比正确或至少是更加正确的方式需要更多时间)是只需将0添加到我的TRUEFALSE中,因为我知道R会强制转换逻辑向量为数字。

更正确或者说更合适的方式是使用as.numeric来转换输出(我认为这就是@JoshO'Brien打算写的内容)。但是.... 不幸的是,这会删除输入的维数属性,所以您需要将结果向量重新转换为矩阵,事实证明,这仍然比我在答案中添加0要快。

阅读了评论和批评后,我想再添加一个选项---使用apply循环遍历列并使用as.numeric方法。虽然比手动重新创建矩阵要慢,但比将0添加到逻辑比较中略快一些。

x <- data.frame(replicate(1e4,sample(0:1e3)))
library(rbenchmark)
benchmark(X1 = {
            x1 <- as.matrix((x > 0) + 0)
          },
          X2 = {
            x2 <- apply(x, 2, function(y) as.numeric(y > 0))
          },
          X3 = {
            x3 <- as.numeric(as.matrix(x) > 0)
            x3 <- matrix(x3, nrow = 1001)
          },
          X4 = {
            x4 <- ifelse(x > 0, 1, 0)
          },
          columns = c("test", "replications", "elapsed", 
                      "relative", "user.self"))
#   test replications elapsed relative user.self
# 1   X1          100 116.618    1.985   110.711
# 2   X2          100 105.026    1.788    94.070
# 3   X3          100  58.750    1.000    46.007
# 4   X4          100 382.410    6.509   311.567

all.equal(x1, x2, check.attributes=FALSE)
# [1] TRUE
all.equal(x1, x3, check.attributes=FALSE)
# [1] TRUE
all.equal(x1, x4, check.attributes=FALSE)
# [1] TRUE

谢谢大家的讨论!


为什么这比 ifelse 更好?(不是因为我建议,只是好奇) - CHP
3
дёҖ件дәӢжҳҜпјҢAnandaзҡ„и§ЈеҶіж–№жЎҲиҝҗиЎҢйҖҹеәҰжҜ”ifelse()зүҲжң¬еҝ«3-4еҖҚгҖӮ(йЎәдҫҝиҜҙдёҖеҸҘпјҢas.logical(as.matrix(x) > 0)жҜ”д»–зҡ„и§ЈеҶіж–№жЎҲеҝ«дёӨеҖҚгҖӮпјүиҝҷжҳҜжҲ‘з”ЁжқҘиҝҗиЎҢеҮ ж¬ЎиҜ•йӘҢзҡ„ж•°жҚ®жЎҶжһ¶пјҡ x <- data.frame(replicate(1e4,sample(0:1e3)))гҖӮ - Josh O'Brien
@JoshO'Brien 感谢您的回复。我也检查了同样的事情。确实是这种情况。 :) - CHP
@JoshO'Brien,谢谢。你是指 as.numeric 对吧?我会尽快更新我的答案。 - A5C1D2H2I1M1N2O1R2T1
@ChinmayPatil,我已经更新了我的答案,并附上了一些基准测试和进一步的思考。 - A5C1D2H2I1M1N2O1R2T1
显示剩余2条评论

6

我通常使用以下方法:

df[df > 0] = 1

4

您可以使用ifelse。它可以在矩阵和数据框上使用,但结果将是矩阵。

> df <- cbind(aaple = c(3, 0 , 1), banana = c(0, 1, 2), orange = c(2, 1, 2))
> df
     aaple banana orange
[1,]     3      0      2
[2,]     0      1      1
[3,]     1      2      2

> ifelse(df>0, 1, 0)
     aaple banana orange
[1,]     1      0      1
[2,]     0      1      1
[3,]     1      1      1

1

只需使用比较:

d = t(matrix(c(3,0,2,0,1,1,1,2,2), 3))
d > 0
t(matrix(as.numeric(d>0), ncol(d)))

0
> pippo
  person apple banana orange
1    Tim     1      0      2
2    Tom     0      1      1
3    Bob     1      2      2
> cols <- c("apple", "banana", "orange")
> lapply(cols, function(x) {pippo[,x] <<- as.numeric(pippo[,x] >= 1)})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接