3

我创建了一个数据框my.df,并希望根据几个条件选择行(或删除行)。对于这个示例数据框,我想保留第 1、2、4、7 和 8 行。具体来说,我想:

  1. 保留第 3、4 或 5 列中包含数字的任何行
  2. 如果第 1 列和第 2 列不是空白且不包含垃圾,则保留第 3-5 列中包含所有缺失观测值的任何行

我可以做到这一点,但我的解决方案似乎过于复杂,我希望有人可以提出更有效的方法。

my.df <- data.frame(C1 = c("group1", "group1",     "",     "", "junk", "junk", "group2",       ""),
                    C2 = c(     "A",      "B",     "",     "",     "", "junk",      "B",      "C"),
                    C3 = c(     100,       NA,     NA,     10,     NA,     NA,       NA,       NA),
                    C4 = c(     200,       NA,     NA,     20,     NA,     NA,      100,       NA),
                    C5 = c(     100,       NA,     NA,     30,     NA,     NA,       NA,        5))

my.df

# the number of missing observations in columns 3-5 is < 3 or
# when the number of missing observations in columns 3-5 is 3 neither column 1 nor 2 is either blank or 'junk'

df.2 <- my.df[ (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
               (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2) & my.df[,1] != 'junk' & my.df[,2] != 'junk'  & my.df[,1] != '' & my.df[,2] != '') , ]
df.2

根据我的实际数据,有资格成为垃圾的东西可能很复杂。所以,在这里我概括junkjunk1并且junk2我仍然想保留第 1、2、4、7 和 8 行。下面的代码有效。

my.df <- data.frame(C1 = c("group1", "group1",     "",     "", "junk2", "junk1", "group2",       ""),
                    C2 = c(     "A",      "B",     "",     "",      "", "junk1",      "B",      "C"),
                    C3 = c(     100,       NA,     NA,     10,      NA,      NA,       NA,       NA),
                    C4 = c(     200,       NA,     NA,     20,      NA,      NA,      100,       NA),
                    C5 = c(     100,       NA,     NA,     30,      NA,      NA,       NA,        5))

my.df

df.3 <- my.df[ (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
               (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2)  & 
                my.df[,1] != 'junk1' & my.df[,2] != 'junk1'     & 
                my.df[,1] != 'junk2' & my.df[,2] != 'junk2'     &
                my.df[,1] != '' & my.df[,2] != '') 

        , ]
df.3

因为有资格作为垃圾的字符串在这里变得非常多样化和复杂,所以我尝试使用 %in% 对垃圾进行分组来稍微简化代码,但我得到了一个错误。

all.junk <- c("", "junk1", "junk2")

my.df.1 <- my.df[,1]
my.df.2 <- my.df[,2]

my.df.1 <- as.character(my.df.1)
my.df.2 <- as.character(my.df.2)

df.4 <- my.df[ (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
               (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2) & 
                my.df.1[!(my.df.1%in%all.junk)] & my.df.2[!(my.df.2%in%all.junk)]) , ]
df.4

我可以继续使用我拥有的功能代码,df.3为每个符合垃圾标准的字符串添加一个新行,但我怀疑有一个更有效的解决方案。

我在 Stackoverflow 上发现了类似的问题,但我发现没有一个问题似乎与此示例中的选择标准一样多或复杂。

感谢您的任何建议,尤其是关于df.4.

4

2 回答 2

3

这非常紧凑:保留不是所有垃圾/nas的每一行:

all.junk=c("junk","")
subset(my.df,!(C1%in%all.junk &
               C2%in%all.junk & 
               is.na(C3) & is.na(C4) & is.na(C5)))

输出

      C1 C2  C3  C4  C5
1 group1  A 100 200 100
2 group1  B  NA  NA  NA
4            10  20  30
7 group2  B  NA 100  NA
8         C  NA  NA   5
于 2012-08-31T22:11:31.367 回答
1

如果您关心的是可读性,您可以重构此代码:

df.3 <- my.df[ (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
           (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2)  & 
            my.df[,1] != 'junk1' & my.df[,2] != 'junk1'     & 
            my.df[,1] != 'junk2' & my.df[,2] != 'junk2'     &
            my.df[,1] != '' & my.df[,2] != '') 
    , ]

进入:

# Rows I want
good.rows = (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
           (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2)  & 
            my.df[,1] != 'junk1' & my.df[,2] != 'junk1'     & 
            my.df[,1] != 'junk2' & my.df[,2] != 'junk2'     &
            my.df[,1] != '' & my.df[,2] != '') 

df.3 <- my.df[good.rows,]

并进一步:

sums.are.fine = (rowSums(is.na(my.df[,3:5]))  < (ncol(my.df)-2)) | 
           (rowSums(is.na(my.df[,3:5])) == (ncol(my.df)-2)

no.junk = my.df[,1] != 'junk1' & my.df[,2] != 'junk1'     & 
            my.df[,1] != 'junk2' & my.df[,2] != 'junk2'     &
            my.df[,1] != '' & my.df[,2] != '') 

good.rows = sums.are.fine & no.junk

df.3 <- my.df[good.rows,]

您还可以编写单独的函数,例如check.if.sums.are.fine(table.to.check)返回布尔值的check.everything(table.to.check)函数,以及调用所有这些函数并给出最终结果的函数。

如果打字部分困扰您,我注意到的一件事是,对于“不能为junk1junk2或为空”之类的事情,您可以制作一个bad.values = character()并用您不想要的每个值填充它,然后只需检查哪些值不包含in bad.values(除非您使用 for 循环,否则这可能需要一些工作才能添加到您的解决方案中)。

于 2012-09-01T00:13:58.113 回答