36

我有一个问题要解决如何在 R 中删除具有零值的行。另一方面,我可以na.omit()用来删除所有 NA 值或用于complete.cases()删除包含 NA 值的行。

有谁知道如何删除 R 中具有零值的行?

例如 :

|    DateTime      | Mac1  | Mac2  | Mac3  | Mac4  |
----------------------------------------------------
| 2011-04-02 06:00 | 20    | 0     | 20    | 20    |  
| 2011-04-02 06:05 | 21    | 21    | 21    | 21    |  
| 2011-04-02 06:10 | 22    | 22    | 22    | 22    |  
| 2011-04-02 06:15 | 23    | 23    | 0     | 23    |  
| 2011-04-02 06:20 | 24    | 24    | 24    | 24    | 
| 2011-04-02 06:25 | 0     | 25    | 25    | 0     | 

|    DateTime      | Mac1  | Mac2  | Mac3  | Mac4  |
----------------------------------------------------
| 2011-04-02 06:05 | 21    | 21    | 21    | 21    |  
| 2011-04-02 06:10 | 22    | 22    | 22    | 22    |  
| 2011-04-02 06:20 | 24    | 24    | 24    | 24    |  
4

12 回答 12

47

有几种不同的方法可以做到这一点。我更喜欢使用apply,因为它很容易扩展:

##Generate some data
dd = data.frame(a = 1:4, b= 1:0, c=0:3)

##Go through each row and determine if a value is zero
row_sub = apply(dd, 1, function(row) all(row !=0 ))
##Subset as usual
dd[row_sub,]
于 2012-04-02T14:01:15.440 回答
9

我会做以下事情。

将零设置为 NA。

 data[data==0] <- NA
 data

删除与 NA 关联的行。

 data2<-data[complete.cases(data),]
于 2018-05-14T20:50:11.263 回答
9

您可以使用 dplyr 包中的过滤器。

让我们称您的数据框为 df

library(dplyr) df1 <- filter(df, Mac1 > 0, Mac2 > 0, Mac3 > 0, Mac4 > 0)

df1 将只有条目大于零的行。希望这可以帮助。

于 2018-10-10T10:47:43.330 回答
8

我可能会接受 Joran 的建议,即用 NA 替换 0,然后使用您提到的内置函数。如果您不能/不想这样做,一种方法是使用any()查找包含 0 的行并将其子集化:

set.seed(42)
#Fake data
x <- data.frame(a = sample(0:2, 5, TRUE), b = sample(0:2, 5, TRUE))
> x
  a b
1 2 1
2 2 2
3 0 0
4 2 1
5 1 2
#Subset out any rows with a 0 in them
#Note the negation with ! around the apply function
x[!(apply(x, 1, function(y) any(y == 0))),]
  a b
1 2 1
2 2 2
4 2 1
5 1 2

要实现 Joran 的方法,你应该开始这样的事情:

x[x==0] <- NA
于 2012-04-02T14:05:51.087 回答
7

好吧,您可以将0'换成NA然后使用其中一种解决方案,但为了区别起见,您可能会注意到,如果一个数字大于0rowSums则它只log会有一个有限对数,因此如果连续没有零。

dfr[is.finite(rowSums(log(dfr[-1]))),]
于 2012-04-02T14:01:37.050 回答
5

我更喜欢对 csgillespie 方法的简单改编,而不需要函数定义:

d[apply(d!=0, 1, all),]

d你的数据框在哪里。

于 2017-12-20T20:42:47.167 回答
2

使用 tidyverse/dplyr,您还可以删除变量子集中具有任何零值的行:

# variables starting with Mac must be non-zero
filter_at(df, vars(starts_with("Mac")), all_vars((.) != 0))

# variables x, y, and z must be non-zero
filter_at(df, vars(x, y, z), all_vars((.) != 0))

# all numeric variables must be non-zero
filter_if(df, is.numeric, all_vars((.) != 0))
于 2019-12-13T23:44:45.277 回答
1

由于 dplyr 1.0.0 弃用了 @Feng Mai 很好地展示的范围变体,这里是新语法的更新。这可能很有用,因为在这种情况下,across()它不起作用,我花了一些时间来找出解决方案如下。

目标是提取列中至少包含一个 0 的所有行。

df %>% 
  rowwise() %>% 
  filter(any(c_across(everything(.)) == 0))

与数据

df <- data.frame(a = 1:4, b= 1:0, c=0:3)
df <- rbind(df, c(0,0,0))
df <- rbind(df, c(9,9,9))

# A tibble: 4 x 3
# Rowwise: 
      a     b     c
  <dbl> <dbl> <dbl>
1     1     1     0
2     2     0     1
3     4     0     3
4     0     0     0

所以它正确地不会返回包含所有 9 的最后一行。

于 2021-01-08T09:35:53.853 回答
0

在基础 R 中,我们可以使用 选择我们想要测试的列grep,将数据与 0 进行比较,使用rowSums选择所有非零值的行。

cols <- grep("^Mac", names(df))
df[rowSums(df[cols] != 0) == length(cols), ]

#          DateTime Mac1 Mac2 Mac3 Mac4
#1 2011-04-02 06:05   21   21   21   21
#2 2011-04-02 06:10   22   22   22   22
#3 2011-04-02 06:20   24   24   24   24

使用反转逻辑执行此操作但提供相同的输出

df[rowSums(df[cols] == 0) == 0, ]

dplyr中,我们可以filter_at用来测试特定列,并all_vars用来选择所有值不等于 0 的行。

library(dplyr)
df %>%  filter_at(vars(starts_with("Mac")), all_vars(. != 0))

数据

df <- structure(list(DateTime = structure(1:6, .Label = c("2011-04-02 06:00", 
"2011-04-02 06:05", "2011-04-02 06:10", "2011-04-02 06:15", "2011-04-02 06:20", 
"2011-04-02 06:25"), class = "factor"), Mac1 = c(20L, 21L, 22L, 
23L, 24L, 0L), Mac2 = c(0L, 21L, 22L, 23L, 24L, 25L), Mac3 = c(20L, 
21L, 22L, 0L, 24L, 25L), Mac4 = c(20L, 21L, 22L, 23L, 24L, 0L
)), class = "data.frame", row.names = c(NA, -6L))
于 2019-09-13T03:53:43.297 回答
0

这是一个更新的方法:

library(dplyr)

df %>%
  filter(!if_any(starts_with("Mac"), ~ . == 0))

          DateTime Mac1 Mac2 Mac3 Mac4
1 2011-04-02 06:05   21   21   21   21
2 2011-04-02 06:10   22   22   22   22
3 2011-04-02 06:20   24   24   24   24
于 2021-09-01T10:41:48.683 回答
0

在遇到类似问题后,我想出了这个:

我想在第 1 列和第 9 列中保留零,因为它们在那里有意义,但将零从其余列中删除。此代码将在数据框中的第 2 列到第 8 列中产生大于零的值,而使第 1 列和第 9 列保持不变。

dataset %>% filter(data.frame(dataset[,2:8]>0))
于 2021-12-11T22:52:14.857 回答
0

可能的最短答案将受益于数字到逻辑的隐式强制,其中零转换为 FALSE,其他值转换为 TRUE,并使用if_any/if_all

library(dplyr)

df %>% filter(if_all(starts_with('Mac')))
于 2021-12-16T13:28:28.287 回答