2012-07-04 22 views
11

Tôi có một khung dữ liệu theo mẫu bên dưới dài:Transpose/reshape dataframe không có "timevar" từ lâu để định dạng rộng

Name   MedName 
    Name1 atenolol 25mg 
    Name1  aspirin 81mg 
    Name1 sildenafil 100mg 
    Name2 atenolol 50mg 
    Name2 enalapril 20mg 

Và muốn có được bên dưới (Tôi không quan tâm nếu tôi có thể nhận được các cột được đặt tên theo cách này, chỉ muốn các dữ liệu ở định dạng này):

Name medication1 medication2  medication3 
    Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
    Name2 atenolol 50mg enalapril 20mg    NA 

qua trang web rất này tôi đã trở thành familiarish với Reshape/gói reshape2, và đã trải qua nhiều nỗ lực để cố gắng có được điều này để làm việc nhưng cho đến nay đã thất bại.

Khi tôi cố gắng dcast(dataframe, Name ~ MedName, value.var='MedName') tôi chỉ nhận được một loạt các cột là lá cờ của các tên thuốc (giá trị mà có được hoán là 1 hoặc 0) Ví dụ:

Name atenolol 25mg aspirin 81mg 
Name1    1    1 
Name2    0    0 

Tôi cũng đã cố gắng một dcast(dataset, Name ~ variable) sau khi tôi tan chảy tập dữ liệu, tuy nhiên điều này chỉ spits ra như sau (chỉ đếm có bao nhiêu meds mỗi người có):

Name MedName 
Name1  3 
name2  2 

Cuối cùng, tôi đã cố gắng để làm tan chảy các dữ liệu và sau đó định hình lại sử dụng idvar="Name"timevar="variable" (trong đó tất cả chỉ là Mednam es), tuy nhiên điều này dường như không được xây dựng cho vấn đề của tôi vì nếu có nhiều kết quả phù hợp với idvar, việc định hình lại chỉ lấy MedName đầu tiên và bỏ qua phần còn lại.

Có ai biết cách thực hiện điều này bằng cách sử dụng chức năng định hình lại hoặc chức năng R khác không? Tôi nhận ra rằng có lẽ có một cách để làm điều này một cách lộn xộn hơn với một số vòng lặp và điều kiện để cơ bản chia và dán lại dữ liệu, nhưng tôi đã hy vọng có một giải pháp đơn giản hơn. Cảm ơn bạn rất nhiều!

Trả lời

13

Giả sử dữ liệu của bạn là trong đối tượng dataset

library(plyr) 
## Add a medication index 
data_with_index <- ddply(dataset, .(Name), mutate, 
         index = paste0('medication', 1:length(Name)))  
dcast(data_with_index, Name~ index, value.var = 'MedName') 

## Name medication1 medication2  medication3 
## 1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
## 2 Name2 atenolol 50mg enalapril 20mg    <NA> 
11

Bạn luôn có thể tạo ra một độc đáo timevar trước khi sử dụng reshape. Ở đây tôi sử dụng ave để áp dụng hàm seq_along 'dọc theo' mỗi "Tên".

test <- data.frame(
Name=c(rep("name1",3),rep("name2",2)), 
MedName=c("atenolol 25mg","aspirin 81mg","sildenafil 100mg", 
      "atenolol 50mg","enalapril 20mg") 
) 

# generate the 'timevar' 
test$uniqid <- with(test, ave(as.character(Name), Name, FUN = seq_along)) 

# reshape! 
reshape(test, idvar = "Name", timevar = "uniqid", direction = "wide") 

Kết quả:

Name  MedName.1  MedName.2  MedName.3 
1 name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
4 name2 atenolol 50mg enalapril 20mg    <NA> 
+0

Cảm ơn sự giúp đỡ, điều này đã hiệu quả. Tôi lo lắng về các cột, đó là trong tập dữ liệu thực tế của tôi, tôi có số lượng và tên thuốc thay đổi, vì vậy tuyên bố MedName = c (Tất cả tên) có thể hơi nhiều, nhưng tôi đánh giá cao sự trợ giúp và sẽ có thể sử dụng phương pháp này trên các vấn đề khác. – Hotamd6

+0

@ Hotamd6 - không cần chỉ định thủ công tất cả các tên - bạn chỉ cần tìm và thay thế tên tập dữ liệu như 'gsub (" MedName. "," Medicine ", tên (reshapedtestdata), fixed = TRUE)' để nhận cùng một kết quả như @mnel ở trên. – thelatemail

