将 python-like 列表转换为 R 嵌套向量
Convert python-like list to R nested vectors
我正在尝试 "automatically" 将 data.frame 列转换为多列。
这是 df 的样子:
library(dplyr)
foo <- data_frame(ID = c(1,2),
Val = c("A", "B"),
Geom = c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]"))
这是我希望的样子:
bar <- data_frame(ID = c(1,1,1,2,2,2),
Val=c("A", "A", "A", "B", "B", "B"),
Geom1 = c("X11", "X12", "X13", "X21", "X22", "X23"),
Geom2 = c("Y11", "Y12", "Y13", "Y21", "Y22", "Y23"),
Geom3 = c("Z11", "Z12", "Z13", "Z21", "Z22", "Z23"))
我考虑进行此类转换的工作流程由两部分组成:
1 - 将 Geom 转换为 R 结构,例如:
list(c("X11","Y11","Z11"), c(...), ...)
2 - 使用 tidyr::unnest()
或 tidyr::separate()
将此类列表拆分为列
我想我可以处理第二部分,但找不到第一部分的好指针。我可以将此专栏写入 csv 并在之后自动读取它,但考虑到我的 data.frame 将是一个闪亮的反应对象,这将涉及很多 writing/reading.
我尝试使用 fromJSON()
(jsonlite、rjson 和 RJSONIO),但由于这不是有效的 json-字符串,所以它不不解析它。
data.table
/splitstackshape
的解决方案:
library(data.table)
library(splitstackshape)
dt = setDT(foo)[,strsplit(gsub('\[{|}\]','', Geom, perl=T), '}, *{', perl=T), .(ID, Val)]
cSplit(dt, 'V1')
# ID Val V1_1 V1_2 V1_3
#1: 1 A X11 Y11 Z11
#2: 1 A X12 Y12 Z12
#3: 1 A X13 Y13 Z13
#4: 2 B X21 Y21 Z21
#5: 2 B X22 Y22 Z22
#6: 2 B X23 Y23 Z23
这是一种使用 base R 的方法:
# vector to work with
geom <- c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]")
# remove extraneous characters and split into list using "},"
geom <- strsplit(gsub("[]{ []", "", Geom), split="},")
# remove two "}"s
geom <- sapply(geom, function(i) gsub("}", "", i))
# make a list of elements
geom <- strsplit(geom, split=",")
# construct the variables
geomData <- data.frame(t(sapply(geom, function(i) sapply(1:3, function(row) c(i[row])))))
# give names to data frame
names(geomData) <- c("Geom1", "Geom2", "Geom3")
# final data.frame
fooNew <- cbind(foo[, 1:2], geomData)
1) dplyr 这将数据帧拆分为行,对于每一行,使用 gsub
将每个三元组拆分为单独的一行,并且 read.table
进一步解析 Geom
。然后它修复列名并执行 ungroup
。 (如果 V1、V2 和 V3 可以代替 Geom1、Geom2 和 Geom3,则可以省略 setNames
行。)
library(dplyr)
foo %>%
group_by(ID, Val) %>%
do(read.table(text=gsub("^..|..$|}, *{", "\n", .$Geom, perl=T), sep=",", as.is=T)) %>%
setNames(sub("^V(\d+)", "Geom\1", colnames(.))) %>%
ungroup()
给予:
Source: local data frame [6 x 5]
ID Val Geom1 Geom2 Geom3
(dbl) (chr) (chr) (chr) (chr)
1 1 A X11 Y11 Z11
2 1 A X12 Y12 Z12
3 1 A X13 Y13 Z13
4 2 B X21 Y21 Z21
5 2 B X22 Y22 Z22
6 2 B X23 Y23 Z23
2) 无包 这使用相同的方法但没有任何包。如果用V1,V2,V3代替Geom1,Geom2,Geom3就可以省略最后一行代码
bar <- do.call("rbind", by(foo, foo$ID, function(x)
cbind(x[1:2], read.table(text = gsub("^..|..$|}, *{", "\n", x$Geom, perl=T), sep=","))))
names(bar) <- sub("^V(\d+)", "Geom\1", names(bar))
给予:
> bar
ID Val Geom1 Geom2 Geom3
1.1 1 A X11 Y11 Z11
1.2 1 A X12 Y12 Z12
1.3 1 A X13 Y13 Z13
2.1 2 B X21 Y21 Z21
2.2 2 B X22 Y22 Z22
2.3 2 B X23 Y23 Z23
我正在尝试 "automatically" 将 data.frame 列转换为多列。
这是 df 的样子:
library(dplyr)
foo <- data_frame(ID = c(1,2),
Val = c("A", "B"),
Geom = c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]"))
这是我希望的样子:
bar <- data_frame(ID = c(1,1,1,2,2,2),
Val=c("A", "A", "A", "B", "B", "B"),
Geom1 = c("X11", "X12", "X13", "X21", "X22", "X23"),
Geom2 = c("Y11", "Y12", "Y13", "Y21", "Y22", "Y23"),
Geom3 = c("Z11", "Z12", "Z13", "Z21", "Z22", "Z23"))
我考虑进行此类转换的工作流程由两部分组成:
1 - 将 Geom 转换为 R 结构,例如:
list(c("X11","Y11","Z11"), c(...), ...)
2 - 使用 tidyr::unnest()
或 tidyr::separate()
将此类列表拆分为列
我想我可以处理第二部分,但找不到第一部分的好指针。我可以将此专栏写入 csv 并在之后自动读取它,但考虑到我的 data.frame 将是一个闪亮的反应对象,这将涉及很多 writing/reading.
我尝试使用 fromJSON()
(jsonlite、rjson 和 RJSONIO),但由于这不是有效的 json-字符串,所以它不不解析它。
data.table
/splitstackshape
的解决方案:
library(data.table)
library(splitstackshape)
dt = setDT(foo)[,strsplit(gsub('\[{|}\]','', Geom, perl=T), '}, *{', perl=T), .(ID, Val)]
cSplit(dt, 'V1')
# ID Val V1_1 V1_2 V1_3
#1: 1 A X11 Y11 Z11
#2: 1 A X12 Y12 Z12
#3: 1 A X13 Y13 Z13
#4: 2 B X21 Y21 Z21
#5: 2 B X22 Y22 Z22
#6: 2 B X23 Y23 Z23
这是一种使用 base R 的方法:
# vector to work with
geom <- c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]")
# remove extraneous characters and split into list using "},"
geom <- strsplit(gsub("[]{ []", "", Geom), split="},")
# remove two "}"s
geom <- sapply(geom, function(i) gsub("}", "", i))
# make a list of elements
geom <- strsplit(geom, split=",")
# construct the variables
geomData <- data.frame(t(sapply(geom, function(i) sapply(1:3, function(row) c(i[row])))))
# give names to data frame
names(geomData) <- c("Geom1", "Geom2", "Geom3")
# final data.frame
fooNew <- cbind(foo[, 1:2], geomData)
1) dplyr 这将数据帧拆分为行,对于每一行,使用 gsub
将每个三元组拆分为单独的一行,并且 read.table
进一步解析 Geom
。然后它修复列名并执行 ungroup
。 (如果 V1、V2 和 V3 可以代替 Geom1、Geom2 和 Geom3,则可以省略 setNames
行。)
library(dplyr)
foo %>%
group_by(ID, Val) %>%
do(read.table(text=gsub("^..|..$|}, *{", "\n", .$Geom, perl=T), sep=",", as.is=T)) %>%
setNames(sub("^V(\d+)", "Geom\1", colnames(.))) %>%
ungroup()
给予:
Source: local data frame [6 x 5]
ID Val Geom1 Geom2 Geom3
(dbl) (chr) (chr) (chr) (chr)
1 1 A X11 Y11 Z11
2 1 A X12 Y12 Z12
3 1 A X13 Y13 Z13
4 2 B X21 Y21 Z21
5 2 B X22 Y22 Z22
6 2 B X23 Y23 Z23
2) 无包 这使用相同的方法但没有任何包。如果用V1,V2,V3代替Geom1,Geom2,Geom3就可以省略最后一行代码
bar <- do.call("rbind", by(foo, foo$ID, function(x)
cbind(x[1:2], read.table(text = gsub("^..|..$|}, *{", "\n", x$Geom, perl=T), sep=","))))
names(bar) <- sub("^V(\d+)", "Geom\1", names(bar))
给予:
> bar
ID Val Geom1 Geom2 Geom3
1.1 1 A X11 Y11 Z11
1.2 1 A X12 Y12 Z12
1.3 1 A X13 Y13 Z13
2.1 2 B X21 Y21 Z21
2.2 2 B X22 Y22 Z22
2.3 2 B X23 Y23 Z23