代码之家  ›  专栏  ›  技术社区  ›  jay.sf

如何使用正则表达式将向量划分为多个组?

  •  1
  • jay.sf  · 技术社区  · 7 年前

    this solution 通过正则表达式对多个组的向量进行分组,但无法找出我做错了什么。 Another solution

    x1 <- gsub(paste0("(^a?A?pr)|(^a?A?ug)|(d?D?ec)"),
               "\\1 \\2 \\3", x)
    > unique(x1)
    [1] "  dec" "Apr  " " aug " "apr  " "  Dec" " Aug "
    

    我希望有三个独特的组,正如我在 gsub "dec Dec", "aug Aug", "apr Apr" .

    超过9组的情况更糟。

    y1 <- gsub(paste0("(^a?A?pr)|(^a?A?ug)|(d?D?ec)|(^f?F?eb)|(^j?J?an)|(^j?J?ul)|", 
                      "(^j?J?un)|(^m?M?ar)|(^m?M?ay)|(^n?|N?ov)|(^o?O?ct)|(^s?S?ep)"),
               "\\1 \\2 \\3 \\4 \\5 \\6 \\7 \\8 \\9 \\10 \\11 \\12", y)
    > unique(y1)
     [1] "         0 1 2"             "      jun   0 1 2"         
     [3] "     jul    0 1 2"          " Aug        0 1 2"         
     [5] "     Jul    0 1 2"          "   feb      0 1 2"         
     [7] "      Jun   0 1 2"          "       Mar  0 1 2"         
     [9] "    jan     0 1 2"          "Apr         Apr0 Apr1 Apr2"
    [11] "  dec       0 1 2"          "   Feb      0 1 2"         
    [13] "  Dec       0 1 2"          "apr         apr0 apr1 apr2"
    [15] " aug        0 1 2" 
    

    作为最终结果,我的目标是为同一类型的不同外观创建一个具有唯一级别的因式分解向量(即,在本例中,为每个月的名称创建一个组,不区分大小写)。

    编辑

    我的应用程序与月份名称的关系不大,只是大写/小写,我的组更复杂。这些数据是OCR生成的,因此被轻微破坏。我试着举另一个例子来说明我的问题:

    z1 <- gsub(paste0("(^0?O?c?i?t)|(^5?S?ep?P?)|(^D?d?8?o?e?c?o?)|(^a?A?p.)|",
                      "(^A?u.)|(F?f?E?e?b)|(^J?I?ul|ju1)|(J?j?u?2?n?2?)|(^N.+)|(^May)"),
               "\\1 \\2 \\3 \\4 \\5 \\6 \\7 \\8 \\9 \\10", z)
    > unique(z1)
     [1] "Oit         Oit0" "       ju2  0"    "0ct         0ct0" "      ju1   0"   
     [5] "    Au9     0"    "      Iul   0"    " Sep        0"    "      Jul   0"   
     [9] "     feb    0"    "       Jun  0"    "Oct         Oct0" "  8oc       0"   
    [13] "     Eeb    0"    "        Nov 0"    "     Feb    0"    "  deo       0"   
    [17] "   Apv      0"    "  Dec       0"    "       j2n  0"    "         0"      
    [21] "   apr      0"    "    Aug     0"    " 5eP        0"  
    

    不同形式的月份名称不在我在 \\10 似乎制造了问题(与案例相比) x ).

    gsub 是否正确,以便可以唯一地识别正则表达式中定义的组?

    资料

    x <- c("dec", "Apr", "dec", "aug", "dec", "dec", "Apr", "apr", "apr", 
    "dec", "Dec", "Aug", "Aug", "Apr", "Aug", "Apr", "aug", "Apr", 
    "apr", "Apr", "dec", "aug", "aug", "aug", "aug", "apr", "dec", 
    "Aug", "dec", "dec", "Dec", "Dec", "Apr", "Apr", "dec", "dec", 
    "Dec", "dec", "apr", "Apr", "Apr", "dec", "apr", "apr", "apr", 
    "apr", "Aug", "apr", "dec", "dec")
    
    y <- c("Oct", "jun", "oct", "jul", "Aug", "jul", "Sep", "Jul", "feb", 
    "feb", "Jun", "Mar", "jan", "Apr", "jul", "oct", "Jun", "jan", 
    "Jun", "Oct", "Jul", "dec", "Jun", "Sep", "Feb", "Nov", "Feb", 
    "dec", "Apr", "Dec", "jan", "Aug", "Feb", "apr", "Sep", "Nov", 
    "aug", "oct", "Jun", "jul", "Apr", "Jun", "Apr", "Dec", "Jun", 
    "Jul", "Aug", "Aug", "Jul", "sep")
    
    z <- c("Oit", "ju2", "0ct", "ju1", "Au9", "Iul", "Sep", "Jul", "feb", 
           "Jun", "Oct", "Jul", "8oc", "Jun", "Sep", "Eeb", "Nov", "Feb", 
           "deo", "Apv", "Dec", "j2n", "May", "Feb", "apr", "Sep", "Nov", 
           "Jul", "Aug", "Aug", "Jul", "5eP")
    
    0 回复  |  直到 7 年前
        1
  •  2
  •   IRTFM    7 年前

    (pats <- sapply(  as.data.frame(  t(matrix( c( month.abb, tolower(month.abb)), ncol=2))) , paste0,collapse="|" ) )
           V1        V2        V3        V4        V5        V6        V7        V8        V9 
    "Jan|jan" "Feb|feb" "Mar|mar" "Apr|apr" "May|may" "Jun|jun" "Jul|jul" "Aug|aug" "Sep|sep" 
          V10       V11       V12 
    "Oct|oct" "Nov|nov" "Dec|dec" 
    pats[1] <- "Jan|jan|Ja|ja"  
     # add generality (that's actually redundant)
     # and might better "Ja.|ja.|.an"
    pats[10] <- "Oct|oct|Oit|oc|Oc"
    # or more compactly:  "OC|oc|O.t"
    

    然后,您可以在循环中运行这些“通用模式”,以更正条目:

     zcopy <- z
    for( p in seq_along(pats) ) { 
             zcopy[grepl( pats[p], z)] <- month.abb[p] }
    #------------------------
    > zcopy
     [1] "Oct" "ju2" "0ct" "ju1" "Au9" "Iul" "Sep" "Jul" "Feb" "Jun" "Oct" "Jul" "Oct" "Jun" "Sep"
    [16] "Eeb" "Nov" "Feb" "deo" "Apv" "Dec" "j2n" "May" "Feb" "Apr" "Sep" "Nov" "Jul" "Aug" "Aug"
    [31] "Jul" "5eP"
    

    您需要决定这一点的通用性,也就是说,您只是想在9月份的模式中添加“5ep”,还是应该是“.ep”?但我认为我已经为一项相当复杂的任务提供了相当紧凑的代码。

    如果您想使字符位置完全通配符,那么可以在模式中使用句点,例如,您可以决定让任何后跟“ul”的字母在7月份成为可接受的命中率,然后只需将“.ul”添加到该模式字符串中(当然带有“|”管道分隔符)。

    -----------旧答案--

    我不确定我是否理解,但如果你只是想对月份缩写字母进行“规范化”排序,那么你可以使用 match month.abb :

    month.abb[ match(tolower(x), tolower(month.abb) )]
     [1] "Dec" "Apr" "Dec" "Aug" "Dec" "Dec" "Apr" "Apr" "Apr" "Dec" "Dec"
    [12] "Aug" "Aug" "Apr" "Aug" "Apr" "Aug" "Apr" "Apr" "Apr" "Dec" "Aug"
    [23] "Aug" "Aug" "Aug" "Apr" "Dec" "Aug" "Dec" "Dec" "Dec" "Dec" "Apr"
    [34] "Apr" "Dec" "Dec" "Dec" "Dec" "Apr" "Apr" "Apr" "Dec" "Apr" "Apr"
    [45] "Apr" "Apr" "Aug" "Apr" "Dec" "Dec"
    

    显然,这可以通过factor函数生成一个factor,但可能应该按照正确的顺序设置级别:

    factor( month.abb[ match(tolower(x), tolower(month.abb) )], levels=month.abb)
     [1] Dec Apr Dec Aug Dec Dec Apr Apr Apr Dec Dec Aug
    [13] Aug Apr Aug Apr Aug Apr Apr Apr Dec Aug Aug Aug
    [25] Aug Apr Dec Aug Dec Dec Dec Dec Apr Apr Dec Dec
    [37] Dec Dec Apr Apr Apr Dec Apr Apr Apr Apr Aug Apr
    [49] Dec Dec
    12 Levels: Jan Feb Mar Apr May Jun Jul Aug ... Dec
    
        2
  •  1
  •   Andrew    7 年前

    x y :),我不确定你到底想要什么 z . 这基本上可以识别向量中的重复项并将它们粘贴在一起。目前,它仅在存在副本时有效,但可适用于多个副本(即。, c("sep", "Sep", "seP") .

    # For y
    y_sort <- sort(unique(y))
    
    #Extract single factors
    table <- data.frame(table(tolower(y_sort)), stringsAsFactors = FALSE)
    solo <- as.character(table[which(table$Freq < 2), ]$Var1)
    y_sort_dups <- y_sort[!tolower(y_sort) %in% solo]
    
    # Create indices for dups
    rep_indices <- rle(tolower(y_sort_dups))$lengths
    
    # Paste together dups
    levels <- cumsum(rep_indices) - 1
    dups <- unique(paste(y_sort_dups[levels], y_sort_dups[levels + 1], sep = " "))
    
    # Add back in solo months
    sort(c(dups, y_sort[tolower(y_sort) %in% solo]))
    [1] "apr Apr" "aug Aug" "dec Dec" "feb Feb" "jan"     "jul Jul" "jun Jun" "Mar"     "Nov"     "oct Oct" "seP Sep"
    

    但是,如果您使用的是OCR生成的数据,为什么不在创建要素之前对其进行大量清理呢?下面我修改了我在一个类似项目中使用的一些语法,它并不完美,但你会得到大致的想法。而不是 jarowinkler 你可以用 levenshteinDist 具有 min which.min

    # Cleaning up z
    library(RecordLinkage)
    
    # Vector with all values 
    z_lower <- trimws(tolower(z))
    
    # Vector with legitimate values (can add to, this was the quick way)
    z_dups <- unique(c(unique(z_lower[duplicated(z_lower)]), tolower(month.abb)))
    
    # Create df to viewing
    df <- data.frame(z_lower = z_lower, stringsAsFactors = FALSE)
    
    # Swap out numbers that look like letters
    df$z_gsub <- gsub("0", "o", df$z_lower, fixed = TRUE)
    df$z_gsub <- gsub("3", "e", df$z_gsub, fixed = TRUE)
    df$z_gsub <- gsub("4", "a", df$z_gsub, fixed = TRUE)
    df$z_gsub <- gsub("5", "s", df$z_gsub, fixed = TRUE)
    df$z_gsub <- gsub("6", "g", df$z_gsub, fixed = TRUE)
    df$z_gsub <- gsub("8", "b", df$z_gsub, fixed = TRUE)
    
    
    df$distance <- sapply(df$z_gsub, function(x) max(jarowinkler(x, z_dups)))
    df$match <- sapply(df$z_gsub, function(x) z_dups[which.max(jarowinkler(x, z_dups))])
    
    > unique(df[order(df$distance), ])
       z_lower z_gsub  distance match
    13     8oc    boc 0.5555556   nov
    6      iul    iul 0.7777778   jul
    16     eeb    eeb 0.7777778   feb
    1      oit    oit 0.8000000   oct
    22     j2n    j2n 0.8000000   jun
    2      ju2    ju2 0.8222222   jul
    4      ju1    ju1 0.8222222   jul
    5      au9    au9 0.8222222   aug
    19     deo    deo 0.8222222   dec
    20     apv    apv 0.8222222   apr
    3      0ct    oct 1.0000000   oct
    7      sep    sep 1.0000000   sep
    8      jul    jul 1.0000000   jul
    9      feb    feb 1.0000000   feb
    10     jun    jun 1.0000000   jun
    11     oct    oct 1.0000000   oct
    17     nov    nov 1.0000000   nov
    21     dec    dec 1.0000000   dec
    23     may    may 1.0000000   may
    25     apr    apr 1.0000000   apr
    29     aug    aug 1.0000000   aug
    32     5ep    sep 1.0000000   sep
    
        3
  •  1
  •   jay.sf    7 年前

    我(还)找不到工作 gsub 解决方案,但是 grep

    考虑一个值已知但由于OCR有点中断的列。

    > dat$z1
     [1] "grcen"  "grey"   "b1ue"   "gree2"  "grey"   "bei9e"  "grey"   "beige" 
     [9] "b|ue"   "bcige"  "green"  "grey"   "giieen" "blue"   "belge"  "bliie"
    

    rex

    rex <- c("(^bl?1?\\|?u?i*?e$)", "(^be?c?i?l?g?9?.$)", "(^gr?i*c?e*n?2?$)", 
             "(^grey$)")
    

    然后,我用 格雷普 得到矩阵 M 有关职位的名称

    M <- sapply(rex, function(i) grep(i, dat$z1))
    

    把他们统一成一个整体 for 通过指定类别编号进行循环:

    for (j in seq(rex)) dat$z1[M[, j]] <- j
    

    最后,我将列分解并为每个类别分配正确的标签。

    factor(dat$z1, labels=c("blue", "beige", "green", "gray"))
    # [1] green gray  blue  green gray  beige gray  beige blue  beige green gray 
    # [13] green blue  beige blue 
    # Levels: blue beige green gray
    

    dat <- structure(list(z1 = c("grcen", "grey", "b1ue", "gree2", "grey", 
    "bei9e", "grey", "beige", "b|ue", "bcige", "green", "grey", "giieen", 
    "blue", "belge", "bliie")), class = "data.frame", row.names = c(NA, 
    -16L))