【问题标题】:R remove rows from panel while keeping the panel balancedR 从面板中删除行,同时保持面板平衡
【发布时间】:2014-09-04 17:06:53
【问题描述】:

有没有一种优雅的方法来平衡不平衡的面板数据集?我想从一个不平衡的面板开始(即一些人丢失了一些数据)并以一个平衡的面板结束(即所有的人都没有丢失任何数据)。下面是一些示例代码。正确的最终结果是保留对“Frank”和“Edward”的所有观察,并删除对“Tony”的所有观察,因为他有一些缺失的数据。谢谢。

unbal <- data.frame(PERSON=c(rep('Frank',5),rep('Tony',5),rep('Edward',5)), YEAR=c(2001,2002,2003,2004,2005,2001,2002,2003,2004,2005,2001,2002,2003,2004,2005), Y=c(21,22,23,24,25,5,6,NA,7,8,31,32,33,34,35), X=c(1:15))
unbal

【问题讨论】:

  • 样本数据不是不平衡面板,而是缺失值的平衡面板。

标签: r panel balance


【解决方案1】:

所以我不确定它是否满足“优雅”的要求,但这里有一个通用功能,您可以使用它来获取平衡数据。

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=参数也是一个字符向量,指定每个ID的不同观察时间。最后,您可以选择指定 VARS= 参数来指定哪些字段必须为 NA(默认为除 ID 或 TIME 值之外的所有字段)。最后,还有一个名为 required 的参数,它说明每个 ID 是否必须对每个 TIME 进行观察(默认),或者如果将其设置为“共享”,它只会返回所有 ID 都具有非缺失值的 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

只要求所有 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 年价值的人。这意味着

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 年的数据,因为所有人都有这些年份的数据。

【讨论】:

  • 非常好。我承认直到我读到它才理解“平衡”的含义。这是一个更好的通用解决方案。
【解决方案2】:

平衡面板的一种方法是删除数据不完整的个体,另一种方法是填写一个值,例如 NA0 用于缺失的观察值。对于第一种方法,您可以使用complete.cases 来查找其中没有NA 的行。然后你可以找到所有PERSON 至少有一个缺失的情况。

missing.at.least.one <- unique(unbal$PERSON[!complete.cases(unbal)])
unbal[!(unbal$PERSON %in% missing.at.least.one),]
#    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

【讨论】:

  • 如果有人对另一种方式感兴趣(通过填写 NA 来平衡不平衡面板),可以使用包plm 中的函数make.pbalanced(需要@987654321 的最新开发版本@)
  • plm 的官方 CRAN 版本 (1.6-4) 现在包含 make.pbalanced(通过参数 balance.type = c("fill", "shared") 可以选择是扩展数据还是减少数据。
【解决方案3】:

我使用的一个解决方案是将数据框临时重塑为宽格式,其中年份为列,单位为行,然后逐行检查完整的案例。如果您有一个感兴趣的变量——如果缺失——意味着整个观察结果都缺失了,那么这是最容易做到的。

我使用以下库:

library(data.table)
library(reshape2)

首先,获取主数据框 (unbal) 的子集,即 ID 变量 ("NAME")、时间变量 ("YEAR") 和感兴趣的变量 ("X" 或 "Y ")。

df<- unbal[c("NAME", "YEAR", "X" )]

其次,重塑新数据框以使其成为宽格式。这将创建一个数据框,其中每个“NAME”是一行,而每年的“X”是一列。

df <- dcast(df, NAME ~ YEAR, value.var = "X")

第三,为每一行运行 complete.cases。任何缺少数据的NAME都将被完全删除。

df <- df[complete.cases(df),]

第四,将数据框重新调整为长格式(默认情况下,这会为您的变量提供通用名称,因此您可能希望将名称改回原来的名称)。

df <- melt(df, id.vars = "ID")
setnames(df, "variable", "YEAR")

注意:使用该方法时,YEAR 默认成为因子变量。如果您的 YEAR 变量是数字,您需要相应地更改该变量。例如:

test4$year <- as.character(test4$year)
test4$year <- as.numeric(test4$year)

第五和第六,只取您创建的数据框中的“NAME”和“YEAR”变量,然后将它与您的原始数据框合并(并确保在原始数据框中删除不属于在您创建的 d 数据框中找到)

df <- df[c("NAME", "YEAR")]
balanced <- merge.data.frame(df, unbal, by = c("NAME", "YEAR"), all.x = TRUE)

【讨论】:

    【解决方案4】:

    这是我使用的解决方案——它利用了data.table 包的便利功能(包括良好的合并能力),并假设您的数据已经是data.table 对象。它相对简单,希望很容易理解。它返回一个平衡面板,其中包含“个人”和“时间段”的每个唯一组合的条目 - 即每个时间段内每个人都有观察的面板。

    library(data.table)
    Balance_Panel = function(Data, Indiv_ColName, Time_ColName){
        Individuals = unique(Data[, get(Indiv_ColName)])
        Times = unique(Data[, get(Time_ColName)])
    
        Full_Panel = data.table(expand.grid(Individuals, Times))
        setnames(Full_Panel, c(Indiv_ColName, Time_ColName))
        setkeyv(Full_Panel, c(Indiv_ColName, Time_ColName))
        setkeyv(Data, c(Indiv_ColName, Time_ColName))
        return(Data[Full_Panel])
    }
    

    示例用法:

    Balanced_Data = Balance_Panel(Data, "SubjectID", "ObservationTime")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-18
      • 2014-10-30
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      相关资源
      最近更新 更多