我有一列字符串,每行包含多列的信息,包括列名称。每个单元格都是结构化的,因此人们可以轻松地看到不同的信息,但以这种格式使用并不容易。单元格的格式类似于“变量:值”,多个输入以逗号分隔。我想将列拆分为单独的列,并根据冒号之前所写的内容进行列名称。这是一个例子。
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")
)
如果没有硬编码列名称,这是一种方法 -
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")
)
请注意,问题在输入的第二行中有
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)
您可以尝试从
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