代码之家  ›  专栏  ›  技术社区  ›  Luks

单数和双数在字符串中的均匀使用

  •  3
  • Luks  · 技术社区  · 7 年前

    我有一个非常大的data.table,其中(大量)项由字符串(包括文本和数字)定义。

    library(data.table)    
    dd <- data.table(x = c("A4","A4","A4","A14","A14","A14","B4","B4","B4"),y = c("A4","A14","B4","A4","A14","B4","A4","A14","B4"), z = c(1,2,3,4,5,6,7,8,9))
    
    x   y   z
    A4  A4  1
    A4  A14 2
    A4  B4  3
    A14 A4  4
    A14 A14 5
    A14 B4  6
    B4  A4  7
    B4  A14 8
    B4  B4  9
    

    数字可以是一位数或两位数 因此r总是根据数字中的第一个数字来排序(a14在a4之前)。mixedsort可以处理这个问题。但是,当我将长数据重塑为宽数据时

    wide <- dcast(dd, x ~ y, value.var = "z")
    

    r根据基本排序规则再次应用排序。

    x    A14  A4  B4
    A14  5    4   6
    A4   2    1   3
    B4   8    7   9
    

    不过,我需要原始的顺序来进行矩阵计算。是否有任何有效的方法将string+single-digits重命名为string+double-digits(a4->a04)或其他我错过的方法?

    5 回复  |  直到 7 年前
        1
  •  5
  •   Jaap    7 年前

    另一个可能也是最简单的选择是 mixedorder gtools -包装:

    wide <- dcast(dd, x ~ y, value.var = "z")[gtools::mixedorder(x)]
    

    它给出:

    > wide
         x A14 A4 B4
    1:  A4   2  1  3
    2: A14   5  4  6
    3:  B4   8  7  9
    

    如果还希望以相同的方式设置列顺序,则可以另外使用 setcolorder 以下内容:

    setcolorder(wide, c(1, gtools::mixedorder(names(wide)[-1]) + 1))
    

    然后给出:

    > wide
         x A4 A14 B4
    1:  A4  1   2  3
    2: A14  4   5  6
    3:  B4  7   8  9
    
        2
  •  2
  •   Dan    7 年前

    此解决方案不需要额外的零。

    # Data frame
    df <- data.frame(x = c("A4","A4","A4","A14","A14","A14","B4","B4","B4"),
                     y = c("A4","A14","B4","A4","A14","B4","A4","A14","B4"), 
                     z = c(1,2,3,4,5,6,7,8,9),
                     stringsAsFactors = FALSE)
    
    # Reorder columns and rows using `mixedsort`. 
    wide <- dcast(df, x ~ y,value.var   = "z") %>% 
      select(x, mixedsort(unique(df$x))) %>% 
      slice(match(x, mixedsort(unique(df$x))))
    

    给予,

    #     x A4 A14 B4
    # 1  A4  1   2  3
    # 2 A14  4   5  6
    # 3  B4  7   8  9
    
        3
  •  2
  •   MHammer    7 年前

    你可以用 sprintf() 用0预填充数字

    sprintf("%s%02.0d", "A",  1:20)
    # [1] "A01" "A02" "A03" "A04" "A05" "A06" "A07" "A08" "A09" "A10" "A11" "A12" "A13" "A14" "A15" "A16" "A17" "A18" "A19" "A20"
    
        4
  •  2
  •   IceCreamToucan    7 年前

    您可以添加 0 用你的数据

    dd[nchar(x) == 2, x := paste0(substr(x, 1, 1), 0, substr(x, 2, 2))]
    dd[nchar(y) == 2, y := paste0(substr(y, 1, 1), 0, substr(y, 2, 2))]
    
    #      x   y z
    # 1: A04 A04 1
    # 2: A04 A14 2
    # 3: A04 B04 3
    # 4: A14 A04 4
    # 5: A14 A14 5
    # 6: A14 B04 6
    # 7: B04 A04 7
    # 8: B04 A14 8
    # 9: B04 B04 9
    

    或者,如果需要应用于更多列:

    to.change <- c('x', 'y')
    
    dd[, (to.change) := lapply(.SD, function(x) ifelse(nchar(x) > 2, x
                                                       , paste0(substr(x, 1, 1), 0, substr(x, 2, 2))))
       , .SDcols = to.change]
    
        5
  •  1
  •   moodymudskipper    7 年前

    您可能想考虑通过因子直接在数据中实现这个顺序,这样以后就不必用数据争用来修复它了。

    如果您已经将这些唯一值排序到了不需要的位置 mixedorder mixedsort ,然后将它们转换为因子。

    否则你可以拿回订单:

    library(gtools)
    dd[,1:2] <- lapply(dd[,1:2],function(x) factor(x, mixedsort(unique(x))))
    

    并正常进行:

    dcast(dd, x ~ y, value.var = "z")
    #      x A4 A14 B4
    # 1:  A4  1   2  3
    # 2: A14  4   5  6
    # 3:  B4  7   8  9
    
    推荐文章