在 R 中越来越多地将多列重新编码为数字

use*_*330 3 r dataframe dplyr

我有 50 列名称,但为了方便起见,这里我只提供了 4 列。

Name1       Name2         Name3      Name4
Rose,Ali    Van,Hall      Ghol,Dam   Murr,kate
Camp,Laura  Ka,Klo        Dan,Dan    Ali,Hoss
Rose,Ali    Van,Hall      Ghol,Dam   Kol,Kan
Murr,Kate   Ismal, Ismal  Sian,Rozi  Nas,Ami
Ghol,Dam    Ka,Klo        Rose,Ali   Nor,Ko
Murr,Kate   Ismal, Ismal  Dan,Dan    Nas,Ami
Run Code Online (Sandbox Code Playgroud)

我想根据列(数字序列)为每个人分配数字。

例如,在名称 1 中,我们获取 1-4 之间的数字。重复的名字将得到相同的数字。

在名称2中,应该从5开始,依此类推。这会给我下表:

Assign1 Assian2 Assian3 Assian4
      1       5       8      12
      2       6       9      13
      1       5       8      14
      3       7      10      15
      4       6      11      17
      3       7       9      15
Run Code Online (Sandbox Code Playgroud)

我希望它没有循环,即,,sapply即,sapply(dat, function(x) match(x, unique(x)))

使用dplyrortidyverse会很棒。

Dar*_*sai 11

tidyverse解决方案purrr::accumulate()

library(tidyverse)

df %>%
  mutate(as_tibble(
    accumulate(across(Name1:Name4, ~ match(.x, unique(.x))), ~ .y + max(.x))
  ))

#   Name1 Name2 Name3 Name4
# 1     1     5     8    12
# 2     2     6     9    13
# 3     1     5     8    14
# 4     3     7    10    15
# 5     4     6    11    16
# 6     3     7     9    15
Run Code Online (Sandbox Code Playgroud)

  • 很不错。这个答案得到了我的投票。 (4认同)

All*_*ron 5

由于每列中的值取决于前一列中的值,因此必须按顺序进行计算。这可能是通过循环最简洁地实现的。请记住,lapplyandsapply只是变相的循环,并且不会比显式循环更快。

请注意,您的预期输出有一个错误(数字 17 应该是 16)

output <- setNames(df, paste0('Assign', seq_along(df)))
                   
for(i in seq_along(output)) {
  output[[i]] <- match(output[[i]], unique(output[[i]]))
  if(i > 1) output[[i]] <- output[[i]] + max(output[[i - 1]])
}

output
#>    Assign1  Assign2  Assign3  Assign4
#> 1        1        5        8       12
#> 2        2        6        9       13
#> 3        1        5        8       14
#> 4        3        7       10       15
#> 5        4        6       11       16
#> 6        3        7        9       15
Run Code Online (Sandbox Code Playgroud)

编辑

如果你真的想要它而不需要显式循环,你可以这样做:

res <- sapply(seq_along(df), \(i) match(df[[i]], unique(df[[i]]))) 
res + t(replicate(nrow(df), head(c(0, cumsum(apply(res, 2, max))), -1))) |>
  as.data.frame() |>
  setNames(paste0('Assign', seq_along(df)))
#>   Assign1 Assign2 Assign3 Assign4
#> 1       1       5       8      12
#> 2       2       6       9      13
#> 3       1       5       8      14
#> 4       3       7      10      15
#> 5       4       6      11      16
#> 6       3       7       9      15
Run Code Online (Sandbox Code Playgroud)

创建于 2023-01-13,使用reprex v2.0.2


以可重现的格式从问题中获取数据

df <- structure(list(Name1 = c("Rose,Ali", "Camp,Laura", "Rose,Ali", 
"Murr,Kate", "Ghol,Dam", "Murr,Kate"), Name2 = c("Van,Hall", 
"Ka,Klo", "Van,Hall", "Ismal, Ismal", "Ka,Klo", "Ismal, Ismal"
), Name3 = c("Ghol,Dam", "Dan,Dan", "Ghol,Dam", "Sian,Rozi", 
"Rose,Ali", "Dan,Dan"), Name4 = c("Murr,kate", "Ali,Hoss", "Kol,Kan", 
"Nas,Ami", "Nor,Ko", "Nas,Ami")), row.names = c(NA, -6L), 
class = "data.frame")
Run Code Online (Sandbox Code Playgroud)