2016-04-20 38 views
1

我试图“自动”将data.frame列转换为多列。将类似Python的列表转换为R嵌套向量

这里的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将是一个闪亮的反应对象,这将涉及大量的写/读。

我试着用fromJSON()(jsonlite,rjson和RJSONIO),但是因为这是无效的json-string,所以它不解析它。

+0

@wildintellect告诉我,fromJSON用[]当更换{}工作。我会测试那些各种解决方案,并基准那些,考虑我更喜欢使用管道的临时变量:) – RobinCura

+1

如果你喜欢管道,你可以重写上校的答案像'setDT(foo)[,Geom%>%gsub(pattern = '\\ [{|} \\'',replacement ='',perl = TRUE)%>%strsplit(split ='},* {',perl = T),。(ID,Val)]'或类似在dplyrish。 – Frank

+0

没有像这样的分割栈形: 'setDT(foo)[,strsplit(gsub('\\ [{|} \\]','',Geom,perl = T),'},* {',perl = T),。(ID,Val)]%>% mutate(UID = id)分离(V1,转入= c(“X”,“Y”,“Z”),convert = (列表(ID,Val)))' – RobinCura

回答

4

data.table/splitstackshape A液:

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 
+1

或使用'tstrsplit':'foo [,tstrsplit(strsplit(...)[[1]],','),。(ID,Val)]' – eddi

2

下面是一个方法,使用碱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

1)dplyr这会将数据帧到行和对每个这样的行使用gsub将每个三元组拆分成单独的行,并使用read.table进一步解析Geom。然后它修复列名称并执行ungroup。 (如果V1,V2和V3都是OK的,而不是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)) 

,并提供:在IRC

> 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