如何将值变成变量,并根据它们的等级给它们赋值?

How to turn values into variables and assign them a value according to their rank?

给定一个这样的数据框:

df <- data.frame(ID = seq(1,8), 
rank1 = c("apple", "NA", "banana", "kiwi", "peach", "kiwi", "kiwi", "grape"), 
rank2 = c('mango', 'NA', 'date', 'grape', 'kiwi', 'apple', 'pear', 'NA'), 
rank3 = c('kiwi', 'NA', 'apple ', 'peach', 'banana', 'NA', 'mango', 'NA'))

ID  rank1 rank2  rank3  
1  1  apple mango   kiwi  
2  2     NA    NA     NA  
3  3 banana  date apple   
4  4   kiwi grape  peach  
5  5  peach  kiwi banana  
6  6   kiwi apple     NA

可不可以把值变成变量,按照等级赋值?

我想要这样的输出:

  ID apple mango  kiwi banana  date grape peach pear 
1  1 rank1 rank2 rank3     NA    NA    NA    NA   NA  
2  2    NA    NA    NA     NA    NA    NA    NA   NA  
3  3 rank3    NA    NA  rank1 rank2    NA    NA   NA  
4  4    NA    NA rank1     NA    NA rank2 rank3   NA  
5  5    NA    NA rank2  rank3    NA    NA rank1   NA  
6  6 rank2    NA rank1     NA    NA    NA    NA   NA

如何使用以下公式为排名位置分配权重:n-r+1(n = 标准数量,r = 排名位置)?

一种方法是从原始数据框重塑为更长的格式,然后重塑为宽格式并切换变量。

library(tidyr)
library(dplyr)

#pivot longer
dfl <- pivot_longer(df, starts_with("rank"), names_to="rank", values_to = "fruit")

#clean up data
dfl$fruit <- trimws(dfl$fruit) 
#dfl <- dfl[dfl$fruit != "NA",]  #optional

#reshape wider
pivot_wider(dfl, ID, names_from = "fruit", values_from = "rank", values_fn = first)
# # A tibble: 8 x 10
#    ID apple mango kiwi  `NA`  banana date  grape peach pear 
# <int> <chr> <chr> <chr> <chr> <chr>  <chr> <chr> <chr> <chr>
#     1     1 rank1 rank2 rank3 NA    NA     NA    NA    NA    NA   
#     2     2 NA    NA    NA    rank1 NA     NA    NA    NA    NA   
#     3     3 rank3 NA    NA    NA    rank1  rank2 NA    NA    NA   
#     4     4 NA    NA    rank1 NA    NA     NA    rank2 rank3 NA   
#     5     5 NA    NA    rank2 NA    rank3  NA    NA    rank1 NA   
#     6     6 rank2 NA    rank1 rank3 NA     NA    NA    NA    NA   
#     7     7 NA    rank3 rank1 NA    NA     NA    NA    NA    rank2
#     8     8 NA    NA    NA    rank2 NA     NA    rank1 NA    NA    

因为我在 pivot_wider 函数中使用了 first 函数。是 select 第一个实例,以防 ID 中有多个,原始数据的第二行就是这种情况。

注意: 'NA' 列需要删除。

我相信这个 dplyr/tidyr 管道计算 ranks 但不是问题中提到的 weights

library(tidyverse)

df %>%
  pivot_longer(
    cols = starts_with('rank'),
    names_to = 'rank',
    values_to = 'fruit'
  ) %>%
  mutate(rank = as.integer(sub('^rank', '', rank)),
         fruit = trimws(fruit)) %>%
  filter(!is.na(fruit), fruit != 'NA') %>%
  pivot_wider(
    id_cols = ID,
    names_from = fruit,
    values_from = rank
  )
## A tibble: 7 x 9
#     ID apple mango  kiwi banana  date grape peach  pear
#  <int> <int> <int> <int>  <int> <int> <int> <int> <int>
#1     1     1     2     3     NA    NA    NA    NA    NA
#2     3     3    NA    NA      1     2    NA    NA    NA
#3     4    NA    NA     1     NA    NA     2     3    NA
#4     5    NA    NA     2      3    NA    NA     1    NA
#5     6     2    NA     1     NA    NA    NA    NA    NA
#6     7    NA     3     1     NA    NA    NA    NA     2
#7     8    NA    NA    NA     NA    NA     1    NA    NA

这是使用 stack + reshape

的基础 R 选项
dfout <- reshape(
  subset(
    cbind(stack(df[-1]), id = df$ID),
    values != "NA"
  ),
  direction = "wide",
  idvar = "id",
  timevar = "values"
)

dfout <- setNames(dfout,gsub("ind\.","",names(dfout)))

这给出了

   id apple banana  kiwi peach grape mango  date  pear apple
1  1 rank1   <NA> rank3  <NA>  <NA> rank2  <NA>  <NA>   <NA>
3  3  <NA>  rank1  <NA>  <NA>  <NA>  <NA> rank2  <NA>  rank3
4  4  <NA>   <NA> rank1 rank3 rank2  <NA>  <NA>  <NA>   <NA>
5  5  <NA>  rank3 rank2 rank1  <NA>  <NA>  <NA>  <NA>   <NA>
6  6 rank2   <NA> rank1  <NA>  <NA>  <NA>  <NA>  <NA>   <NA>
7  7  <NA>   <NA> rank1  <NA>  <NA> rank3  <NA> rank2   <NA>
8  8  <NA>   <NA>  <NA>  <NA> rank1  <NA>  <NA>  <NA>   <NA>