пакет plyr, записывающий одну и ту же функцию в несколько столбцов

Я хочу написать одну и ту же функцию для нескольких столбцов, используя функцию ddply, но я пытался писать их в одну строку, хочу посмотреть, есть ли лучший способ сделать это?

Вот простая версия данных:

data<-data.frame(TYPE=as.integer(runif(20,1,3)),A_MEAN_WEIGHT=runif(20,1,100),B_MEAN_WEIGHT=runif(20,1,10))

и я хочу узнать сумму столбцов A_MEAN_WEIGHT и B_MEAN_WEIGHT, выполнив следующие действия:

ddply(data,.(TYPE),summarise,MEAN_A=sum(A_MEAN_WEIGHT),MEAN_B=sum(B_MEAN_WEIGHT))

но в моих текущих данных у меня более 8 "*_MEAN_WEIGHT", и я устал писать их 8 раз, например

ddply(data,.(TYPE),summarise,MEAN_A=sum(A_MEAN_WEIGHT),MEAN_B=sum(B_MEAN_WEIGHT),MEAN_C=sum(C_MEAN_WEIGHT),MEAN_D=sum(D_MEAN_WEIGHT),MEAN_E=sum(E_MEAN_WEIGHT),MEAN_F=sum(F_MEAN_WEIGHT),MEAN_G=sum(G_MEAN_WEIGHT),MEAN_H=sum(H_MEAN_WEIGHT))

Есть ли лучший способ написать это? Спасибо за помощь!!


person linp    schedule 18.04.2013    source источник


Ответы (2)


Подход, ориентированный на plyr, заключается в использовании colwise

eg

 ddply(data, .(TYPE), colwise(sum))
  TYPE A_MEAN_WEIGHT B_MEAN_WEIGHT
1    1      319.8977      60.80317
2    2      621.6745      37.05863

Вы можете передать имена столбцов в качестве аргумента .col, если вам нужно только подмножество

Вы также можете использовать numcolwise или catcolwise для работы только с числовыми или категориальными столбцами.

обратите внимание, что вы можете использовать sapply вместо самого простого использования colwise

ddply(data, .(TYPE), sapply, FUN = 'mean') 

Идиоматический подход data.table заключается в использовании lapply(.SD, fun)

eg

dt <- data.table(data)
dt[,lapply(.SD, sum) ,by = TYPE]
   TYPE A_MEAN_WEIGHT B_MEAN_WEIGHT
1:    2      621.6745      37.05863
2:    1      319.8977      60.80317
person mnel    schedule 18.04.2013
comment
Спасибо @mnel! еще один вопрос, кажется, я не могу написать это так ddply(data, .(TYPE),colwise(sum,.(A_MEAN_WEIGHT)),colwise(sqrt,.(B_MEAN_WEIGHT))), так что если я хотите две разные функции для нескольких столбцов, мне нужно написать их дважды? - person linp; 19.04.2013

Попробуй это:

ddply(data, .(TYPE), colSums)

Вот (более медленный) эквивалент вышеизложенного, который можно настроить так, чтобы вместо суммирования использовалась любая функция:

ddply(data, .(TYPE), function(x) {apply(x, 2, sum)})

И если вы хотите сохранить столбец .(TYPE), подойдет что-то вроде этого:

ddply(data, .(TYPE), function(x) {apply(x[,names(x) != "TYPE"], 2, sum)})

А еще лучше используйте data.table вместо plyr:

library(data.table)
dt = data.table(data)

# just sums
dt[, data.table(t(colSums(.SD))), by = TYPE]

# sum for "A" and "B", and sqrt(sum) for "C" and "D"
# note: you will have to call setnames() to fix the column names after
dt[, data.table(t(colSums(.SD[, c("A_MEAN_WEIGHT", "B_MEAN_WEIGHT"), with = F])),
                t(apply(.SD[, c("C_MEAN_WEIGHT", "D_MEAN_WEIGHT"), with = F],
                        2, function(x) sqrt(sum(x))))),
     by = TYPE]
person eddi    schedule 18.04.2013
comment
Работает отлично! Спасибо @эдди!! - person linp; 18.04.2013
comment
Эмм... дополнительный вопрос, что, если у меня есть 16 столбцов, и я хочу сделать сумму для 8 из них и sqrt (сумма) для остальных 8.... - person linp; 18.04.2013
comment
Вы могли бы, например. запустите приведенную выше команду дважды - один раз с каждой функцией и фильтрацией по нужным столбцам (например, выполнив names(x) %in% c("column_a", "column_b", ...) в apply или по номеру столбца или что-то еще, что подходит для ваших данных), а затем cbind результат - person eddi; 18.04.2013
comment
В качестве альтернативы вы можете запустить dt[, ...] бизнес дважды, используя разные значения для .SDcols каждый раз, а затем cbind результат, если вы понимаете, что я имею в виду ... - person Steve Lianoglou; 19.04.2013
comment
Не используйте colSums для data.table или apply - оба будут преобразованы в матрицу внутри, и поэтому неэффективны. - person mnel; 19.04.2013
comment
Не используйте colSums и не применяйте к data.frame. - person mnel; 19.04.2013
comment
@mnel в моих тестах dt[, colSums(.SD)] примерно на 10% быстрее, чем dt[, lapply(.SD, sum)], поэтому я не думаю, что ваш комментарий верен. - person eddi; 19.04.2013
comment
Это может не укусить, когда вы имеете дело с небольшими наборами данных. Но взгляните на исходный код каждой функции и проведите бенчмаркинг с большими данными. - person mnel; 20.04.2013
comment
достаточно честно, запуская больше проверок, действительно colSums быстрее на меньших данных, но становится медленнее с большими данными - person eddi; 20.04.2013