使用R将结构化字符串拆分为多列,并根据字符串值设置列名称

问题描述 投票:0回答:3

我有一列字符串,每行包含多列的信息,包括列名称。每个单元格都是结构化的,因此人们可以轻松地看到不同的信息,但以这种格式使用并不容易。单元格的格式类似于“变量:值”,多个输入以逗号分隔。我想将列拆分为单独的列,并根据冒号之前所写的内容进行列名称。这是一个例子。

my_df <- tibble(
address = c("street: AvenueName, number: 1, code: 1234 AB, city: City One", 
"street: AnotherStreet, number: 99, code: 5678 CD, city: Town Two")
)

我知道我可以使用

separate_wider_delim
拆分字符串,然后将列名称分配给 data.frame。虽然这有效,但我希望看到一种不依赖于“手动”设置列名称的方法,而是从字符串内的值派生它们。

我预期的数据框将如下所示:

expected_df <- tibble(
street= c("AvenueName", "AnotherStreet"),
number = c(1, 99),
code = c("1234 AB", "5678 CD"),
city = c("City One", "Town Two")
)
r string split multiple-columns
3个回答
2
投票

如果没有硬编码列名称,这是一种方法 -

library(dplyr)
library(tidyr)

my_df %>%
  #To keep track of each row of data 
  mutate(row = row_number()) %>%
  # Bring data in separate rows splitting on comma
  separate_rows(address, sep = ",\\s*") %>%
  # Split data on colon to get data in two columns
  separate_wider_delim(address, ": ", names = c("col", "value")) %>%
  # Get data in wide format
  pivot_wider(names_from = col, values_from = value) %>%
  # Drop row column
  select(-row)

#  street        number code    city    
#  <chr>         <chr>  <chr>   <chr>   
#1 AvenueName    1      1234 AB City One
#2 AnotherStreet 99     5678 CD Town Two

数据

我冒昧修复了您的数据,使其与预期输出相匹配。

my_df <- tibble(
  address = c("street: AvenueName, number: 1, code: 1234 AB, city: City One", 
            "street: AnotherStreet, number: 99, code: 5678 CD, city: Town Two")
)

1
投票

请注意,问题在输入的第二行中有

codee
而不是
code
。我们保留了这一点。如果已更正,代码将给出相应的更正输出。

1) 通过用换行符替换逗号空格和行尾,将每一行转换为 dcf 格式,然后使用 read.dcf。如果字符矩阵可以,那么我们可以省略最后两行,或者如果包含所有字符列的 data.frame 可以,那么我们可以省略最后一行。

library(dplyr)

my_df %>%
  mutate(address = gsub(", |$", "\n", address)) %>%
  { textConnection(.$address) } %>%
  read.dcf %>%
  as.data.frame %>%
  type.convert(as.is = TRUE)

给予:

         street number    code     city   codee   plaats
1    AvenueName      1 1234 AB City One    <NA>     <NA>
2 AnotherStreet     99    <NA>     <NA> 5678 CD Town Two

2) 或仅使用碱基 R:

my_df |>
  transform(address = gsub(", |$", "\n", address)) |>
  with(textConnection(address)) |>
  read.dcf() |>
  as.data.frame() |>
  type.convert(as.is = TRUE)

或不带管道

mat <- read.dcf(textConnection(gsub(", |$", "\n", my_df$address)))
type.convert(as.data.frame(mat), as.is = TRUE)

0
投票

您可以尝试从

py_eval
+
reticulate
开始
gsub
,如下所示

library(reticulate)
type.convert(
    do.call(
        rbind,
        lapply(
            sprintf(
                "{%s}",
                gsub("(\\w+):\\s([A-Za-z0-9 ]+)", "'\\1':'\\2'", my_df$address)
            ),
            \(x) list2DF(py_eval(x))
        )
    ),
    as.is = TRUE
)

这给出了

         street number    code     city
1    AvenueName      1 1234 AB City One
2 AnotherStreet     99 5678 CD Town Two
© www.soinside.com 2019 - 2024. All rights reserved.