Получите сумму каждого n-го столбца для каждого человека и создайте новый фрейм данных в r

Поискав похожие посты, пишу свой вопрос. У меня есть ежемесячные переменные количества осадков за несколько лет для каждого участка. Мне нужно рассчитать среднемесячное количество осадков за несколько лет. Я дал простой фрейм данных следующим образом. Мне нужно создать новый фрейм данных, состоящий из среднемесячных значений (12) для каждого сайта.

d<-structure(list(ID = structure(1:4, .Label = c("A", "B", "C", 
"D"), class = "factor"), X2000_1 = c(25L, 42L, 74L, 52L), X2000_2 = c(15L, 
15L, 51L, 12L), X2000_3 = c(14L, 21L, 25L, 41L), X2000_4 = c(74L, 
4L, 23L, 51L), X2000_5 = c(15L, 25L, 65L, 12L), X2000_6 = c(31L, 
23L, 15L, 25L), X2001_1 = c(52L, 54L, 18L, 63L), X2001_2 = c(85L, 
165L, 12L, 12L), X2001_3 = c(25L, 36L, 20L, 14L), X2001_4 = c(1L, 
17L, 23L, 52L), X2001_5 = c(24L, 45L, 12L, 15L), X2001_6 = c(3L, 
23L, 45L, 52L)), .Names = c("ID", "X2000_1", "X2000_2", "X2000_3", 
"X2000_4", "X2000_5", "X2000_6", "X2001_1", "X2001_2", "X2001_3", 
"X2001_4", "X2001_5", "X2001_6"), class = "data.frame", row.names = c(NA, 
-4L))

Вывод должен быть таким;

df<-data.frame(id = c("A","B","C","D"))
df[c("jan","feb","mar","apr","may","jun")]<-NA

например, ячейка A1 должна содержать среднее количество осадков X2000_1 и X2001_1.

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

n = 6
unname(tapply(d, (seq_along(d)-1) %/% n, sum))

Имена столбцов моего фактического фрейма данных:

c("est", "X1990_1", "X1990_2", "X1990_3", "X1990_4", "X1990_5", 
"X1990_6", "X1990_7", "X1990_8", "X1990_9", "X1990_10", "X1990_11", 
"X1990_12", "X1991_1", "X1991_2", "X1991_3", "X1991_4", "X1991_5", 
"X1991_6", "X1991_7", "X1991_8", "X1991_9", "X1991_10", "X1991_11", 
"X1991_12", "X1992_1", "X1992_2", "X1992_3", "X1992_4", "X1992_5", 
"X1992_6", "X1992_7", "X1992_8", "X1992_9", "X1992_10", "X1992_11", 
"X1992_12", "X1993_1", "X1993_2", "X1993_3", "X1993_4", "X1993_5", 
"X1993_6", "X1993_7", "X1993_8", "X1993_9", "X1993_10", "X1993_11", 
"X1993_12", "X1994_1", "X1994_2", "X1994_3", "X1994_4", "X1994_5", 
"X1994_6", "X1994_7", "X1994_8", "X1994_9", "X1994_10", "X1994_11", 
"X1994_12", "X1995_1", "X1995_2", "X1995_3", "X1995_4", "X1995_5", 
"X1995_6", "X1995_7", "X1995_8", "X1995_9", "X1995_10", "X1995_11", 
"X1995_12", "X1996_1", "X1996_2", "X1996_3", "X1996_4", "X1996_5", 
"X1996_6", "X1996_7", "X1996_8", "X1996_9", "X1996_10", "X1996_11", 
"X1996_12", "X1997_1", "X1997_2", "X1997_3", "X1997_4", "X1997_5", 
"X1997_6", "X1997_7", "X1997_8", "X1997_9", "X1997_10", "X1997_11", 
"X1997_12", "X1998_1", "X1998_2", "X1998_3", "X1998_4", "X1998_5", 
"X1998_6", "X1998_7", "X1998_8", "X1998_9", "X1998_10", "X1998_11", 
"X1998_12", "X1999_1", "X1999_2", "X1999_3", "X1999_4", "X1999_5", 
"X1999_6", "X1999_7", "X1999_8", "X1999_9", "X1999_10", "X1999_11", 
"X1999_12", "X2000_1", "X2000_2", "X2000_3", "X2000_4", "X2000_5", 
"X2000_6", "X2000_7", "X2000_8", "X2000_9", "X2000_10", "X2000_11", 
"X2000_12")

person sriya    schedule 22.12.2016    source источник


Ответы (5)


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

# extract the months for each column
mon <- sub(".*_(\\d+)$", "\\1", names(d)[-1])

# split the data frame by columns and calculate the rowMeans
cbind.data.frame(d[1], lapply(split.default(d[-1], mon), rowMeans))

