基于行值拼接列名

3

我有一个包含0或1的R数据框,其中有3列。当值为1时,我需要创建一列作为由列名连接而成的字符串,用'&'分隔。以下代码在空格''作为分隔符时有效,但在将其更改为'&'时失败。

代码:

A = c(1,0,1,0,0,1)
B = c(1,1,1,0,1,0)
C = c(0,0,0,1,1,1)
data = data.frame(A, B, C)
data$New = paste(ifelse(data$A == 1, "A", ""),
                 ifelse(data$B == 1, "B", ""),
                 ifelse(data$C == 1, "C", ""), sep = '')
data

输出:

  A B C New
1 1 1 0  AB
2 0 1 0   B
3 1 1 0  AB
4 0 0 1   C
5 0 1 1  BC
6 1 0 1  AC

代码和输出使用“&”分隔符:

A = c(1,0,1,0,0,1)
B = c(1,1,1,0,1,0)
C = c(0,0,0,1,1,1)
data = data.frame(A, B, C)
data$New = paste(ifelse(data$A == 1, "A", ""), 
                 ifelse(data$B == 1, "B", ""),
                 ifelse(data$C == 1, "C", ""), sep = '&')
data

  A B C  New
1 1 1 0 A&B&
2 0 1 0  &B&
3 1 1 0 A&B&
4 0 0 1  &&C
5 0 1 1 &B&C
6 1 0 1 A&&C

预期输出:

  A B C New
1 1 1 0 A&B
2 0 1 0   B
3 1 1 0 A&B
4 0 0 1   C
5 0 1 1 B&C
6 1 0 1 A&C
  1. 有没有在 R 中实现这个的方法?
  2. 如果列数很多,是否有一种方法可以在不对每列都编写明确的 ifelse 条件的情况下完成相同的操作?
3个回答

5
我们可以通过遍历行来对names进行子集处理。
data$New <- apply(data[1:3], 1, function(x) paste(names(x[x!=0]), collapse="&"))
data$New
#[1] "A&B" "B"   "A&B" "C"   "B&C" "A&C"

这也可以按列完成

library(tidyverse)
data[1:3] %>% 
    na_if(0) %>%
   `*`(col(.)) %>% 
   imap(~ rep(.y, length(.x))[.x]) %>%
   reduce(paste, sep= "&") %>% 
   str_remove("(NA&)+|(&NA)+") %>%
   str_remove("&NA")
#[1] "A&B" "B"   "A&B" "C"   "B&C" "A&C"

谢谢。执行速度如何?这是矢量化实现还是逐行操作? - Rinaz Belhaj
可以按列进行操作,而不是逐行进行操作。例如:data[1:3] %>% na_if(0) %>% *(col(.)) %>% imap(~ rep(.y, length(.x))[.x]) %>% reduce(paste, sep= "&") %>% str_remove("(NA&)+|(&NA)+") %>% str_remove("&NA") - akrun

4
你可以使用applypaste来实现它。
nms <- names(data)
data$New <- apply(data, 1, function(x){
  paste(nms[as.logical(x)], collapse = "&")
})

data
#  A B C New
#1 1 1 0 A&B
#2 0 1 0   B
#3 1 1 0 A&B
#4 0 0 1   C
#5 0 1 1 B&C
#6 1 0 1 A&C

2

使用 whicharr.ind = TRUE,然后使用 aggregate

cbind(data,
      new = aggregate(col ~ row, data = which(data == 1, arr.ind = TRUE),
                      function(x) paste(names(data)[x], collapse = "&"))[ , "col"])

#   A B C new
# 1 1 1 0 A&B
# 2 0 1 0   B
# 3 1 1 0 A&B
# 4 0 0 1   C
# 5 0 1 1 B&C
# 6 1 0 1 A&C

相似地,使用tapply
ix <- which(data == 1, arr.ind = TRUE)
cbind(data,
      new = tapply(ix[ , "col"], ix[ , "row"],
                   function(x) paste(names(data)[x], collapse = "&")))

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