2016-04-20 39 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