2012-08-31 136 views
2

我已经创建了一个数据帧my.df并希望根据几个标准选择行(或删除行)。在该示例的数据帧我想保留的行1,2,4,图7和8具体而言,我想:R:根据几个标准选择数据帧的行

  1. 保持任何行包含在列的3号,4或5
  2. 保留任何包含3-5列中的所有缺失观察,如果1和2列 不空白,不包含垃圾排

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

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 

用我的实际数据有什么资格成为垃圾可能很复杂。所以,在这里我将junk概括为junk1junk2,我仍然想保留第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 

因为有资格作为垃圾变得相当多样和复杂的字符串在这里我尽量简化代码使用%在一点%至组的垃圾,但我得到一个错误。

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中的错误。

回答

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 
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()和你不希望每个值填充此,后来干脆检查哪些值不包含在bad.values(这可能需要一些工作才能添加到您的解决方案,除非您使用for循环)。