【问题标题】:How to assign numbers to names using in R如何在 R 中为名称分配数字
【发布时间】:2023-01-13 20:01:29
【问题描述】:

我有 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

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

例如,在 Name 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

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

使用 dplyr 或 tidyverse 会很棒。

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

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

    请注意,您的预期输出中有一个错误(数字 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
    

    编辑

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

    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
    

    创建于 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")
    

    【讨论】:

    • 谢谢你,艾伦,我对循环不感兴趣,抱歉。
    • 好的@user330 - 我添加了一个非循环替代方案。在我看来,它比循环更复杂且效率更高,但它可以满足您在问题中的要求。
    【解决方案2】:

    更短的方法可能是:

    colnames(df) <- map(seq(ncol(df)), function(n) paste0('assign', n))
    

    【讨论】:

    • 这只会更改数据框的名称;它不执行 OP 想要的计算。
    【解决方案3】:

    这是一个tidyverse 方法:

    首先paste所有列中每个字符串之后的列名,以便稍后进行排序。然后pivot将其放入一个两列的df中,这样我们就可以通过match为他们分配ID。最后pivot它回到宽格式并取消嵌套列表列。

    library(tidyverse)
    
    df %>% 
      mutate(across(everything(), ~ paste0(.x, "_", cur_column()))) %>% 
      pivot_longer(everything(), names_to = "ab", values_to = "a") %>% 
      arrange(ab) %>% 
      mutate(b = match(a, unique(a)), .keep = "unused") %>% 
      pivot_wider(names_from = "ab", values_from = "b") %>% 
      unnest(everything())
    
    # A tibble: 6 × 4
      Name1 Name2 Name3 Name4
      <int> <int> <int> <int>
    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
    

    数据

    取自@Allan Cameron。

    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")
    

    【讨论】:

      猜你喜欢
      • 2020-12-12
      • 2017-02-13
      • 2015-09-16
      • 2014-11-01
      • 2015-09-17
      • 1970-01-01
      • 2016-05-12
      • 2013-11-03
      • 1970-01-01
      相关资源
      最近更新 更多