2016-02-23 4 views
1

У меня есть dataframe, который выглядит следующим образом:Split колонки на несколько столбцов адаптивно в R

Name Value 
abc  Asia 
def  Asia/Africa 
gbc  Africa 
jhg  America/Africa/Asia 

Я хочу столбец Value быть разделены таким образом, что dataframe выглядит следующим образом:

Name Value.1 Value.2 Value.3 
abc  Asia 
def  Asia  Africa 
gbc  Africa 
jhg  America Africa Asia 

Я знаю, что есть похожие вопросы о stackoverflow (например, here, here), но они предполагают, что Значение можно разделить на одно и то же количество разделов для каждой строки. Так что, когда я пытаюсь запустить следующие команды:

out <- strsplit(as.character(df$Value),'/') 
do.call(rbind, out) 
data.frame(df$Value, do.call(rbind, out)) 

Он работает до второй линии, а затем дает мне следующую ошибку:

Error in data.frame(df$Value, do.call(rbind, : 
    arguments imply differing number of rows: 24819, 24707 
In addition: Warning message: 
In (function (..., deparse.level = 1) : 
    number of columns of result is not a multiple of vector length (arg 10) 

Я также посмотрел в reshape2 функции colSplit и tidyr функцию separate , Они также ожидают, что для каждой строки Значение может быть разделено на точно такое же количество компонентов, поэтому они ожидают, что я буду называть столбцы заранее.

мне интересно, там есть способ адаптивно имя разделить значение на отдельные столбцы называются значения.1, Value.2 ...

+1

Ваш вопрос лучше, так как вы включили пример, но я предполагаю, что это один и охватывает его: http://stackoverflow.com/q/26898833/1191259 – Frank

ответ

4

в базовой R:

df <- read.table(textConnection("Name Value 
abc  Asia 
def  Asia/Africa 
gbc  Africa 
jhg  America/Africa/Asia"), header=TRUE) 

out <- strsplit(as.character(df$Value),'/') 
out <- lapply(out, FUN=function(x) c(unlist(x), rep(NA, max(lengths(out))-length(x)))) 
out <- as.data.frame(cbind(df$Value,do.call(rbind, out))) 

    V1  V2  V3 V4 
1 3 Asia <NA> <NA> 
2 4 Asia Africa <NA> 
3 1 Africa <NA> <NA> 
4 2 America Africa Asia 

же подход, написал несколько иначе:

out <- strsplit(as.character(df$Value),'/') 
cbind(df[1], do.call(rbind, lapply(out, 'length<-', max(lengths(out))))) 
    Name  1  2 3 
1 abc Asia <NA> <NA> 
2 def Asia Africa <NA> 
3 gbc Africa <NA> <NA> 
4 jhg America Africa Asia 
+0

Вы можете использовать 'max (lengths (out))' как максимальную длину после 'strsplit' –

+0

Thanks @docendodiscimus – HubertL

+1

Добро пожаловать. Другой трюк заключается в использовании 'lapply (out, 'length <-', max (lengths (out))), который будет заполнять более короткие векторы с NAs –

3

Мы можем использовать cSplit

library(splitstackshape) 
cSplit(df1, 'Value', '/', 'wide') 
# Name Value_1 Value_2 Value_3 
#1: abc Asia  NA  NA 
#2: def Asia Africa  NA 
#3: gbc Africa  NA  NA 
#4: jhg America Africa Asia 

В base R, мы могли бы просто сделать

cbind(df1[1],read.table(text=df1$Value, sep='/', fill=TRUE)) 
# Name  V1  V2 V3 
#1 abc Asia    
#2 def Asia Africa  
#3 gbc Africa    
#4 jhg America Africa Asia 
4

См data.table, который автоматически заполняет неровный шпагат tstrsplitNA по умолчанию, но можно управлять с помощью fill аргумента):

library(data.table) 
setDT(df1)[ , tstrsplit(Value, split = "/")] 

Если вы хотите добавить их в качестве столбцов данных, это немного уродливее сделать динамически

setDT(df1)[ , paste0("V", 1:max(sapply(spl <- strsplit(x, "/"), length))) := 
       transpose(spl)]