2015-10-05 30 views
2

以下是複製我的數據集的代碼。根據變量獲取列的值和位置

col1=c(20,15,NA,NA) 
col2=c(30,30,6,NA) 
col3=c(40,NA,7,NA) 
col4=c(NA,60,8,NA) 
col5=c(60,75,9,NA) 
check=c(40,35,10,NA) 

df=data.frame(col1,col2,col3,col4,col5,check) 

我想獲得它大於列的位置「檢查」 column.If有可能,我也想獲得該列的值也是如此。

這裏是我創建了一個功能,它不工作:

fun=function(x){ 
     j1=which(x>df$check)[1] 
     if(is.na(j1)){ 
       NA 
     } 
     else if (!is.na(j1)){ 
       j1 
     } 
} 

df$test=apply(df[,1:5],1,fun) 

我最後的數據幀應該是這樣的:

col1=c(20,15,NA,NA) 
col2=c(30,30,6,NA) 
col3=c(40,NA,7,NA) 
col4=c(NA,60,8,NA) 
col5=c(60,75,9,NA) 
check=c(40,35,10,NA) 
test=c(5,4,NA,NA) 
value=c(60,60,NA,NA) 
df=data.frame(col1,col2,col3,col4,col5,check, test,value) 

任何幫助,將不勝感激。謝謝

回答

2

我們可以使用max.col來獲得列索引。使用行序列和列索引,我們可以從前五列中提取元素。

#created a logical matrix 
m1 <- df[1:5] > df$check 
#changed the NA elements to FALSE 
m1[is.na(m1)] <- FALSE 
#used max.col to get the column index. For rows that have all FALSE 
#we change it to 0 after multiplying with the logical index of `rowSums(..`. 
v1 <- max.col(m1, 'first')*(rowSums(m1)!=0) 
#reconvert the 0 values to NA 
test <- NA^(v1==0)*v1 
#extract the elements using row/column index 
value <- df[1:5][cbind(1:nrow(df), test)] 
#cbind the new vectors to get the desired output. 
df <- cbind(df, test, value) 
df 
# col1 col2 col3 col4 col5 check test value 
#1 20 30 40 NA 60 40 5 60 
#2 15 30 NA 60 75 35 4 60 
#3 NA 6 7 8 9 10 NA NA 
#4 NA NA NA NA NA NA NA NA 

或兩個列可以使用apply創建。雖然這可能是緊湊的,但與第一個解決方案相比,效率可能會更低。我們使用applyMARGIN=1循環遍歷行,得到大於第6個值的元素1到5的數字索引,第一個發生的子集(如果沒有元素,這會自動將其轉換爲NA)。基於這個索引,我們對元素進行子集合,連接,獲得轉置並分配給'df'中的新列。

df[c('test', 'value')] <- t(apply(df, 1, function(x) { 
      i1 <- which(x[1:5]>x[6])[1] 
       c(i1, x[i1])})) 
+1

構建'test'如'max.col(M1, '第一')* NA ^(rowSums(M1)== 0)'從處理中間變量可以節省。雖然也許很難解釋。另外,最好將新的cols添加到'df'而不是'cbind'新的'df [c(「test」,「value」)] < - list(test,value)'。去添加評論申請vs max.col?看起來後者在SO上更受歡迎。 – Frank

+1

@Frank我想過把它用在一行中,但它變得很難理解。 – akrun