2014-09-18 2 views
3

я набор данных как этотR колонки означают фактором

data 
name v1 v2 v3 v4 v5 
a 1 2 7 9 3 
b 3 8 6 4 8 
c 2 5 0 1 9 
a 6 0 6 2 1 
c 3 9 4 7 5 

name является переменным фактором. Я хочу рассчитать среднее значение v2,v3,v4,v5 по коэффициенту data$name. Я использовал следующую команду, но это не сработало.

tapply(data[,3:6],data$name,mean) 

Теперь, я использовал следующий код

newdata<-0 
for (name in unique(data$name)){ 
    rowIndex <- which(data$name == name) 
    result <- colMeans(data[rowIndex,]) 
    newdata[name,]<-result 
} 

Требуемый результат получается. Но я хочу знать, есть ли какой-то гладкий метод для этого.

+1

Try 'библиотека (data.table); setDT (data) [, lapply (.SD, mean), by = name, .SDcols = paste0 ("v", 2: 5)] '(не тестировалось) –

+1

Ваш пример кода не работает. Можете ли вы опубликовать свой ожидаемый результат? – A5C1D2H2I1M1N2O1R2T1

+0

Я добавил ожидаемый результат в вопрос. – Prabhu

ответ

6

Вот еще один способ

library(data.table) 
cols <- paste0("v", 2:5) # set the columns you want to operate on 
setDT(data)[, Sums := rowSums(.SD), .SDcols = cols] 
data[, list(Means = sum(Sums)/(.N*length(cols))), by = name] 
## name Means 
## 1: a 3.75 
## 2: b 6.50 
## 3: c 5.00 

Редактировать

За @Aruns предположение, что было бы, вероятно, гораздо лучше

setDT(data)[, mean(c(v2,v3,v4,v5)), by=name] 
## name V1 
## 1: a 3.75 
## 2: b 6.50 
## 3: c 5.00 

Или за @Anandas предложение

library(reshape2) 
melt(setDT(data), id.vars = "name", measure.vars = cols)[, mean(value), by = name] 
## name V1 
## 1: a 3.75 
## 2: b 6.50 
## 3: c 5.00 
+2

Я не знаю компромисс между' .SD' и 'melt', но 'melt (setDT (data), id.vars =" name ", measure.vars = cols) [, mean (value), by = name]' возможно? – A5C1D2H2I1M1N2O1R2T1

+3

Или 'data [, mean (c (v2, v3, v4, v5)), by = name]'. Если есть больше столбцов, мы можем просто построить выражение и оценить его. – Arun

+1

@Arun, это аккуратно. Я пытался это сделать, но имел проблемы с именами столбцов. Наверное, потому что я использовал 'paste', и они стали цитироваться –

2

Редактировать: оригинальный ответ не дал правильного результата. Это, кажется, работает нормально (выберите (-переменными) позволяет избежать необходимости дополнительного столбца, но в противном случае не требуется)

Использование dplyr и reshape2 пакетов:

library(reshape2) 
library(dplyr) 
data %>% 
select(-v1) %>% 
melt %>% 
group_by(name) %>% 
select(-variable) %>% 
summarise_each(funs(mean)) 
# Source: local data frame [3 x 2] 
# 
# name value 
# 1 a 3.75 
# 2 b 6.50 
# 3 c 5.00 
+1

Это не даст желаемого результата –

+0

О, бог. Вы правы @DavidArenburg. Должен быть более осторожным (снова ...) в следующий раз. – ddiez

+0

ОК, изменили ответ и теперь он работает. Тем не менее, не знаю, как это выглядит ... – ddiez

4

Согласно ожидаемому результату показал:

т.е. The expected result for factor a is a (2+7+9+3)+(0+6+2+1)/8

sapply(split(dat[,-(1:2)], dat$name), function(x) sum(x)/prod(dim(x))) 
# a b c 
# 3.75 6.50 5.00 

Или

tapply(rowMeans(dat[,-(1:2)]), dat[,1], sum)/table(dat[,1]) 
#a b c 
#3.75 6.50 5.00 

Или

m1 <- as.matrix(dat[,-c(1:2)]) 
c(by(c(m1), dat[,1][row(m1)], FUN=mean)) 
# a b c 
#3.75 6.50 5.00 

Или методы предложены @Ananda Mahto

tapply(unlist(dat[-c(1, 2)]), rep(dat$name, 4), mean) 
    # a b c 
    #3.75 6.50 5.00 

    tapply(stack(dat, select = paste0("v", 2:5))$values, rep(dat$name, 4), mean) 
    # a b c 
    #3.75 6.50 5.00 
+0

(+1) Это аккуратно –

+0

@David Arenburg Спасибо Я дал +1 для вас за код данных. Я думаю, '4' является ncol (data), правильно? – akrun

+0

Да .. Это не так общее, как твое. Я думаю, чтобы предварительно определить имена столбцов в начале и затем сделать его более общим. Отредактировано соответственно –

3

Это может быть сделано с помощью комбинации пакетов dplyr и tidyr:

library(dplyr) 
library(tidyr) 

data %>% gather(name, value, v2:v5) %>% 
    group_by(name) %>% summarize(average=mean(value)) 
# name average 
# 1 a 3.75 
# 2 b 6.50 
# 3 c 5.00 

Это работает, потому что gather приносит v2:v5 колонны вместе в одну колонку, где они могут быть интуитивно сгруппированных:

data %>% gather(name, value, v2:v5) 
# name v1 name value 
# 1  a 1 v2  2 
# 2  b 3 v2  8 
# 3  c 2 v2  5 
# 4  a 6 v2  0 
# 5  c 3 v2  9 
# 6  a 1 v3  7 
# ...