Dplyrに関する次の問題を解決したいと思います。ウィンドウ関数のいずれかで好ましい。家と購入価格のデータフレームがあります。次に例を示します。
houseID year price
1 1995 NA
1 1996 100
1 1997 NA
1 1998 120
1 1999 NA
2 1995 NA
2 1996 NA
2 1997 NA
2 1998 30
2 1999 NA
3 1995 NA
3 1996 44
3 1997 NA
3 1998 NA
3 1999 NA
このようなデータフレームを作成したいと思います。
houseID year price
1 1995 NA
1 1996 100
1 1997 100
1 1998 120
1 1999 120
2 1995 NA
2 1996 NA
2 1997 NA
2 1998 30
2 1999 30
3 1995 NA
3 1996 44
3 1997 44
3 1998 44
3 1999 44
適切な形式のデータを次に示します。
# Number of houses
N = 15
# Data frame
df = data.frame(houseID = rep(1:N,each=10), year=1995:2004, price =ifelse(runif(10*N)>0.15, NA,exp(rnorm(10*N))))
それを行う方法はありますか?
これらはすべてna.locf
Zooパッケージから。 na.locf0
(Zooでも定義されています)はna.locf
デフォルト以外はna.rm = FALSE
および単一のベクトル引数が必要です。 na.locf2
最初のソリューションで定義されたものは、他のいくつかでも使用されます。
dplyr
library(dplyr)
library(Zoo)
na.locf2 <- function(x) na.locf(x, na.rm = FALSE)
df %>% group_by(houseID) %>% do(na.locf2(.)) %>% ungroup
与える:
Source: local data frame [15 x 3]
Groups: houseID
houseID year price
1 1 1995 NA
2 1 1996 100
3 1 1997 100
4 1 1998 120
5 1 1999 120
6 2 1995 NA
7 2 1996 NA
8 2 1997 NA
9 2 1998 30
10 2 1999 30
11 3 1995 NA
12 3 1996 44
13 3 1997 44
14 3 1998 44
15 3 1999 44
これのバリエーションは次のとおりです。
df %>% group_by(houseID) %>% mutate(price = na.locf0(price)) %>% ungroup
以下のその他のソリューションでは、出力が非常に似ているため、形式が大幅に異なる場合を除いて繰り返しません。
もう1つの可能性は、by
ソリューション(さらに下に表示)とdplyrを組み合わせることです。
df %>% by(df$houseID, na.locf2) %>% bind_rows
by
library(Zoo)
do.call(rbind, by(df, df$houseID, na.locf2))
ave
library(Zoo)
transform(df, price = ave(price, houseID, FUN = na.locf0))
data.table
library(data.table)
library(Zoo)
data.table(df)[, na.locf2(.SD), by = houseID]
Zooこのソリューションでは、Zooのみを使用しています。長い結果ではなく、広い結果を返します。
library(Zoo)
z <- read.Zoo(df, index = 2, split = 1, FUN = identity)
na.locf2(z)
与える:
1 2 3
1995 NA NA NA
1996 100 NA 44
1997 100 NA 44
1998 120 30 44
1999 120 30 44
このソリューションは、次のようにdplyrと組み合わせることができます。
library(dplyr)
library(Zoo)
df %>% read.Zoo(index = 2, split = 1, FUN = identity) %>% na.locf2
入力
上記の例で使用される入力は次のとおりです。
df <- structure(list(houseID = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 3L, 3L, 3L, 3L, 3L), year = c(1995L, 1996L, 1997L, 1998L,
1999L, 1995L, 1996L, 1997L, 1998L, 1999L, 1995L, 1996L, 1997L,
1998L, 1999L), price = c(NA, 100L, NA, 120L, NA, NA, NA, NA,
30L, NA, NA, 44L, NA, NA, NA)), .Names = c("houseID", "year",
"price"), class = "data.frame", row.names = c(NA, -15L))
[〜#〜] revised [〜#〜]ソリューションを再配置して追加しました。最新の変更dplyrに適合するようにdplyr/Zooソリューションを修正しました。固定および因数分解を適用na.locf2
すべてのソリューションから。
tidyr::fill
で、これはばかげて簡単になりました。
library(dplyr)
library(tidyr)
# or library(tidyverse)
df %>% group_by(houseID) %>% fill(price)
# Source: local data frame [15 x 3]
# Groups: houseID [3]
#
# houseID year price
# (int) (int) (int)
# 1 1 1995 NA
# 2 1 1996 100
# 3 1 1997 100
# 4 1 1998 120
# 5 1 1999 120
# 6 2 1995 NA
# 7 2 1996 NA
# 8 2 1997 NA
# 9 2 1998 30
# 10 2 1999 30
# 11 3 1995 NA
# 12 3 1996 44
# 13 3 1997 44
# 14 3 1998 44
# 15 3 1999 44
data.table
でサポートされているローリング自己結合を実行できます。
require(data.table)
setDT(df) ## change it to data.table in place
setkey(df, houseID, year) ## needed for fast join
df.woNA <- df[!is.na(price)] ## version without the NA rows
# rolling self-join will return what you want
df.woNA[df, roll=TRUE] ## will match previous year if year not found
純粋なdplyrソリューション(動物園なし)。
df %>%
group_by(houseID) %>%
mutate(price_change = cumsum(0 + !is.na(price))) %>%
group_by(price_change, add = TRUE) %>%
mutate(price_filled = nth(price, 1)) %>%
ungroup() %>%
select(-price_change) -> df2
サンプルソリューションの興味深い部分は、df2の最後にあります。
> tail(df2, 20)
Source: local data frame [20 x 4]
houseID year price price_filled
1 14 1995 NA NA
2 14 1996 NA NA
3 14 1997 NA NA
4 14 1998 NA NA
5 14 1999 0.8374778 0.8374778
6 14 2000 NA 0.8374778
7 14 2001 NA 0.8374778
8 14 2002 NA 0.8374778
9 14 2003 2.1918880 2.1918880
10 14 2004 NA 2.1918880
11 15 1995 NA NA
12 15 1996 0.3982450 0.3982450
13 15 1997 NA 0.3982450
14 15 1998 1.7727000 1.7727000
15 15 1999 NA 1.7727000
16 15 2000 NA 1.7727000
17 15 2001 NA 1.7727000
18 15 2002 7.8636329 7.8636329
19 15 2003 NA 7.8636329
20 15 2004 NA 7.8636329
dplyr
とimputeTS
の組み合わせ。
library(dplyr)
library(imputeTS)
df %>% group_by(houseID) %>%
mutate(price = na.locf(price, na.remaining="keep"))
na.locf
をimputeTS
からのより高度な欠損データ置換(補完)関数に置き換えることもできます。たとえば、na.interpolation
またはna.kalman
です。このためには、na.locf
を好きな関数の名前に置き換えてください。
dplyr
なし:
prices$price <-unlist(lapply(split(prices$price,prices$houseID),
function(x) Zoo::na.locf(x,na.rm=FALSE)))
prices
houseID year price
1 1 1995 NA
2 1 1996 100
3 1 1997 100
4 1 1998 120
5 1 1999 120
6 2 1995 NA
7 2 1996 NA
8 2 1997 NA
9 2 1998 30
10 2 1999 30
11 3 1995 NA
12 3 1996 44
13 3 1997 44
14 3 1998 44
15 3 1999 44