【问题标题】:split string and extract according to a pattern to form data frame拆分字符串并根据模式提取以形成数据框
【发布时间】:2017-04-19 02:42:56
【问题描述】:

我试图在 R 中将以下字符串分割为 3 个单独的列(国家、城市、计数)

Country    City     Count    
Japan      Tokyo    361

数据:

"country=Japan&city=Tokyo","361"
"country=Spain&city=Barcelona","359"
"country=United Kingdom&city=London","333"
"country=Japan&city=Fukuoka","259"
"country=United States of America&city=New York City","223"

我试过了:

library(data.table)
library(stringr)

df <- read.table(file.choose(), header = FALSE, sep = ",", colClasses = c('character', 'character'), na.strings = 'null')

df.1 <- data.table(str = as.character(df$V1))

df.2 <- df.1[grepl("country=.+&city=\\w+", str),
             country := str_extract(str,"(?<=country=)(.+)"),
             city := str_extract(str, "(?<=city=)(.+)")]

但是,虽然我想查看城市格式,但国家列将返回如下:

Japan&city=Tokyo

我想去掉 &city=Tokyo 位来制作漂亮的格式。

然后,我将 df 和 df.2 合并在一起,以便对齐数值。但是,我认为必须有更聪明的方法来做到这一点。

请分享你的知识。感谢您的帮助。

【问题讨论】:

    标签: r regex stringr strsplit


    【解决方案1】:

    我们可以使用base Rstrsplit将'V1'列通过=&amp;拆分成list,循环遍历list,提取替代元素(x[c(FALSE, TRUE)])同时用剩余的元素命名它,rbind list 元素,然后 cbind 使用原始数据集的第二列

    res <- do.call(rbind, lapply(strsplit(as.character(df$V1), "[=&]"), 
                 function(x) setNames(x[c(FALSE, TRUE)], x[c(TRUE, FALSE)])))
    res1 <- cbind(res, setNames(df[-1], 'Count'))
    res1
    #                   country          city Count
    #1                    Japan         Tokyo   361
    #2                    Spain     Barcelona   359
    #3           United Kingdom        London   333
    #4                    Japan       Fukuoka   259
    #5 United States of America New York City   223
    

    我们也可以使用tidyverse 来做到这一点。创建一个行索引列(rownames_to_column from tibble),然后用分隔符'&'(separate_rows)拆分'V1'以重塑为'long'格式,将'V1'拆分为新列(' new1' 和 'new2') 通过将 'sep' 指定为 =,将数据集重新整形为 'wide' (spread) 并重新排列列 (select)

    library(tidyverse)
    rownames_to_column(df, 'rn') %>%
          separate_rows(V1, sep='[&]') %>% 
          separate(V1, into= c("new1", "new2"), sep="=")  %>% 
          spread(new1, new2) %>% 
          select(country, city, Count=V2) 
    #                   country          city Count
    #1                    Japan         Tokyo   361
    #2                    Spain     Barcelona   359
    #3           United Kingdom        London   333
    #4                    Japan       Fukuoka   259
    #5 United States of America New York City   223
    

    数据

    df <- structure(list(V1 = structure(c(2L, 3L, 4L, 1L, 5L), 
    .Label = c("country=Japan&city=Fukuoka", 
     "country=Japan&city=Tokyo", "country=Spain&city=Barcelona", 
      "country=United Kingdom&city=London", 
    "country=United States of America&city=New York City"), class = "factor"), 
    V2 = c(361L, 359L, 333L, 259L, 223L)), .Names = c("V1", "V2"
    ), row.names = c(NA, -5L), class = "data.frame")
    

    【讨论】:

      【解决方案2】:

      您所拥有的是有效的 URL 编码查询,因此您可以使用 httr::parse_url 对它们进行解码。两个并发症:

      1. parse_url 在查询前查找 ? 以识别它,因此您必须打开 paste0 它,并且
      2. parse_url 未矢量化,因此必须通过 lapplypurrr::map 将其应用于每个查询。

      不过,大多数情况下,它的效果都很好:

      library(tidyverse)
      
      df <- read_csv('"country=Japan&city=Tokyo","361"
      "country=Spain&city=Barcelona","359"
      "country=United Kingdom&city=London","333"
      "country=Japan&city=Fukuoka","259"
      "country=United States of America&city=New York City","223"', 
                     col_names = c('query', 'count'))
      
      df %>% transmute(count, 
                       query = map(paste0('?', query), 
                                   ~as_data_frame(httr::parse_url(.x)$query))) %>% 
          unnest()
      
      #> # A tibble: 5 × 3
      #>   count                  country          city
      #>   <int>                    <chr>         <chr>
      #> 1   361                    Japan         Tokyo
      #> 2   359                    Spain     Barcelona
      #> 3   333           United Kingdom        London
      #> 4   259                    Japan       Fukuoka
      #> 5   223 United States of America New York City
      

      甚至只是

      df %>% do(data.frame(count = .$count, 
                           query = map_df(paste0('?', .$query), 
                                          ~httr::parse_url(.x)$query)))
      

      或使用curlconverter::parse_queryshiny::parseQueryString,不需要额外的?

      df %>% bind_cols(map_df(.$query, curlconverter::parse_query)) %>% select(-query)
      

      所有返回相同的东西。

      【讨论】:

      • 这太酷了!直到现在我才知道有 parse_url 函数。非常感谢您分享此内容,我可以将其应用于我正在处理的其他数据集。
      猜你喜欢
      • 2021-04-17
      • 1970-01-01
      • 2017-05-07
      • 1970-01-01
      • 2016-08-15
      • 2018-01-14
      • 2013-06-17
      • 2021-04-16
      • 2018-05-12
      相关资源
      最近更新 更多