如何基于因子变量的子集创建标准化排名列?

How to create a normalised rank column based on subset of factor variable?

数据框样本:

df <- structure(list(Rank = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), Year = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("2001", "2003", "2005", "2007", "2009", "2011", "2013", "2015", "2017"), class = "factor")), .Names = c("Rank", "Year"), row.names = c(NA, -44L), class = c("tbl_df", "tbl", "data.frame"))

我的数据框中有一个 "Rank" 向量,范围从 1 到 x,具体取决于 "Year" 中的因子值。我希望能够根据年份值对排名进行标准化,并将其放入新列中。

到目前为止,我正在使用此自定义函数在 0 和 1 之间进行归一化:

range01 <- function(x){(x-min(x))/(max(x)-min(x))}

我创建了一个用 NA 填充的新列。

df$normrank <- NA

然后我尝试生成 2001 年的规范化排名,但是这会在子集因子值的每一行中创建新规范化排名向量的副本,而不是将行中的规范化值与相应的旧匹配值。

df$normrank[which(df$Year==2001)] <- range01(subset(df, Year == 2001, select=Rank))

我不知道如何解决这个问题,希望得到任何帮助 - 可能使用另一个自定义函数?

使用dplyr的一个解决方案可以基于Year列上的group_by,然后应用归一化因子计算normrank

df %>% group_by(Year) %>%
  mutate(normrank  = (Rank - min(Rank)) / (max(Rank)+min(Rank)) )

# # Groups: Year [3]
# Rank Year   normrank
# <dbl> <fctr>    <dbl>
#   1  1.00 2001     0     
# 2  2.00 2001     0.0556
# 3  3.00 2001     0.111 
# 4  4.00 2001     0.167 
# 5  5.00 2001     0.222 
# 6  6.00 2001     0.278 
# 7  7.00 2001     0.333 
# 8  8.00 2001     0.389 
# 9  9.00 2001     0.444 
# 10 10.0  2001     0.500 
# # ... with 34 more rows

现在数据已准备好 filter Year