3

@ giải pháp thelatemail là tương tự như thế này. Khi tôi tạo biến thời gian, tôi sử dụng rle trong trường hợp tôi không hoạt động tương tác và biến số Name cần phải động.

# start with your example data 
x <- 
    data.frame(
     Name=c(rep("name1",3),rep("name2",2)), 
     MedName=c("atenolol 25mg","aspirin 81mg","sildenafil 100mg", 
      "atenolol 50mg","enalapril 20mg") 
    ) 

# pick the id variable 
id <- 'Name' 

# sort the data.frame by that variable 
x <- x[ order(x[ , id ]) , ] 

# construct a `time` variable on the fly 
x$time <- unlist(lapply(rle(as.character(x[ , id ]))$lengths , seq_len)) 

# `reshape` uses that new `time` column by default 
y <- reshape(x , idvar = id , direction = 'wide') 

# done 
y 
+0

Tôi không chắc chắn tôi hiểu nhận xét của bạn về việc sử dụng 'rle' khi biến" Tên "cần phải động. Giải pháp @ thelatemail sẽ không cho phép sự linh hoạt như vậy (và không phải sắp xếp dữ liệu trước)? – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto có thể bạn đúng .. tôi cho rằng bạn có thể sử dụng 'id <- 'Name'' và sau đó là' as.character (get (id)) 'trong dòng thứ hai đó và phần còn lại là động. –

7

Điều này dường như thực sự là một vấn đề khá phổ biến, vì vậy tôi đã bao gồm một chức năng gọi là getanID trong tôi gói "splitstackshape".

Dưới đây là những gì nó làm:

library(splitstackshape) 
getanID(test, "Name") 
#  Name   MedName .id 
# 1: name1 atenolol 25mg 1 
# 2: name1  aspirin 81mg 2 
# 3: name1 sildenafil 100mg 3 
# 4: name2 atenolol 50mg 1 
# 5: name2 enalapril 20mg 2 

Kể từ khi "data.table" được nạp cùng với "splitstackshape", bạn có thể truy cập dcast.data.table, vì vậy bạn có thể tiến hành như với ví dụ @ mnel của.

dcast.data.table(getanID(test, "Name"), Name ~ .id, value.var = "MedName") 
#  Name    1    2    3 
# 1: name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
# 2: name2 atenolol 50mg enalapril 20mg    NA 

Chức năng cơ bản thực hiện một sequence(.N) bởi các nhóm xác định để tạo ra "thời gian" cột.

6

Với gói data.table, điều này có thể dễ dàng được giải quyết với các rowid chức năng mới:

library(data.table) 
dcast(setDT(d1), 
     Name ~ rowid(Name, prefix = "medication"), 
     value.var = "MedName") 

mang đến cho:

Name medication1  medication2  medication3 
1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
2 Name2 atenolol 50mg enalapril 20mg    <NA> 

Phương pháp khác (thường được sử dụng trước khi phiên bản 1.9. 7):

dcast(setDT(d1)[, rn := 1:.N, by = Name], 
     Name ~ paste0("medication",rn), 
     value.var = "MedName") 

cho cùng một kết quả.


Một cách tiếp cận tương tự, nhưng bây giờ bằng cách sử dụng dplyrtidyr gói:

library(dplyr) 
library(tidyr) 
d1 %>% 
    group_by(Name) %>% 
    mutate(rn = paste0("medication",row_number())) %>% 
    spread(rn, MedName) 

mang đến cho:

Source: local data frame [2 x 4] 
Groups: Name [2] 

    Name medication1 medication2  medication3 
    (fctr)   (chr)   (chr)   (chr) 
1 Name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
2 Name2 atenolol 50mg enalapril 20mg    NA 
0

Đây là một cách ngắn hơn, tận dụng sự cách unlist giao dịch với tên:

library(dplyr) 
df1 %>% group_by(Name) %>% do(as_tibble(t(unlist(.[2])))) 
# # A tibble: 2 x 4 
# # Groups: Name [2] 
#  Name  MedName1  MedName2   MedName3 
#  <chr>   <chr>   <chr>   <chr> 
# 1 name1 atenolol 25mg aspirin 81mg sildenafil 100mg 
# 2 name2 atenolol 50mg enalapril 20mg    <NA>