Так я не уверен, что это удовлетворяет «элегантное» требование, но вот функция общего назначения вы можете использовать, чтобы получить сбалансированные данные.
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 вы хотите подмножество. Второй параметр (ID=
) является символьным вектором имен столбцов, которые идентифицируют каждого «человека» в наборе данных. Затем параметр TIME=
также является символьным вектором, определяющим разные времена наблюдения для каждого идентификатора. Наконец, вы можете указать аргумент VARS=
, чтобы указать, какие поля должны быть NA (по умолчанию все значения, отличные от ID или TIME). Наконец, есть один последний параметр с именем required
, в котором указано, должен ли каждый идентификатор иметь наблюдение за каждым ВРЕМЕНИ (по умолчанию), или если вы установили его в «общий», он вернет только TIMES, для которых все идентификаторы имеют не пропущенные значения.
Так, например
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
требует только то, что «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 г. Это означает, что
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 г., поскольку все лица имеют данные для в те годы.
Если кто-то заинтересованы в наоборот (сделать несбалансированную панель сбалансирована, заполнив НСБ), можно использовать функцию 'сделать .pbalanced' из пакета 'plm' (последняя версия разработки требуется от https://r-forge.r-project.org/R/?group_id=406) – Helix123
Официальный релиз CRAN (1.6-4) из plm теперь имеет' make.pbalanced 'объединены (и по аргументу' balance.type = c ("fill", "shared") 'можно выбрать, следует ли расширять данные или уменьшать их. – Helix123