したがって、「エレガント」な要件を満たすかどうかはわかりませんが、バランスの取れたデータを取得するために使用できる汎用関数を次に示します。
balanced<-function(data, ID, TIME, VARS, required=c("all","shared")) {
if(is.character(ID)) {
ID <- match(ID, names(data))
}
if(is.character(TIME)) {
TIME <- match(TIME, names(data))
}
if(missing(VARS)) {
VARS <- setdiff(1:ncol(data), c(ID,TIME))
} else if (is.character(VARS)) {
VARS <- match(VARS, names(data))
}
required <- match.arg(required)
idf <- do.call(interaction, c(data[, ID, drop=FALSE], drop=TRUE))
timef <- do.call(interaction, c(data[, TIME, drop=FALSE], drop=TRUE))
complete <- complete.cases(data[, VARS])
tbl <- table(idf[complete], timef[complete])
if (required=="all") {
keep <- which(rowSums(tbl==1)==ncol(tbl))
idx <- as.numeric(idf) %in% keep
} else if (required=="shared") {
keep <- which(colSums(tbl==1)==nrow(tbl))
idx <- as.numeric(timef) %in% keep
}
data[idx, ]
}
で目的の結果を得ることができます
balanced(unbal, "PERSON","YEAR")
# PERSON YEAR Y X
# 1 Frank 2001 21 1
# 2 Frank 2002 22 2
# 3 Frank 2003 23 3
# 4 Frank 2004 24 4
# 5 Frank 2005 25 5
# 11 Edward 2001 31 11
# 12 Edward 2002 32 12
# 13 Edward 2003 33 13
# 14 Edward 2004 34 14
# 15 Edward 2005 35 15
最初のパラメーターは、サブセット化する data.frame です。2 番目のパラメーター ( ID=
) は、データセット内の各 "人" を識別する列名の文字ベクトルです。この場合、TIME=
パラメーターは、ID ごとに異なる観測時間を指定する文字ベクトルでもあります。最後に、オプションでVARS=
引数を指定して、どのフィールドを NA にする必要があるかを指定できます (デフォルトは ID または TIME 値以外のすべて)。required
最後に、各 ID が TIME ごとに観測値を持つ必要があるかどうか (デフォルト)、または「共有」に設定した場合は、すべての ID が欠損値のない TIMES のみを返すかどうかを示す名前付きの最後のパラメーターが 1 つあります。
たとえば
balanced(unbal, "PERSON","YEAR", "X")
# PERSON YEAR Y X
# 1 Frank 2001 21 1
# 2 Frank 2002 22 2
# 3 Frank 2003 23 3
# 4 Frank 2004 24 4
# 5 Frank 2005 25 5
# 6 Tony 2001 5 6
# 7 Tony 2002 6 7
# 8 Tony 2003 NA 8
# 9 Tony 2004 7 9
# 10 Tony 2005 8 10
# 11 Edward 2001 31 11
# 12 Edward 2002 32 12
# 13 Edward 2003 33 13
# 14 Edward 2004 34 14
# 15 Edward 2005 35 15
すべての PERSON/YEARS に対して "X" が NA であることのみが必要であり、これはすべてのレコードに当てはまるため、サブ設定は行われません。
もしあなたがそうするなら
balanced(unbal, "PERSON","YEAR", required="shared")
# PERSON YEAR Y X
# 1 Frank 2001 21 1
# 2 Frank 2002 22 2
# 4 Frank 2004 24 4
# 5 Frank 2005 25 5
# 6 Tony 2001 5 6
# 7 Tony 2002 6 7
# 9 Tony 2004 7 9
# 10 Tony 2005 8 10
# 11 Edward 2001 31 11
# 12 Edward 2002 32 12
# 14 Edward 2004 34 14
# 15 Edward 2005 35 15
次に、2001 年、2002 年、2004 年、2005 年のすべての人のデータを取得します。
ここで、少し異なるサンプル データ セットを作成してみましょう
unbal2 <- unbal
unbal2[15, 2] <- 2006
tail(unbal2)
# PERSON YEAR Y X
# 10 Tony 2005 8 10
# 11 Edward 2001 31 11
# 12 Edward 2002 32 12
# 13 Edward 2003 33 13
# 14 Edward 2004 34 14
# 15 Edward 2006 35 15
ここで、2006 年の値を持つ人物は Edward だけであることに注意してください。これは、次のことを意味します。
balanced(unbal2, "PERSON","YEAR")
# [1] PERSON YEAR Y X
# <0 rows> (or 0-length row.names)
今は何も返しません
balanced(unbal2, "PERSON","YEAR", required="shared")
# PERSON YEAR Y X
# 1 Frank 2001 21 1
# 2 Frank 2002 22 2
# 4 Frank 2004 24 4
# 6 Tony 2001 5 6
# 7 Tony 2002 6 7
# 9 Tony 2004 7 9
# 11 Edward 2001 31 11
# 12 Edward 2002 32 12
# 14 Edward 2004 34 14
すべての人がこれらの年のデータを持っているため、2001、2002、2004 のデータが返されます。