2015-06-23 2 views
4

У меня есть data.tableres, который имеет следующие данные:Выбор частых значений из нескольких столбцов из таблицы R

  V1 V2 V3 V4 
    1:  Day_1 4 4 4 
    2:  Day_2 1 1 2 
    3:  Day_3 4 5 4 
    4:  Day_4 3 4 4 
    5:  Day_5 3 2 3 

мне нужно, чтобы выбрать наиболее частое значение из столбцов V2, V3 и V4, вместе взятых. То есть, мне нужно выбрать результат следующим образом:

Day_1 4 
Day_2 1 
Day_3 4 
Day_4 4 
Day_5 3 

Я не ожидаю каких-либо связей, так как там будет всегда нечетное число столбцов. Можно ли манипулировать data.table, чтобы сделать это? Или мне нужно изменить какой-либо другой тип данных?

Спасибо - V

+4

[This] (http://stackoverflow.com/questions/2547402/standard-library-function-in-r-for-finding-the-mode) - это функция, которую вы, вероятно, ищете. –

+2

Попробуйте 'apply (res [, - 1, with = FALSE], 1, Mode)' '(Mode)' из ссылки – akrun

+0

использование режима (из ссылки) с применением приложения работает отлично! Спасибо. – visakh

ответ

5

Я я отправляю это как вариант this old questiondata.table пока что-то лучше, предлагается

Mode <- function(x) { 
    ux <- unique(x) 
    ux[which.max(tabulate(match(x, ux)))] 
} 

DT[, .(res = Mode(unlist(.SD))), by = V1] 

#  V1 res 
# 1: Day_1 4 
# 2: Day_2 1 
# 3: Day_3 4 
# 4: Day_4 4 
# 5: Day_5 3 
+0

@David ... спасибо. Я буду ждать немного дольше, прежде чем принимать ответ. – visakh

3

Вот два варианта на ответ Давида:

# table 
DT[,ans:={ 
    tab <- table(r = rep(.I,length(.SD)), unlist(.SD)) 
    as(colnames(tab)[ max.col(tab) ], class(.SD[[1]])) 
},.SDcols=-1] 

# apply Mode 
DT[,ans:=apply(.SD,1,Mode),.SDcols=-1] 

I подумал, что я посмотрю на них, потому что расщепление DT по строкам может быть медленным.

Speed ​​.

Сравнение со строкой. Начав с очень мало уникальных значений и строк ...

n <- 1e4 
nv <- 5 
nc <- 3 

DT <- do.call(data.table,c(
    list(id=1:n), 
    replicate(nc,sample(nv,n,replace=TRUE),simplify=FALSE) 
)) 

require(rbenchmark) 

benchmark(
    table  = DT[,.({ 
    tab <- table(r = rep(.I,length(.SD)), unlist(.SD)) 
    as(colnames(tab)[ max.col(tab) ], class(.SD[[1]])) 
    }),.SDcols=-1], 
    byMode = DT[,.(Mode(unlist(.SD))), by = id], 
    applyMode = DT[,.(apply(.SD,1,Mode)),.SDcols=-1], 
    replications=10 
)[1:5] 
#  test replications elapsed relative user.self 
# 3 applyMode   10 1.66 4.611  1.65 
# 2 byMode   10 2.03 5.639  2.02 
# 1  table   10 0.36 1.000  0.36 

Увеличение каждого из трех параметров по отдельности ...

nv <- 1e3 # up from 5 

#  test replications elapsed relative user.self 
# 3 applyMode   10 1.67 1.000  1.67 
# 2 byMode   10 2.05 1.228  2.02 
# 1  table   10 4.27 2.557  4.15 

n <- 5e4 # up from 1e4 

#  test replications elapsed relative user.self 
# 3 applyMode   10 8.67 4.492  8.65 
# 2 byMode   10 10.21 5.290  10.22 
# 1  table   10 1.93 1.000  1.92 

nc <- 100 # up from 3 

#  test replications elapsed relative user.self 
# 3 applyMode   10 2.59 1.000  2.59 
# 2 byMode   10 6.71 2.591  6.69 
# 1  table   10 11.69 4.514  11.68 

Обсуждение. (Я сравнивая elapsed столбцы через бенчмарках.)

  • NV. В то время как table выигрывает за маленький чехол, он плохо масштабируется с количеством уникальных значений, так как его объект tab становится очень большим. Остальные два метода не затрагиваются.
  • n. Все линейно масштабируется с количеством строк. (Я ожидал, что table также будет уменьшаться по этому размеру, но, возможно, n должен быть еще больше.)
  • nc. table весы линейно с колоннами, а остальные два лучше.

Опять же, с расплавом

# back to original values for n, nv, nc 
benchmark(
    table  = DT[,.({ 
    tab <- table(r = rep(.I,length(.SD)), unlist(.SD)) 
    as(colnames(tab)[ max.col(tab) ], class(.SD[[1]])) 
    }),.SDcols=-1], 
    byMode = DT[,.(Mode(unlist(.SD))), by = id], 
    applyMode = DT[,.(apply(.SD,1,Mode)),.SDcols=-1], 
    melt  = melt(DT, id.vars = 'id')[, .N, by = .(id, value)][, 
       value[which.max(N)], by = id], 
    melto  = melt(DT, id.vars = 'id')[, .N, by = .(id, value)][ 
       order(N)][,last(value),by=id], 
    meltMode = melt(DT, id.vars = 'id')[,Mode(value),by=id], 
    replications=10 
)[1:5] 
#  test replications elapsed relative user.self 
# 3 applyMode   10 2.42 8.643  2.36 
# 2 byMode   10 2.84 10.143  2.81 
# 4  melt   10 0.28 1.000  0.28 
# 6 meltMode   10 1.92 6.857  1.81 
# 5  melto   10 0.44 1.571  0.44 
# 1  table   10 0.83 2.964  0.81 

Похоже @ Eddi-х melt с which.max побед.

Данные.

DT <- 
    data.table(V1=paste("Day",1:5,sep="_"),V2=c(4,1,4,3,3),V3=c(4,1,5,4,2),V4=c(4,2,4,4,3)) 
3

Преобразовать в длинной форме, а затем это тривиально сделать:

dt <- data.table(id=paste("Day",1:5,sep="_"),V2=c(4,1,4,3,3),V3=c(4,1,5,4,2),V4=c(4,2,4,4,3)) 

melt(dt, id.vars = 'id')[, .N, by = .(id, value)][, value[which.max(N)], by = id] 
#  id V1 
#1: Day_1 4 
#2: Day_2 1 
#3: Day_3 4 
#4: Day_4 4 
#5: Day_5 3 

Это значительно быстрее, чем другие варианты до сих пор, до тех пор, как количество уникальных (id,value) пар не слишком велик.

Смежные вопросы