【问题标题】:R how to merge different columns of data frame in oneR如何将数据框的不同列合并为一个
【发布时间】:2014-11-16 23:19:02
【问题描述】:

我在 R 中有一个如下所示的数据框

data
x1  x2  x3a x3b x3c x3d x4
A   43  0   0   0   1   P
B   23  0   1   0   0   Q
C   11  0   0   0   0   R 
D   66  0   0   1   0   S

现在我想将列 x3a, x3b, x3c, x3d 合并为单列。预期的单列将包含 x3a,x3b,x3c,x3d 中值为 1 的列号。该值应编号为(x3a=1,x3b=2,x3c=3,x3d=4)。预期结果将如下所示

x3
[1] 4    2    0    3

我尝试了reshape() 函数,但无法得到我真正想要的

q<-data[,3:6]
r<-reshape(q,varying=c("x3a","x3b","x3c","x3d"),v.names="x3",direction="long",times=c("x3a","x3b","x3c","x3d"))
final<-r[r$x3!=0,][,3]

但这并没有给出预期的结果。它错过了23 之间的值0

final
[1]4    2    3 

【问题讨论】:

  • 每行的那些是唯一的吗?

标签: r reshape


【解决方案1】:

这行得通:

data <- data.frame(
  x1 = c('A','B','C','D'),
  x2 = c(43,23,11,66),
  x3a = c(0,0,0,0),
  x3b = c(0,1,0,0),
  x3c = c(0,0,0,1),
  x3d = c(1,0,0,0),
  x4 = c('P','Q','R','S')
)
data$x3 <- as.matrix(data[,c('x3a','x3b','x3c','x3d')]) %*% c(1,2,3,4)

结果:

  x1 x2 x3a x3b x3c x3d x4 x3
1  A 43   0   0   0   1  P  4
2  B 23   0   1   0   0  Q  2
3  C 11   0   0   0   0  R  0
4  D 66   0   0   1   0  S  3

Chase 发表了一条相关的评论:如果x3a ... x3d 不是零或一怎么办?您可以使用ifelse() 来考虑这种情况:

data$x3 <- as.matrix(ifelse(data[,c('x3a','x3b','x3c','x3d')] > 0, 1, 0)) %*% c(1,2,3,4)

【讨论】:

  • 聪明!请注意,这假设 x3a - x3d 中的值始终为 1,在这种情况下这似乎是一个安全的假设。
  • @Chase 这就是我能用 OP 中提供的数据(指标变量)来计算的全部......但是可以进行简单的修改以支持任何条件
  • 是的,我同意 - 主要只是为了后代/如果 OPs 数据与所指示的不同。再次,非常聪明的解决方案!
  • 如果每行不止一个怎么办?我们必须选择包含 1 的任何一列?
  • @Prabhu 那么结果不能是唯一的。您必须定义一个规则来处理这种情况
【解决方案2】:

@Barrankas 的答案非常聪明而且矢量化,这是一个不太聪明/矢量化的选项

as.numeric(apply(data[, 3:6], 1, function(x) which(x == 1)))
## [1]  4  2 NA  3

【讨论】:

    【解决方案3】:

    使用rowcol 索引。应该很快,因为您只分配一次。

    data$new <- 0
    tmp <- data[3:6]==1
    data$new[ row(tmp)[tmp] ] <- col(tmp)[tmp]
    
    data
    
    #  x1 x2 x3a x3b x3c x3d x4 new
    #1  A 43   0   0   0   1  P   4
    #2  B 23   0   1   0   0  Q   2
    #3  C 11   0   0   0   0  R   0
    #4  D 66   0   0   1   0  S   3
    

    tmp 可以更改以适应所需的任何逻辑比较。

    【讨论】:

    • 最后,row()col() 的用法!!
    • @RichardScriven - 这类任务中没有充分利用的功能。
    • 我通常总是在矩阵索引中尝试一下,但最终我总是感到困惑。哈哈
    【解决方案4】:

    即使问题得到了最佳解决方案,我也只是根据可能不太为人所知的max.col 函数添加一个答案,该函数给出了行的最大元素的列索引。在这种情况下:

      data$x3 <-  max.col(data[,3:6])*as.logical(rowSums(data[,3:6]))
    

    当所有元素都是 0(根据需要)时,此调用给出 0,否则给出最大索引。它的优点是值可以是任何值。如果有平局,max.col 默认选择随机列;您也可以将其设置为找到的第一个或最后一个最大值。

    【讨论】:

      【解决方案5】:

      还有一个:您可以跨行使用match,并将nomatch 参数设置为零

      apply(df[-c(1,2,length(df))] == 1, 1, match, x = TRUE, nomatch = 0L)
      # [1] 4 2 0 3
      

      【讨论】:

        【解决方案6】:

        另一种方法是使用来自tidyrunite

        library(dplyr)
        library(tidyr) 
        
         dat1 <- data
        
         data$x3 <- unite(data[,3:6], x3, sep="") %>% #I could use starts_with("x3"), but it adds more characters
                        mutate(x3 = sub("-\\d", "0", paste(gregexpr("[^0]", x3)))) #x3 is character column
         data
            x1 x2 x3a x3b x3c x3d x4 x3  
         #1  A 43   0   0   0   1  P  4
         #2  B 23   0   1   0   0  Q  2
         #3  C 11   0   0   0   0  R  0
         #4  D 66   0   0   1   0  S  3
        

        假设,每行有多个匹配项,并且值不是 0

         dat1$x3c[2] <- 3
         dat1$x3 <- unite(dat1[,3:6], x3, sep="") %>% 
                              mutate(x3 = sub("-\\d", "0", paste(gregexpr("[^0]", x3))))
        
        
         dat1
         #  x1 x2 x3a x3b x3c x3d x4  x3
         #1  A 43   0   0   0   1  P   4
         #2  B 23   0   1   3   0  Q 2:3
         #3  C 11   0   0   0   0  R   0
         #4  D 66   0   0   1   0  S   3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-14
          • 1970-01-01
          • 2021-05-17
          • 1970-01-01
          • 2021-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多