2015-03-15 3 views
2

у меня есть кадр данных (DF):Преобразование столбца в несколько столбцов по группам

group col 
a  12 
a  15 
a  13 
b  21 
b  23 

Желаемый выход также кадр данных (DF1):

col1 col2 
12 21 
15 23 
13 0 

Namley, я хочу раздел «col» из «df» по «группе» в несколько столбцов как «col1» и «col2».

Когда длина каждого столбца не равна друг другу, «конец» должен быть добавлен к концу каждого столбца до тех пор, пока длина каждого столбца не достигнет максимальной длины столбца.

ответ

4

Мы могли бы использовать либо base R функции split или unstack разделить «COL» на «группы» в списке, то прокладка NA в список элементов, которые меньше, чем максимальная длина элемента списка. Изменение имен столбцов, замените 'NA' на 0.

lst <- unstack(df1, col~group) 
    d1 <- as.data.frame(sapply(lst, `length<-`, max(sapply(lst, length)))) 
    d1[is.na(d1)] <- 0 
    colnames(d1) <- paste0('col', 1:ncol(d1)) 
    d1 
# col1 col2 
#1 12 21 
#2 15 23 
#3 13 0 

Или используйте stri_list2matrix из stringi

library(stringi) 
d1 <- as.data.frame(stri_list2matrix(unstack(df1, col~group), 
      fill=0), stringsAsFactors=FALSE) 
d1[] <- lapply(d1, as.numeric) 

Или с помощью data.table/splitstackshape

library(splitstackshape) 
setnames(dcast(getanID(df1, 'group'), .id~group, value.var='col', 
      fill=0L)[, .id:= NULL], paste0('col', 1:2))[] 
# col1 col2 
#1: 12 21 
#2: 15 23 
#3: 13 0 
+0

спасибо много. Это работает очень хорошо, как всегда. – oercim

4

Как это сделать с dplyr ...

library(dplyr) 
library(tidyr) 

df1 %>% 
    group_by(group) %>% 
    mutate(n = row_number()) %>% 
    spread(group, col) %>% 
    select(-n) %>% 
    (function(x) { x[is.na(x)] <- 0; x }) 
+0

Я работал над аналогичным решением, но использовал 'mutate_each (funs (ifelse (is.na (.), 0,.)))' Для замены NA. –

+0

Конечно! Он выглядит еще более изящным. С другой стороны - подмножество немного быстрее, чем ifelse ... – bergant

3

Поскольку вы заполняете нулями, еще одна идея:

xtabs(col ~ ave(DF$col, DF$group, FUN = seq_along) + group, DF) 
#          group 
#ave(DF$col, DF$group, FUN = seq_along) a b 
#          1 12 21 
#          2 15 23 
#          3 13 0 

Где "DF":

DF = structure(list(group = structure(c(1L, 1L, 1L, 2L, 2L), .Label = c("a", 
"b"), class = "factor"), col = c(12L, 15L, 13L, 21L, 23L)), .Names = c("group", 
"col"), class = "data.frame", row.names = c(NA, -5L)) 
Смежные вопросы