删除数据帧行的简单方法,对没有行符合删除条件的实例具有鲁棒性

时间:2013-02-15 21:37:55

标签: r

R中数据操作的一个常见任务是通过删除符合特定条件的行来对数据帧进行子类化。然而,在R中执行此操作的简单方法似乎在逻辑上不一致,甚至对无经验的人(如我自己)也很危险。

假设我们有一个数据框,我们想要排除属于“G1”处理的行:

Treatment=c("G1","G1","G1","G1","G1","G1","G2","G2","G2","G2","G2",
"G2","G3","G3","G3","G3","G3","G3")
Vals=c(runif(6),runif(6)+0.9,runif(6)-0.3)
data=data.frame(Treatment)
data=cbind(data, Vals)  

正如所料,下面的代码删除了与第一行标准匹配的数据帧行

to_del=which(data$Treatment=="G1")
new_data=data[-to_del,]
new_data

然而,与预期相反,使用此方法如果'which'命令找不到任何匹配行,则此代码将删除所有行而不是将它们全部留下

to_del=which(data$Treatment=="G4")
new_data=data[-to_del,]
new_data

上面的代码导致数据帧没有剩下的行,这没有任何意义(即,由于R没有找到符合我的删除标准的行,它删除了所有行)。我的解决方案完成了这项工作,但我想如果没有所有这些条件语句,有一种更简单的方法可以做到这一点

###WORKAROUND
to_del=which(data$Treatment=="G4") #no G4 treatment in this particular data frame
if (length(to_del)>0){
  new_data=data[-to_del,]  
}else{
  new_data=data
}
new_data

有没有人有一个简单的方法来做到这一点,即使没有符合指定条件的行?

4 个答案:

答案 0 :(得分:6)

您偶然发现了使用which的常见问题。请改用!=

new_data <- data[data$Treatment!="G4",]

如果所有元素都是which,问题是integer(0)会返回FALSE。即使which返回0,这仍然是一个问题,因为按零的子集也会返回integer(0)

R> # subsetting by zero (positive or negative)
R> (1:3)[0]  # same as (1:3)[-0]
integer(0)

如果按NA

进行分组,您也会遇到问题
R> # subsetting by NA
R> (1:3)[NA]
[1] NA NA NA

答案 1 :(得分:3)

为什么不使用subset

subset(data,  ! rownames(data) %in% to_del )

(无论如何,你隐含地匹配data[-to_del, ]示例中的rownames。) 当然,一旦有效,你可以回到使用“[”

data[  ! rownames(data) %in% to_del , ]

答案 2 :(得分:3)

我喜欢使用data.table进行子集化,因为它更直观,更短,并且可以更快地运行大型数据集。

library(data.table)
data.dt<-as.data.table(data)
setkey(data.dt, Treatment)

data.dt[!"G1",]
##     Treatment        Vals
##  1:        G2  0.90264622
##  2:        G2  1.47842130
##  3:        G2  1.52494735
##  4:        G2  1.46373958
##  5:        G2  1.12850658
##  6:        G2  1.46705561
##  7:        G3  0.58451869
##  8:        G3 -0.20231228
##  9:        G3  0.52519475
## 10:        G3  0.62956475
## 11:        G3 -0.06655426
## 12:        G3  0.56814703

data.dt[!"G4",]
##    Treatment        Vals
## 1         G1  0.93411692
## 2         G1  0.60153972
## 3         G1  0.28147464
## 4         G1  0.97264924
## 5         G1  0.50804831
## 6         G1  0.48273876
## 7         G2  0.90264622
## 8         G2  1.47842130
## 9         G2  1.52494735
## 10        G2  1.46373958
## 11        G2  1.12850658
## 12        G2  1.46705561
## 13        G3  0.58451869
## 14        G3 -0.20231228
## 15        G3  0.52519475
## 16        G3  0.62956475
## 17        G3 -0.06655426
## 18        G3  0.56814703

请注意,如果您对尚未设置为键的列进行子集化,则需要在子集中使用列名称(例如data.dt[Vals<0,]

我认为data.table的创建者可能正在研究直接从原始表中删除行的方法,而不是必须将所有未删除的行复制到新表中,然后删除原始表。当你遇到内存限制时,这将是一个很好的帮助。

答案 3 :(得分:2)

问题是您没有选择要删除的行,而是选择要 KEEP 的行。正如您已经发现的那样,您可以经常交换这些概念,但有时会出现问题。

具体来说,当你使用which时,你会问R“这个向量的哪些元素是真的”。但是,当它找不到时,它通过返回integer(0)来指示这一点。

整数(0)不是实际数字,因此取整数(0)的负数仍然给出整数(0)。

但是,如果您只想使用它来过滤,则无需使用哪个。

相反,请将您传递给which的语句作为过滤器直接传递给data[..]。回想一下,您可以使用逻辑向量作为索引以及整数向量。