2015-11-05 34 views
0

我有許多變量,其中許多變量都有缺失值,包括第一次和最後一次觀察值。我想要一個新的數據集,它包含每個人的第一個和最後一個觀察值,忽略錯誤。在很多變量中存在NA的head()和tail()

在下面的代碼做的,但我希望1)有一些功能是類似於head(),但無需拆卸NA小號手動,2)的方式來寫一個函數dplyrsummarize_each()可以使用該數據集中的所有變量自動化(比id等,當然)

set.seed(23331) 
df <- data.frame(id=rep(c(1,2,3,4), each = 5), 
       a = c(NA, rnorm(4), rnorm(3), rep(NA, 2), rnorm(4), rep(NA, 5), rnorm(1)), 
       b = c(rep(NA, 2), rnorm(14), rep(NA, 3), rnorm(1))) 
df %>% group_by(id) %>% summarise(a.head=head(a[!is.na(a)], n=1), 
            a.tail=tail(a[!is.na(a)], n=1), 
            b.head=head(b[!is.na(b)], n=1), 
            b.tail=tail(b[!is.na(b)], n=1)) %>% 
    gather("type", "value", -id) %>% 
    separate(type, into = c("variable", "time"), sep = "\\.") %>% 
    spread(variable, value) 

我希望爲dplyr解決方案,但會採取basedata.table解決方案,如果其中之一是去了解的最佳方式它。

所需的輸出:

來源:本地數據幀[8×4]

 id time   a   b 
    (dbl) (chr)  (dbl)  (dbl) 
1  1 head -0.5877282 0.4975612 
2  1 tail -0.7904277 -0.3860010 
3  2 head 0.5872134 -0.3923887 
4  2 tail -0.3222003 0.3114662 
5  3 head -0.2553290 0.7521095 
6  3 tail 0.3095699 -0.9113326 
7  4 head -0.3809334 1.4752274 
8  4 tail -0.3809334 3.2767918 
+1

可以減少幾個步驟'DF%>%GROUP_BY(ID)%>%summarise_each(玩意兒(頭=頭([ (。)],n = 1),Tail = tail(。[!is.na(。)],n = 1)))%>%gather(Var,Val,-id)%>%單獨的(Var,c('Variable','time'))%>%spread(Variable,Val)' – akrun

+1

(1)'na.omit(x)'比'x [!is.na x)]的'; (2)爲了進一步提高可讀性,爲什麼不寫輔助函數(例如'hn1 < - function(x)head(na.omit(x),1)')? –

回答

2

我們的 'data.frame' 轉換爲 'data.table'(setDT(df))中,由「ID分組',我們循環遍歷Data.table的子集(lapply(.SD,..)並且領導每列的headtail

library(data.table) 
f1 <- function(x, n) {x1 <- x[!is.na(x)]; c(head(x1,n), tail(x1,n))} 
setDT(df)[,lapply(.SD, f1, n=1) ,id][, time:= c('head', 'tail')][] 

或者使用melt/dcast

DT <- setDT(df)[,melt(lapply(.SD, function(x) list(head=head(x[!is.na(x)],1), 
       tail=tail(x[!is.na(x)],1)))) ,id] 
dcast(DT, id+L2~L1, value.var='value') 
+2

我想你可以定義像'Myfunc < - function(x){tmp < - x [!is.na(x)]; c(tmp [1L],tmp [length(tmp)])}'然後可以在'setDT(df)[,lapply(。SD,Myfunc),by = id]'和'df%>%group_by(id)%>%summarise_each(funs(Myfunc))''。你仍然需要添加'時間'變種btw。 –

+0

@DavidArenburg你是對的。在第一個選項中,我手動生成了'time',但'melt/dcast'應該自動獲得列。 – akrun

1

dplyr不適合轉換導致了一些比1n()其他行的。

要留在這個世界中,你可以使用(只要我見過)低效do

library(magrittr) 
ht_nona = . %>% na.omit %>% { c(first(.), dplyr::last(.)) } 

df %>% group_by(id) %>% do(as.data.frame(lapply(., ht_nona))) 

另一個(甚至可以說更糟糕)的辦法是summarise兩次,並結合行:

bind_rows(
    df %>% group_by(id) %>% summarise_each(funs(. %>% na.omit %>% first)), 
    df %>% group_by(id) %>% summarise_each(funs(. %>% na.omit %>% (dplyr::last))) 
) 
與data.table
+0

我意識到這並沒有發佈後的頭/尾欄;並認爲這樣做太麻煩了。希望這個信息足夠清楚:dplyr似乎不適合這個。 – Frank

0

上@ akrun的答案的變化,再次:

library(data.table) 

setDT(df)[, c(
    list(time=c("head","tail")), 
    lapply(.SD, function(v) setDT(list(v))[!is.na(V1)][c(1,.N), V1]) 
), by=id] 

    id time   a   b 
1: 1 head -0.5877282 0.4975612 
2: 1 tail -0.7904277 -0.3860010 
3: 2 head 0.5872134 -0.3923887 
4: 2 tail -0.3222003 0.3114662 
5: 3 head -0.2553290 0.7521095 
6: 3 tail 0.3095699 -0.9113326 
7: 4 head -0.3809334 1.4752274 
8: 4 tail -0.3809334 3.2767918 

setDT(list(v))borrowed from @eddi

1

不利的一面是,這其中需要包

set.seed(23331) 
df <- data.frame(id=rep(c(1,2,3,4), each = 5), 
       a = c(NA, rnorm(4), rnorm(3), rep(NA, 2), rnorm(4), rep(NA, 5), rnorm(1)), 
       b = c(rep(NA, 2), rnorm(14), rep(NA, 3), rnorm(1))) 

library('base') 
library('utils') 
library('stats') 

data.frame(id = rep(1:4, each = 2), time = c('head', 'tail'), 
      sapply(df[, -1], function(x) unlist(tapply(x, df$id, FUN = function(y) 
      c(head(na.omit(y), 1), tail(na.omit(y), 1)))))) 

# id time   a   b 
# 11 1 head -0.5877282 0.4975612 
# 12 1 tail -0.7904277 -0.3860010 
# 21 2 head 0.5872134 -0.3923887 
# 22 2 tail -0.3222003 0.3114662 
# 31 3 head -0.2553290 0.7521095 
# 32 3 tail 0.3095699 -0.9113326 
# 41 4 head -0.3809334 1.4752274 
# 42 4 tail -0.3809334 3.2767918 
+0

您可能想要提供有關笑話的提示(所有這些軟件包都包含在基本安裝中)。 – Frank

相關問題