2015-04-28 2 views
2

У меня есть следующий ДФ, который был получен из файла Excel:Преобразуя информацию из кадра данных в R

df1 <- data.frame(Colour = c("Green","Red","Blue"), 
        Code = c("N","U", "U"), 
        User1 = c("John","Brad","Peter"), 
        User2 = c("Meg","Meg","John"), 
        User3= c("", "Lucy", "")) 

Мне нужно, чтобы изменить его, чтобы получить кадр данных, где все имена перечислены в первый столбец (только один раз), и цвет (и соответствующие коды) отображаются в следующих столбцах, как показаны на рисунке:

df2 <- data.frame(User=c("John","Brad","Peter","Meg","Lucy"), 
        Color1 = c("Green","Red","Blue","Green","Red"), 
        Code1 = c("N","U","U","N","U"), 
        Color2=c("Blue","","","Red",""), 
        Code2=c("U","","","U","")) 

ценит я бы некоторую помощь. Огромное спасибо,

ответ

4

Это не красиво, но вот еще одно решение в чистом базовом R, который использует пару звонков в reshape():

reshape(transform(subset(reshape(df1,varying=grep('^User',names(df1)),dir='l',v.names='User'),User!=''),id=NULL,time=ave(c(User),User,FUN=seq_along),User=factor(User)),dir='w',idvar='User',sep=''); 
##  User Colour1 Code1 Colour2 Code2 
## 1.1 John Green  N Blue  U 
## 2.1 Brad  Red  U <NA> <NA> 
## 3.1 Peter Blue  U <NA> <NA> 
## 1.2 Meg Green  N  Red  U 
## 2.3 Lucy  Red  U <NA> <NA> 
3

Мы можем использовать dcast от версии devel data.table, то есть v1.9.5 +. Это может занимать несколько столбцов value.var. Мы преобразуем data.frame в data.table (setDT(df1)), melt данные с столбцами id как «Цвет» и «Код», удалите строки, в которых «Пользователь» не равен «» ([User!='']), создайте последовательность группировки на основе « Пользовательский столбец и dcast. Инструкции по установке являются here

library(data.table)#v1.9.5+ 
dcast(melt(setDT(df1), id.var=c('Colour', 'Code'), 
      value.name='User')[User!=''][, 
       N:=1:.N, User], User~N, value.var=c('Colour', 'Code')) 
# User 1_Colour 2_Colour 1_Code 2_Code 
#1: Brad  Red  NA  U  NA 
#2: John Green  Blue  N  U 
#3: Lucy  Red  NA  U  NA 
#4: Meg Green  Red  N  U 
#5: Peter  Blue  NA  U  NA 

Или, как @Arun упоминалось в комментариях, мы можем использовать subset аргумента в dcast вместо [User!='']

dcast(melt(setDT(df1), id.var=c('Colour', 'Code'), 
      value.name='User')[,N:= 1:.N, User], 
     subset=.(User !=''), User~N, value.var=c('Colour', 'Code')) 
# User 1_Colour 2_Colour 1_Code 2_Code 
#1: Brad  Red  NA  U  NA 
#2: John Green  Blue  N  U 
#3: Lucy  Red  NA  U  NA 
#4: Meg Green  Red  N  U 
#5: Peter  Blue  NA  U  NA 
+2

вы можете используйте 'subset =. (User! =" ")' непосредственно в 'dcast' – Arun

+0

@Arun Спасибо, это полезно. – akrun

4

Я смущаюсь этот пост из-за концептуальное сходство с ответом @ akrun, но вы можете сделать это также с merged.stack из моего пакета «splitstackshape» вместе с reshape из базы R.

library(splitstackshape) 
reshape(
    getanID(
    merged.stack(df1, var.stubs = "User", sep = "var.stubs")[User != ""], 
    "User"), 
    direction = "wide", idvar = "User", timevar = ".id", drop = ".time_1") 
#  User Colour.1 Code.1 Colour.2 Code.2 
# 1: Peter  Blue  U  NA  NA 
# 2: John  Blue  U Green  N 
# 3: Meg Green  N  Red  U 
# 4: Brad  Red  U  NA  NA 
# 5: Lucy  Red  U  NA  NA 

merged.stack делает длинными данные, getanID создает переменную ID для использования при переходе к широкой форме, reshape делает фактическое преобразование из этого полушироких форм в широкую форму.


Это было лучшее, что я мог придумать для пользователей «dplyr» + «tidyr». Кажется довольно громоздким, но не должно быть слишком трудно следовать:

library(dplyr) 
library(tidyr) 

df1 %>% 
    gather(var, User, User1:User3) %>%  # Get the data into a long form 
    filter(User != "") %>%     # Drop empty rows 
    group_by(User) %>%      # Group by User 
    mutate(Id = sequence(n())) %>%   # Create a new id variable 
    gather(var2, value, Colour, Code) %>% # Go long a second time 
    unite(Key, var2, Id) %>%    # Combine values to create a key 
    spread(Key, value, fill = "")   # Convert back to a wide form 
# Source: local data frame [6 x 6] 
# 
#  var User Code_1 Code_2 Colour_1 Colour_2 
# 1 User1 Brad  U    Red   
# 2 User1 John  N   Green   
# 3 User1 Peter  U   Blue   
# 4 User2 John    U    Blue 
# 5 User2 Meg  N  U Green  Red 
# 6 User3 Lucy  U    Red   
Смежные вопросы