2016-08-11 51 views
1

我遇到了重新排列某些數據的問題。通過匹配列重新排列數據

原始數據是:

structure(list(id = 1:3, artery.1 = structure(c(1L, 1L, 2L), .Label = c("a", 
"b"), class = "factor"), artery.2 = structure(c(1L, NA, 2L), .Label = c("b", 
"c"), class = "factor"), artery.3 = structure(c(1L, NA, 2L), .Label = c("c", 
"d"), class = "factor"), artery.4 = structure(c(NA, NA, 1L), .Label = "e", class = "factor"), artery.5 = structure(c(NA, NA, 1L), .Label = "f", class = "factor"), 
diameter.1 = c(3L, 2L, 1L), diameter.2 = c(2L, NA, 2L), diameter.3 = c(3L, 
NA, 3L), diameter.4 = c(NA, NA, 4L), diameter.5 = c(NA, NA, 
5L)), .Names = c("id", "artery.1", "artery.2", "artery.3", 
"artery.4", "artery.5", "diameter.1", "diameter.2", "diameter.3", 
"diameter.4", "diameter.5"), class = "data.frame", row.names = c(NA, 
-3L)) 

# id artery.1 artery.2 artery.3 artery.4 artery.5 diameter.1 diameter.2 diameter.3 diameter.4 diameter.5 
# 1 1  a  b  c  <NA>  <NA>   3   2   3   NA   NA 
# 2 2  a  <NA>  <NA>  <NA>  <NA>   2   NA   NA   NA   NA 
# 3 3  b  c  d  e  f   1   2   3   4   5 

我想獲得該:

structure(list(id = 1:3, a = c(3L, 2L, NA), b = c(2L, NA, 1L), 
c = c(3L, NA, 2L), d = c(NA, NA, 3L), e = c(NA, NA, 4L), 
f = c(NA, NA, 5L)), .Names = c("id", "a", "b", "c", "d", 
"e", "f"), class = "data.frame", row.names = c(NA, -3L)) 

# id a b c d e f 
# 1 1 3 2 3 NA NA NA 
# 2 2 2 NA NA NA NA NA 
# 3 3 NA 1 2 3 4 5 

基本上,af表示動脈和數值表示對應的直徑。每一行代表一個病人。

有沒有一種簡潔的方法來排序這個數據框?

回答

3

使用tidyrdplyr包。

library(dplyr) 
library(tidyr) 

new.df <- gather(df, variable, value, artery.1:diameter.5) %>% 
    separate(variable, c('variable', 'num')) %>% 
    spread(variable, value) %>% 
    subset(!is.na(artery)) %>% 
    mutate(diameter = as.numeric(diameter)) %>% 
    select(-num) %>% 
    spread(artery, diameter) 

輸出:

id a b c d e f 
1 1 3 2 3 NA NA NA 
2 2 2 NA NA NA NA NA 
3 3 NA 1 2 3 4 5 
+1

注意'subset'不是'dplyr'。改用相同的語法來使用'filter'。 – AlexR

+0

簡化了一點:'df%>%gather(var,val,-id)%>%separate(var,c('var','num'))%>%spread(var,val,convert = TRUE) %>%select(-num)%>%na.omit()%>%spread(動脈,直徑)' – alistaire

+0

這很棒......像魅力一樣工作。謝謝你們的幫助。愛R和R社區! – user3919790

1

您可以使用xtabsreshape從基地R.使用後者的數據轉換爲長格式,使用前獲得伯爵表:

xtabs(diameter ~ id + artery, reshape(df, varying = 2:11, sep = '.', dir = "long")) 

# artery 
#id a b c d e f 
# 1 3 2 3 0 0 0 
# 2 2 0 0 0 0 0 
# 3 0 1 2 3 4 5 
+0

真的很簡潔,但是它用0代替「NA」填充缺失的值,不是嗎? – jdobres

+0

@jdobres是的。不完全如預期的輸出,但實際上它可能仍然工作取決於需要。除了用'NA'代替0應該是微不足道的。 – Psidom

1

這可以有兩個reshape()調用來完成。首先,我們可以在id上對arterydiameter進行修改,然後用artery作爲時間變量進行擴大。爲了防止一列NAs,我們還必須在中間幀中對具有NA值的行進行子集排列artery

reshape(subset(reshape(df,dir='l',varying=setdiff(names(df),'id'),timevar=NULL),!is.na(artery)),dir='w',timevar='artery'); 
##  id diameter.a diameter.b diameter.c diameter.d diameter.e diameter.f 
## 1.1 1   3   2   3   NA   NA   NA 
## 2.1 2   2   NA   NA   NA   NA   NA 
## 3.1 3   NA   1   2   3   4   5 

如果需要,diameter.前綴可以隨後刪除。但是,這種解決方案的一個優點是它能夠保留多個列集,而xtabs()解決方案則不能。在這種情況下,前綴對區分列集非常重要。

2

或者使用melt/dcastdata.table組合,而在patterns功能

library(data.table) #v>=1.9.6 
dcast(melt(setDT(df), 
      id = "id", 
      measure = patterns("artery", "diameter")), 
     id ~ value1, 
     sum, 
     value.var = "value2", 
     subset = .(!is.na(value2)), 
     fill = NA) 
# id a b c d e f 
# 1: 1 3 2 3 NA NA NA 
# 2: 2 2 NA NA NA NA NA 
# 3: 3 NA 1 2 3 4 5 

正如你所看到的,meltdcast選擇使用正則表達式的變量是非常靈活,你可以使用正則表達式,指定一個子集,傳遞多個函數並指定如何填充缺失的值。

+0

是的,我真的希望'tidyr :: gather'可以做這樣的平行聚會。相反,我最終做了很糟糕的事情,比如'df%>%do(bind_cols(gather(。,label1,artery,artery.1:artery.5),gather(。,label2,diameter,diameter.1:diameter.5) %>%select(-id)))%>%select(id,artery,diameter)%>%na。omit()%>%spread(動脈,直徑)' – alistaire

+0

@alistaire雖然我有'spread'的主要問題,但它沒有'fun.aggregate'參數。一旦不是所有的組合都是獨一無二的,那真是讓殘疾人無法接受。永遠不要理解爲什麼這個功能真的被刪除了 –

+0

是的,這對標識符有點挑剔。我認爲它只是爲了強制人們只用'summarise'來聚合,所以每個函數只做一件事情,以便更容易理解,人們不太可能用它們做可怕的事情。最終所有的重塑功能(甚至是「桌子」)都讓我有點瘋狂,每種都以他們獨特的方式。 – alistaire