2015-03-21 2 views
3

У меня есть dataframe с временными столбцами данных и началом года и конца года.Соответствует и суммирует dataframe в R

df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c(6, 56),y2008=c(64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005)) 

Для каждой строки я хочу рассчитать среднее значение в течение начального и конечного лет, а также до и после периода начала и окончания. Желаемый результат выглядит следующим образом:

y2000 y2001 y2002 y2003 y2004 y2005 y2006 y2007 y2008 y2009 y2010 startyear endyear before_mean within_mean after_mean 
12 234 3434 36 6 56 43 6 64 63 65 2006 2009 629.6666667  44 65 
636 76 46 35 64 65 65 56 66 5656 54 2001 2005 636 57.2  1179.4 

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

ответ

3

1. dplyr/tidyr

Это может быть лучше, чтобы преобразовать 'широкий' формат в формат 'длинных'. Мы могли бы использовать dplyr/tidyr, чтобы получить mean. Создайте столбец «ind», измените данные на «длинный» с помощью gather, разделите столбец «переменная» на два столбца («var1», «var2») с помощью extract, группу «ind», получите значения mean столбец «значение» после того, как Подменю он основан на другой логический индекс, созданный (т.е. var2 < startyear, var2 >= startyear & var2 <= endyear и var2 >endyear)

library(dplyr) 
library(tidyr) 

dS <- df %>% 
      mutate(ind=row_number()) %>% 
      gather(variable, value, starts_with('y')) %>% 
      extract(variable, c('var1', 'var2'), '([^0-9]+)([0-9]+)', 
         convert=TRUE) %>% 
      group_by(ind) %>% 
      summarise(before_mean= mean(value[var2 < startyear]), 
        within_mean = mean(value[var2 >= startyear & 
              var2 <= endyear]), 
        after_mean=mean(value[var2 >endyear])) %>% 
     as.data.frame() 

nm1 <- paste(c('before', 'within', 'after'), 'mean', sep="_") 
dS 
# ind before_mean within_mean after_mean 
#1 1 629.6667  44.0  65.0 
#2 2 636.0000  57.2  1179.4 

Мы можем создать дополнительные столбцы в «ДФ» из вышеприведенного вывода

df[nm1] <- dS 

2. основание R

Мы можем использовать методы base R и без изменения формата набора данных. Из исходного набора данных ('df') создайте индекс ('indx') числовых имен столбцов, удалите нечисловую часть и преобразуйте в числовой ('v1').

indx <- grep('\\d+', names(df)) 
v1 <- as.numeric(sub('[^0-9]+', '', names(df)[indx])) 

Петля строки 'ДФ' (lapply), match 'StartYear' с 'v1', используйте этот индекс ('i1'), чтобы получить столбцы, unlist и вычислить mean. То же самое можно сделать, сопоставив «endyear» с «v1», чтобы получить индекс («i2»). Основываясь на 'i1' и 'i2', вычислите 'inside_mean' и 'after_mean'. rbind элементы списка и назначить вывод новым столбцам ('nm1') в 'df'.

df[nm1] <- do.call(rbind,lapply(1:nrow(df), function(i) { 
     i1 <- match(df$startyear[i], v1) 
     before_mean<- mean(unlist(df[i,1:(i1-1),drop=FALSE])) 
     i2 <- match(df$endyear[i], v1) 
     within_mean <- mean(unlist(df[i,i2:i1])) 
     after_mean <- mean(unlist(df[i,match(v1[(i2+1):length(v1)],v1)])) 
     data.frame(before_mean,within_mean, after_mean) })) 
df[nm1] 
# before_mean within_mean after_mean 
#1 629.6667  44.0  65.0 
#2 636.0000  57.2  1179.4 
1

Вот решение:

#The original data: 
df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c(6, 56),y2008=c(64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005)) 

df$s = df$startyear - 1999 
df$e = df$endyear - 1999 
df$before_mean <- apply(df, 1, function(x)sum(x[1:(x[14]-1)])) 
df$within_mean <- apply(df, 1, function(x)sum(x[x[14]:x[15]])) 
df$after_mean <- apply(df, 1, function(x)sum(x[(x[15]+1):11])) 
df$s <- NULL 
df$e <- NULL 

Это решение связано с точным лет, как в примере, но это не будет слишком сложно, чтобы сделать его более универсальным.

3

Другой подход, чем akrun's, также используя Base R. Мы создадим промежуточную переменную в том же порядке, что и имена столбцов, но имеющие численный формат. Это будет использоваться для обозначения столбцов фактического dataframe:

col.years <- suppressWarnings(as.numeric(sub("^y", "", colnames(df))))[1:11] 

# Initialise everything to NA (better when preparing to loop over df)   
df$before_mean <- NA 
df$within_mean <- NA 
df$after_mean <- NA 

for(i in seq_len(nrow(df))) { 
    df$before_mean[i] <- mean(as.numeric(df[i, which(col.years < df$startyear[i])])) 
    df$within_mean[i] <- mean(as.numeric(df[i, which((col.years >= df$startyear[i]) & (col.years <= df$endyear[i]))])) 
    df$after_mean[i] <- mean(as.numeric(df[i, which(col.years > df$endyear[i])])) 
} 

Результаты

df[,14:16] 

# before_mean within_mean after_mean 
# 1 629.6667  44.0  65.0 
# 2 636.0000  57.2  1179.4