对范围内的每个值应用一个数字



所以我有一列值,这些值在特定的年份范围内(见下文)。我已经使用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来创建RangeAvg列,并使用application函数。我们还可以用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

我相信你可以用更少的代码更快地完成这项工作,但作为交换,这是相当可读的,你可以把它交给你的同事,而不必做大量的评论。

最新更新