2012-07-04 58 views
11

我有如下的下方多頭格局數據幀:移調/重塑數據框中沒有「timevar」從長到寬幅

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

,並希望得到以下(我不在乎,如果我能得到列被命名這種方式,只是想在這個格式的數據):通過這個非常網站,我已經成爲familiarish與重塑/ reshape2包

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

,並通過多次嘗試都去嘗試得到這個工作但迄今失敗。

當我嘗試dcast(dataframe, Name ~ MedName, value.var='MedName')我只是得到了一堆屬於藥物名稱的標誌列(即獲得轉置值是0或1)例如:

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

我也嘗試了dcast(dataset, Name ~ variable)我融化後數據集,然而,這只是吐出以下(只計算每個人多少吃藥了):

Name MedName 
Name1  3 
name2  2 

最後,我試圖融化的數據,然後重塑使用idvar="Name"timevar="variable"(所有這些都只是Mednam es),但是這似乎並不適合我的問題,因爲如果有多個匹配的idvar,重塑只需要第一個MedName並忽略其餘。

有誰知道如何使用重塑或其他R功能來做到這一點?我意識到可能有一種方法可以以更加混亂的方式執行此操作,其中一些for循環和條件可以基本拆分並重新粘貼數據,但我希望有更簡單的解決方案。非常感謝!

回答

13

假設你的數據在對象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

使用reshape之前,你總是可以生成一個唯一的timevar。在這裏,我使用ave將函數seq_along'沿着每個「名稱」應用。

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") 

結果:

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

感謝您的幫助,這工作。我的一個擔心列,是在我的實際數據集中,我有一個不斷變化的數字和藥物名稱,所以聲明MedName = c(所有名稱)可能會有點多,但我感謝幫助,並會可能在其他問題上使用這種方法。 – Hotamd6

+0

@ Hotamd6 - 無需手動指定所有名稱 - 只需在數據集名稱(如gsub(「MedName。」,「medication」,names(reshapedtestdata),fixed = TRUE))上進行查找和替換即可獲得與上面的@mnel相同的結果。 – thelatemail

3

@ thelatemail的解決方案是與此類似。當我生成時間變量時,我使用rle以防萬一我不以交互方式工作,並且Name變量需要動態變化。

# 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

當「Name」變量需要動態時,我不確定我是否理解了關於使用'rle'的評論。 Thelatemail的解決方案是否也允許這種靈活性(並且不必首先對數據進行排序)? – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto也許你是對的..我想你可以在第二行使用'id' - 'Name''然後'as.character(get(id))',然後剩下的就是動態的。 –

7

這似乎實際上是一個相當普遍的問題,所以我已經包括在我的「splitstackshape」呼包getanID功能。

下面是它做什麼:

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 

由於「data.table」與「splitstackshape」一起加載,您可以訪問dcast.data.table,這樣你就可以與@ MNEL的例子進行。

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 

功能基本實現了sequence(.N)通過鑑定打造的「時間」欄目組。

6

隨着data.table包,這可以很容易地與新的rowid功能解決:

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

其給出:

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

的另一種方法(1.9版本之前常用。 7):

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

給予相同的結果。


類似的方法,但現在使用dplyrtidyr包:

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

這給:

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

這裏有一個較短的方式,採取優勢用unlist處理名稱:

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>