2016-06-09 3 views
1

Я работаю над решением для очистки некоторых данных, но не на 100% уверен, что лучшее решение. Я нашел рабочее решение, но хотел бы знать, был ли более простой подход (особенно при попытке масштабировать его). То, что я хотел бы сделать, - это выделить все элементы в кадре данных (разделенные точкой с запятой), применить каждый из этих компонентов к элементу фрейма данных, а затем объединить результаты в новый фрейм данных. Пример ниже:Цитирование через кадр данных для создания нового фрейма данных

test <- data.frame(class=c("a1", "a2","a3","a4"), 
     person=c("p1;p3;p4","p2;p4","p4;p5;p6","p1;p5"), 
     stringsAsFactors = F) 

test1 <- c() 
test2 <- c() 

for (i in 1:nrow(test)){ 
    test1 <-append(test1, strsplit(test[i,2],";")[[1]]) 
    test2 <- append(test2, rep(test[i,1],length(strsplit(test[i,2],";")[[1]]))) 
} 

ответ

1

Мы можем использовать cSplit из splitstackshape (здесь я упомянул один пакет и используется один и не входит в другую), чтобы разделить колонку «человек» разделителем ; и указать direction в long, чтобы изменить формат «длинных» после того, Трещина.

library(splitstackshape) 
cSplit(test, 'person', ';', 'long') 
# class person 
# 1: a1  p1 
# 2: a1  p3 
# 3: a1  p4 
# 4: a2  p2 
# 5: a2  p4 
# 6: a3  p4 
# 7: a3  p5 
# 8: a3  p6 
# 9: a4  p1 
#10: a4  p5 

Или еще один вкладыш из base R (без использования каких-либо пакетов)

stack(setNames(strsplit(test$person, ";"), test$class))[2:1] 
1

Это немного многословным Oneliner будет делать это, если я понимаю, именно то, что вы пытаетесь сделать:

do.call("rbind",apply(test, 1, function(x) expand.grid(x[1], unlist(strsplit(x[2], split=";"))))) 

    Var1 Var2 
1 a1 p1 
2 a1 p3 
3 a1 p4 
4 a2 p2 
5 a2 p4 
6 a3 p4 
7 a3 p5 
8 a3 p6 
9 a4 p1 
10 a4 p5 

Я использую expand.grid на каждой строке исходного dataframe, в том числе первая переменная и вторая переменная, разделенная на ;. В результате apply - это список, затем я использую do.call с rbind, чтобы вернуть его в кадр данных.

1

С tidyr:

library(dplyr) 
library(tidyr) 

     # separate person into multiple columns 
test %>% separate(person, into = paste0('person', 1:5), fill = 'right') %>% 
    # gather from wide to long 
    gather(key = id, value = person, -class, na.rm = TRUE) %>% 
    # clean up extra column 
    select(-id) 

# class person 
# 1  a1  p1 
# 2  a2  p2 
# 3  a3  p4 
# 4  a4  p1 
# 5  a1  p3 
# 6  a2  p4 
# 7  a3  p5 
# 8  a4  p5 
# 9  a1  p4 
# 11 a3  p6 
Смежные вопросы