R如何合并不同的数据帧列

时间:2014-09-22 21:31:45

标签: r reshape

我在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]

但这没有给出预期的结果。它错过了02

之间的值3
final
[1]4    2    3 

6 个答案:

答案 0 :(得分:10)

这有效:

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)

答案 1 :(得分:5)

@Barrankas的答案非常聪明,也是矢量化的,这里是一个不那么聪明/矢量化的选项

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

答案 2 :(得分:5)

使用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以适应所需的逻辑比较。

答案 3 :(得分:4)

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

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

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

答案 4 :(得分:1)

还有一个:您可以跨行使用matchnomatch参数设置为零

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

答案 5 :(得分:1)

另一种方法是使用unite

中的tidyr
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