所以我有一列值,这些值在特定的年份范围内(见下文)。我已经使用aggregate()得到了每个范围的平均值。但是,当我尝试将这个平均数应用于每个值时,我会得到一个错误。例如,对于1900-1910范围内的每个值,我希望该范围的平均值出现在该行的"Avg"列下
我能得到的:
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
我可以得到每个范围的平均值,但我不知道如何将该范围的Avg应用于每个特定值。我唯一能想到的就是一堆嵌套的ifelse()语句,但这似乎太乏味了。例如:
d$Avg<-ifelse(Range=="1900-1910",15.33,
ifelse(Range=="1911-1920",6.67,
...etc))
有没有一种方法可以加快这个过程,而不是使用一堆嵌套的ifelse语句?
解决方案是将聚合数据视为查找表,然后使用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
我知道您明确表示希望避免嵌套的ifelse语句,所以请原谅我在这里使用了一个。但在我的辩护中,我们有一个解决方案,该解决方案本质上重用相同的ifelse
来创建Range
和Avg
列,并使用application函数。我们还可以用dplyr
快速取平均值。
这个解决方案还假设您一开始只有Value
和Year
,因为我真的不确定您是如何到达现在的位置的,例如,创建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
我相信你可以用更少的代码更快地完成这项工作,但作为交换,这是相当可读的,你可以把它交给你的同事,而不必做大量的评论。