2015-12-01 110 views
0

因此,我有一个值在一定范围内的列(请参见下文)。我已经使用aggregate()获得了每个范围的平均值。但是,当我尝试为每个值应用这个平均值时,我得到一个错误。例如,对于是1900-1910范围内的每个值,我想我的平均该范围出现在该行中,在我的“平均”列为范围内的每个值应用一个数字

我能得到什么:

Range  Avg 
1900-1910 15.33 
1911-1920 6.67 
.... 
1941-1950 22.00 

旺旺:

Value Year Range  Avg 
12 1906 1900-1910 15.33 
15 1909 1900-1910 15.33 
7  1911 1911-1920 6.67 
22 1950 1941-1950 22.00 
4  1917 1911-1920 6.67 
9  1917 1911-1920 6.67 
19 1902 1900-1910 15.33 

我能够得到平均每个范围,但我无法弄清楚如何为应用范围的平均到每个特定的值。我唯一能想到的就是一堆嵌套的ifelse()语句,但这似乎太乏味。例如:

d$Avg<-ifelse(Range=="1900-1910",15.33, 
     ifelse(Range=="1911-1920",6.67, 
     ...etc)) 

有没有一种方法,我可以加速这一进程,而不是使用嵌套ifelse语句一堆的?

回答

2

解决方法是将聚合数据视为查找表,然后使用merge获取所需的数据集。

所以,如果累计的数据是lookupdf,那么我们就可以用merge这样的:

final_df <- merge(d, lookupdf, by=c("Range")) 

示例代码,以证明这一点:

d <- data.frame(Year=rep(1900+c(1:20), 20), 
      Value=runif(400, 1, 20)) 

d$Range <- ifelse(d$Year <= 1910, "1900-1910", "1911-1920") 

library(dplyr) 
# generate the aggregation; should be same as what you have above. 
lookupdf <- d %>% group_by(Range) %>% summarise(Avg=mean(Value)) 

# base R version 
final_df <- merge(d, lookupdf, by=c("Range")) 

输出:

> head(final_df[final_df$Year %in% c(1910, 1911),]) 
    Year  Value  Range  Avg 
10 1910 18.643543 1900-1910 11.17740 
11 1911 1.142544 1911-1920 10.18118 
30 1910 11.187802 1900-1910 11.17740 
31 1911 9.887889 1911-1920 10.18118 
50 1910 5.316916 1900-1910 11.17740 
51 1911 15.365103 1911-1920 10.18118 
1

我知道你明确表达了避免嵌套ifelse陈述的愿望,所以原谅我在这里使用一个陈述。但在我的辩护中,我们有一个解决方案,基本上重复使用相同的ifelse创建RangeAvg列,使用apply函数。我们还可以通过dplyr快速获得平均值。

该解决方案还假设你只有ValueYear,首先,因为我真的不知道你是怎么到你的地方,例如,创造了Range列。所以我从头开始。

首先写一个函数定义Range

library(dplyr) 

get_range <- function(number){ #<-- takes in percentile 
    ans <- 
    if ((number >= 1900) & (number <= 1910)) { 
     "1900-1910" 
    } else if ((number > 1910) & (number <= 1920)) { 
     "1911-1920" 
    } else if ((number > 1920) & (number <= 1930)) { 
     "1921-1930" 
    } else if ((number > 1930) & (number <= 1940)) { 
     "1931-1940" 
    } else if ((number > 1940) & (number <= 1950)) { 
     "1941-1950" 
    } else if ((number > 1950) & (number <= 1960)) { 
     "1951-1960" 
    } else if ((number > 1960) & (number <= 1970)) { 
     "1961-1970" 
    } else if ((number > 1970) & (number <= 1980)) { 
     "1971-1980" 
    } else if ((number > 1980) & (number <= 1990)) { 
     "1981-1990" 
    } else if ((number > 1990) & (number <= 2000)) { 
     "1991-2000" 
     } else { 
     "NA" 
    } 
    return(ans) 
} 

然后,应用它:

df$Range <- sapply(df$Year, function(x) get_range(x)) 

接下来,使用dplyr获得在一个单独的数据帧的聚合值和存储。

df_Avg <- df %>% 
    group_by(Range) %>% 
    summarise(Avg = mean(Value)) 

修改同样的功能上面取平均值

get_avg <- function(number){ 
    ans <- 
    if ((number >= 1900) & (number <= 1910)) { 
     df_Avg$Avg[1] 
    } else if ((number > 1910) & (number <= 1920)) { 
     df_Avg$Avg[2] 
    } else if ((number > 1920) & (number <= 1930)) { 
     df_Avg$Avg[3] 
    } else if ((number > 1930) & (number <= 1940)) { 
     df_Avg$Avg[4] 
    } else if ((number > 1940) & (number <= 1950)) { 
     df_Avg$Avg[5] 
    } else if ((number > 1950) & (number <= 1960)) { 
     df_Avg$Avg[6] 
    } else if ((number > 1960) & (number <= 1970)) { 
     df_Avg$Avg[7] 
    } else if ((number > 1970) & (number <= 1980)) { 
     df_Avg$Avg[8] 
    } else if ((number > 1980) & (number <= 1990)) { 
     df_Avg$Avg[9] 
    } else if ((number > 1990) & (number <= 2000)) { 
     df_Avg$Avg[1] 
    } else { 
     "NA" 
    } 
    return(ans) 
} 

的照顾......最后,应用功能。

df$Avg <- sapply(df$Year, function(x) get_avg(x)) 

应该给你这样的:

> df 
    Value Year  Range  Avg 
1  12 1906 1900-1910 15.333333 
2  15 1909 1900-1910 15.333333 
3  7 1911 1911-1920 6.666667 
4  22 1950 1941-1950 12.500000 
5  4 1917 1911-1920 6.666667 
6  9 1917 1911-1920 6.666667 
7  19 1902 1900-1910 15.333333 
8  1 1921 1921-1930 1.000000 
9  2 1931 1931-1940 2.000000 
10  3 1941 1941-1950 12.500000 
11  4 1951 1951-1960 4.000000 
12  5 1961 1961-1970 5.000000 
13  6 1971 1971-1980 6.000000 
14  7 1981 1981-1990 7.000000 
15  8 1991 1991-2000 15.333333 

我相信你可以做到这一点更快,用更少的代码,但作为交换条件,这是相当可读的,你可以将它交给你的同事不得不做大量的评论。

相关问题