2014-09-22 14 views
4

合併數據幀的不同列我有R中的數據幀,看起來像這樣[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 
+1

每行的那些獨特其他? – Barranka 2014-09-22 21:40:18

回答

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 

大通做了一個評論是有關什麼如果x3a ... x3d與零或一個不同?您可以使用ifelse()考慮到情景:

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

聰明!注意,這裏假設'x3a - x3d'中的值總是爲1,這在這種情況下看起來像是一個安全的假設。 – Chase 2014-09-22 21:55:13

+0

@Chase這是我可以用OP中提供的數據(指標變量)來計算......但是可以進行一個簡單的修改以支持任何條件 – Barranka 2014-09-22 21:56:24

+1

是的,我同意 - 主要只是注意到後代/如果OP數據與所指出的不同。再次,非常聰明的解決方案! – Chase 2014-09-22 23:05:54

5

@Barrankas的回答很聰明,也矢量,這裏有一個聰明的少/量化選項

as.numeric(apply(data[, 3:6], 1, function(x) which(x == 1))) 
## [1] 4 2 NA 3 
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可以改變,以適應任何需要的邏輯比較。

+1

最後,用於'row()'和'col()'! – 2014-09-23 00:51:58

+0

@RichardScriven - 這類任務的功能非常欠缺。 – thelatemail 2014-09-23 00:54:59

+0

我通常總是試一試矩陣指數,但我總是感到困惑。哈哈 – 2014-09-23 00:55:52

1

還有一個:你可以使用match跨行,與nomatch參數設置爲零

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

即使問題都獲得了最佳的解決方案,我只是添加一個基於可能的答案並不知道max.col函數,它給出了行的最大元素的列索引。在這種情況下:

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

此調用在所有元素均爲0(根據需要)時爲0,否則爲0。它的優點是值可以是任何值。如果存在平局,max.col默認選擇一個隨機列;您可以將其設置爲找到的第一個或最後一個最大值。

0

另一種方法是使用unitetidyr

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