#  ID    1    2    3    4    5    6
#1  A 38.5 50.0 19.5 37.5 19.5 17.0
#2  B 48.0 90.0 28.5 10.5 35.0 23.0
#3  C 46.0 31.5 22.5 23.0 38.5 30.0
#4  D 57.5 12.0 27.5 51.5 13.5 38.5
person Psidom    schedule 22.12.2016
comment
когда решение используется для другого фрейма данных, аналогичного примеру, появляется сообщение об ошибке Error in base::rowMeans(x, na.rm = na.rm, dims = dims, ...) : 'x' должно быть числовой - person sriya; 22.12.2016
comment
Каковы имена столбцов ваших реальных данных? А также запустите lapply(d[-1], class), чтобы проверить, все ли столбцы, кроме ID, имеют числовой тип. - person Psidom; 22.12.2016
comment
В моих реальных данных все столбцы, кроме ID, имеют числовой тип. Я проверил это. Единственным отличием от примера является NA за несколько месяцев. - person sriya; 23.12.2016
comment
Вы можете удалить na, передав параметр na.rm в lapply, например cbind.data.frame(d[1], lapply(split.default(d[-1], mon), rowMeans, na.rm = TRUE)), но это не соответствует сообщению об ошибке. Вы также сказали, что mon не дает 1,..6, возможно, в этом проблема. Каковы настоящие имена столбцов? Может быть, у них есть несколько подчеркиваний _? - person Psidom; 23.12.2016
comment
Я проверил, но в именах столбцов нет ничего плохого, все одинаковые? - person sriya; 23.12.2016
comment
Он создается только для месяца 12, а все остальные месяцы, как в исходном названии. - person sriya; 23.12.2016
comment
Вы можете dput(names(d))? Мне любопытно, почему это произойдет. - person Psidom; 23.12.2016
comment
Я включил его в конце моего вопроса. Пожалуйста, посмотрите это. - person sriya; 23.12.2016
comment
Я заменил names(d) в первой строке вектором, который вы разместили, он возвращает "1", "2", ...."11", "12", как и ожидалось. - person Psidom; 23.12.2016
comment
d означает имя фрейма данных. Поэтому вместо этого, если я дал имя фрейма данных как d2, код должен быть «mon ‹- sub(.*_(\\d2+)$, \\1, имена (d2)[-1])». также интересно, почему он не дает 1,..., 12 - person sriya; 23.12.2016
comment
А, я вижу, в чем проблема. Я должен был объяснить лучше. Первый \\d+ является символом регулярного выражения, он обозначает цифры или [0-9] и не имеет ничего общего с именем фрейма данных, поэтому его следует оставить. Попробуйте вместо этого mon <- sub(".*_(\\d+)$", "\\1", names(d2)[-1]) или даже mon <- sub(".*_([0-9]+)$", "\\1", names(d2)[-1]) - person Psidom; 23.12.2016
comment
Большое спасибо. Теперь я понимаю ваш код, и он отлично работает. - person sriya; 23.12.2016

Вы также можете сделать это с помощью reshape для длинного набора данных вместе с табулированием:

tmp <- reshape(d, idvar="ID", sep="_", direction="long", varying=-1)
xtabs(rowMeans(cbind(X2000,X2001)) ~ ID + time, data=tmp)
#   time
#ID     1    2    3    4    5    6
#  A 38.5 50.0 19.5 37.5 19.5 17.0
#  B 48.0 90.0 28.5 10.5 35.0 23.0
#  C 46.0 31.5 22.5 23.0 38.5 30.0
#  D 57.5 12.0 27.5 51.5 13.5 38.5
person thelatemail    schedule 22.12.2016

Вот вариант использования Reduce с +

cbind(d[1], Reduce(`+`, list(d[2:7], d[8:13]))/2)
#    ID X2000_1 X2000_2 X2000_3 X2000_4 X2000_5 X2000_6
#1  A    38.5    50.0    19.5    37.5    19.5    17.0
#2  B    48.0    90.0    28.5    10.5    35.0    23.0
#3  C    46.0    31.5    22.5    23.0    38.5    30.0
#4  D    57.5    12.0    27.5    51.5    13.5    38.5

Или просто

cbind(d[1], (d[2:7] + d[8:13])/2)
person akrun    schedule 22.12.2016
comment
Как можно удалить NA при расчете здесь - person sriya; 22.12.2016
comment
@sriya Если есть NA, решение, предоставленное psidom или решением thelatemail, лучше, поскольку аргумент rowMeans имеет na.rm=TRUE - person akrun; 22.12.2016

Предполагая, что у нас есть первые столбцы как ID, а остальные все столбцы распределены поровну.

Можем ли мы просто разделить фрейм данных на две половины и получить среднее значение между ними.

cbind(d[1],(d[2:ceiling(ncol(d)/2)] + d[(ceiling(ncol(d)/2) + 1):ncol(d)])/2)


#   ID X2000_1 X2000_2 X2000_3 X2000_4 X2000_5 X2000_6
#1  A    38.5    50.0    19.5    37.5    19.5    17.0
#2  B    48.0    90.0    28.5    10.5    35.0    23.0
#3  C    46.0    31.5    22.5    23.0    38.5    30.0
#4  D    57.5    12.0    27.5    51.5    13.5    38.5

Очевидно, мы всегда можем обойтись жестким кодированием номеров столбцов.

cbind(d[1], (d[2:7] + d[8:13])/2)

Однако вышеупомянутый подход является обобщенным и будет работать, даже если у нас больше 13 столбцов.

person Ronak Shah    schedule 22.12.2016

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

person nikhil sharma    schedule 22.12.2016
comment
@Psidom, когда решение используется для другого фрейма данных, аналогичного примеру, появляется сообщение об ошибке Error in base::rowMeans(x, na.rm = na.rm, dims = dims, ...) : 'x' должен быть числовым. Я считаю, что это как-то связано с пн здесь. Потому что, когда вызывается mon, он создает не 1, 6, а исходные имена столбцов (X2000_1) - person sriya; 22.12.2016