提问人:94621 提问时间:3/8/2023 更新时间:3/8/2023 访问量:191
如何从 csv/dataframe 列中的字符串解析数组数组
How to parse array of arrays from string in column of csv/dataframe
问:
我有一个 csv 文件,其中一列包含一个 numpy 数组。读取 csv 文件时,生成的列将具有字符类型,因为它全部包装在字符串中。 我想将其解析为单独的数据帧来分析数据。
输入数据
作为 csv:
first_column,second_column
a,"[[1,2],[3,4]]"
b,"[[5,6],[7,8]]"
c,"[[9,10],[11,12]]"
作为数据帧:
df <- data.frame(first_column = c("a","b","c"),
second_column = c("[[1,2],[3,4]]","[[5,6],[7,8]]","[[9,10],[11,12]]"))
我试过什么
由于我不知道有任何可以从字符串中提取数组的直接解析函数,所以我开始做字符串操作。
删除外部字符:[]
> df %>% mutate(second_column = str_replace_all(second_column, c("^\\[" = "","]$" = "")))
first_column second_column
1 a [1,2],[3,4]
2 b [5,6],[7,8]
3 c [9,10],[11,12]
但是,从现在开始,我不知道该如何进行。
预期输出
最终生成的数据帧应如下所示:
col_1 col_2
1 1 2
2 3 4
3 5 6
4 7 8
5 9 10
6 11 12
请注意,实际数据帧中有更多的列和行
答:
0赞
Matt
3/8/2023
#1
这是一个黑客解决方案,使用:tidyverse
df <- data.frame(first_column = c("a","b","c"),
second_column = c("[[1,2],[3,4]]","[[5,6],[7,8]]","[[9,10],[11,12]]"))
library(tidyverse)
df %>%
mutate(second_column = str_replace_all(second_column, c("^\\[" = "","]$" = "")),
second_column = gsub("\\[|\\]", "", second_column)) %>%
separate(second_column, into = c("col_1", "col_2", "col_3", "col_4"), sep = ",") %>%
pivot_longer(-first_column) %>%
mutate(name = case_when(name == "col_3" ~ "col_1",
name == "col_4" ~ "col_2",
.default = name)) %>%
select(-first_column) %>%
pivot_wider(names_from = name, values_from = value, values_fn = list) %>%
unnest(cols = c(col_1, col_2))
#> # A tibble: 6 × 2
#> col_1 col_2
#> <chr> <chr>
#> 1 1 2
#> 2 3 4
#> 3 5 6
#> 4 7 8
#> 5 9 10
#> 6 11 12
1赞
Andre Wildberg
3/8/2023
#2
一种基本 R 方法,用于处理给定列上的任意行数。
setNames(
data.frame(Vectorize(\(x) as.numeric(x))(
data.frame(do.call(rbind,
sapply(lapply(strsplit(df$second_column, "\\],\\["),
gsub, pattern="\\[|\\]", replacement=""), strsplit, ","))))),
c("col_1", "col_2"))
col_1 col_2
1 1 2
2 3 4
3 5 6
4 7 8
5 9 10
6 11 12
3赞
G. Grothendieck
3/8/2023
#3
将出现的 ],[ 替换为换行符,将方括号替换为空格,并用于读取该值。read.table
df$second_column |>
gsub("\\],\\[", "\n", x = _) |>
chartr("[]", " ", x = _) |>
read.table(text = _, sep = ",")
给:
V1 V2
1 1 2
2 3 4
3 5 6
4 7 8
5 9 10
6 11 12
评论
0赞
94621
3/8/2023
这看起来很整洁!这将导致宽表布局:当 CSV 有 10 行且嵌套表的大小为 10x10 时,生成的表将为 10 x 100 (10x10 = 100)
2赞
GKi
3/8/2023
#4
基本变体可以是:
#Replace [], with space
. <- gsub("[][,]", " ", df$second_column)
#. <- chartr("[],", " ", df$second_column) #Alternativ
#Split at " " and unlist result
. <- unlist(strsplit(., " ", fixed=TRUE))
#. <- sub(" ", "\n", ., fixed=TRUE) #Alternativ
#use read.table to get columns
read.table(text = .)
# V1 V2
#1 1 2
#2 3 4
#3 5 6
#4 7 8
#5 9 10
#6 11 12
或使用trimws
. <- trimws(df$second_column, whitespace = "[][]")
. <- unlist(strsplit(., "],[", fixed=TRUE))
#. <- sub("],[", "\n", ., fixed=TRUE) #Alternativ
read.csv(text=.)
评论
0赞
94621
3/8/2023
在此解决方案中,生成的表具有较长的布局:当 CSV 有 10 行且嵌套表的大小为 10x10 时,生成的表将为 100 x 10(其中 x 10 是嵌套数组中的列数)
0赞
GKi
3/8/2023
您能举个例子和该案例的预期输出吗?
0赞
94621
3/8/2023
没关系,这种形式最适合我。由于它是一系列观察结果,因此我在单独的 df 中提取了它,然后通过(提取的 df)进一步过滤了一个实体,但我在这里没有要求这样做obs[seq(1,nrow(obs),10,]
obs.
0赞
ThomasIsCoding
3/8/2023
#5
来自的技巧py_eval
reticulate
library(reticulate)
with(
df,
as.data.frame(
do.call(
rbind,
py_eval(gsub("]], [[", "],[",
toString(second_column),
fixed = TRUE
))
)
)
)
或另一个技巧fromJSON
jsonlite
library(jsonlite)
with(
df,
as.data.frame(
fromJSON(sprintf("[%s]", gsub("]], [[", "],[",
toString(second_column),
fixed = TRUE
)))[1, , ]
)
)
输出
V1 V2
1 1 2
2 3 4
3 5 6
4 7 8
5 9 10
6 11 12
评论