首页 > 解决方案 > 字符变量未排序

问题描述

tablecrt %>%
  pivot_longer(Q1.Op:Q22.Buy, "q", "val") %>%
  mutate(val = factor(val, levels = 9:1 )) %>% 
  tabyl(val, product.or.block, q, show_na = TRUE)

输出正在以这种格式打印

Q1.Op    
Q10.JAR    
Q12.Af     
Q21.ex             
Q3.Opi             
Q4.JARaro        

因为,您可以看到问题没有以正确的方式排序。我想把它作为

Q1.Op             
Q3.Opi            
Q4.JARaro           
Q10.JAR           
Q12.Af  

提前致谢。

标签: r

解决方案


它被正确排序:它是按字母顺序正确的。如果您想根据任意子字符串的整数转换进行排序,那么您需要这样做,语言不会为您猜测。

要将带有数字的任何内容作为数字进行排序,可能类似于:

numrank <- function(z, ...) rank(as.integer(sapply(regmatches(z, gregexpr("\\d+", z)), `[`, 1)), ...)
vec <- c("Q1.Op","Q10.JAR","Q12.Af","Q21.ex","Q3.Opi","Q4.JARaro","QZ")

tibble(v = vec) %>%
  arrange(numrank(v, na.last=FALSE))
# # A tibble: 7 x 1
#   v        
#   <chr>    
# 1 QZ       
# 2 Q1.Op    
# 3 Q3.Opi   
# 4 Q4.JARaro
# 5 Q10.JAR  
# 6 Q12.Af   
# 7 Q21.ex   

还支持的是ties.method=...,请参阅?rank

快速浏览“code-golfy”功能(正如@qdread 对其进行分类,我认为这是一个公平的标签)。如果我们debugonce(numrank)运行一次,我们可以分解不同的部分。

  • 首先,gregexpr旨在从字符串中识别和提取模式;它的返回仅仅是索引向量的列表(及其“长度”):

    z
    # [1] "Q1.Op"     "Q10.JAR"   "Q12.Af"    "Q21.ex"    "Q3.Opi"    "Q4.JARaro" "QZ"       
    str(gregexpr("\\d+", z))
    # List of 7
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 1
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 2
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 2
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 2
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 1
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int 2
    #   ..- attr(*, "match.length")= int 1
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    #  $ : int -1
    #   ..- attr(*, "match.length")= int -1
    #   ..- attr(*, "index.type")= chr "chars"
    #   ..- attr(*, "useBytes")= logi TRUE
    

    这很多,但请注意,第一个int 2表示匹配的子字符串从字符串位置 2 开始,这"match.length"= int 1意味着第一个是一个字符长。向前跳到最后,看到int -1,表示没有找到该模式。这是有道理的。

  • regmatches(z, ...)用于从gregexpr.

    str(regmatches(z, gregexpr("\\d+", z)))
    # List of 7
    #  $ : chr "1"
    #  $ : chr "10"
    #  $ : chr "12"
    #  $ : chr "21"
    #  $ : chr "3"
    #  $ : chr "4"
    #  $ : chr(0) 
    

    请注意(再次)最后一个长度为 0,这是预期的。(如果正则表达式中有多个模式组,那么这些列表元素中的每一个都可能更长。)

  • sapply(..., `[`, 1)是从列表的每个组件中提取第一个元素的技巧,一个不错的功能是,如果元素的内容长度为 0,则返回NA,这实际上是我们在这里工作所需要的。最终,我们希望 this 的返回是一个character 向量(不是list),只要输入。

    sapply(regmatches(z, gregexpr("\\d+", z)), `[`, 1)
    # [1] "1"  "10" "12" "21" "3"  "4"  NA  
    
  • as.integer应该是不言自明的。(如果您有浮点数,则需要更新正则表达式,这将更改为as.numeric。)

  • 输出需要能够指示元素的相对等级,因此我们只需将此向量传递给rank,以及用户可能想要的任何其他参数。例如,na.last=将无编号元素推到行的前面(false)或末尾(true);并ties.method=处理连续的相同数量的元素。


推荐阅读