我正在清理还没有列名的数据集(因此我正在使用索引),并且我试图通过将第一个过滤器的结果输送到第二个过滤器的结果中来过滤df的两列不明白为什么下面的方法不起作用:
stripcols <- c("","Total+")
df <- df %>%
filter(!df[,1] %in% stripcols) %>%
filter(!df[,2] %in% stripcols)
运行此结果将导致:
Error in filter_impl(.data, quo) : Result must have length 46, not 58
通过两次运行过滤器可以轻松解决此问题,但是我不明白为什么它不起作用。
我也很好奇,是否有一种方法可以对两个列而不是两个列应用一个过滤器命令。
答案 0 :(得分:1)
错误的根源是,您总是与nrow(df)
行进行比较,而不管第二行filter
有多少行。例如:
dat <- data.frame(a=1:10)
dat %>% filter(a > 5)
# a
# 1 6
# 2 7
# 3 8
# 4 9
# 5 10
编写方式,执行方式
dat %>% filter(dat[,1] > 5)
# a
# 1 6
# 2 7
# 3 8
# 4 9
# 5 10
对于第一个调用,进入 filter
的行数为10,并且正在内部 filter
进行比较的行数也是10。但是,如果您要这样做:
dat %>% filter(dat[,1] > 5) %>% filter(dat[,1] > 7)
# Error in filter_impl(.data, quo) : Result must have length 5, not 10
这失败了,因为进入第二个filter
的行数只有5而不是10,尽管我们通过使用filter
给dat[,1]
命令进行了10次比较。
(注:关于名称的许多注释都非常恰当,但让我们继续使用列索引这一主题。)
第一个技巧是给每个filter
仅提供与输入数据一样多的比较。另一种说法是对那个时间点的数据状态进行比较。 magrittr
(并因此dplyr
)使用.
占位符执行此操作。总是可以推断出该点(默认为RHS函数的第一个参数,即%>%
之后的函数),但是有些人认为显式更好。例如,这是合法的:
mtcars %>%
group_by(cyl) %>%
tally()
# # A tibble: 3 x 2
# cyl n
# <dbl> <int>
# 1 4 11
# 2 6 7
# 3 8 14
但是这是一个明显的等效管道:
mtcars %>%
group_by(., cyl) %>%
tally(.)
如果函数的第一个参数不是框架本身,则%>%
推断的方式将失败:
mtcars %>%
xtabs(~ cyl + vs)
# Error in as.data.frame.default(data, optional = TRUE) :
# cannot coerce class '"formula"' to a data.frame
(因为它实际上是在调用xtabs(., ~cyl + vs)
,并且没有命名参数,所以xtabs
假定第一个参数是formula
。)
因此,在以下情况下,我们必须必须明确:
mtcars %>%
xtabs(~ cyl + vs, data = .)
# vs
# cyl 0 1
# 4 1 10
# 6 3 4
# 8 14 0
(伪造的示例,已授予)。一个人也可以做mtcars %>% xtabs(formula=~cyl+vs)
,但我的观点是正确的。
因此,为了适应您的代码,我希望它能起作用:
df %>%
filter(!.[,1] %in% stripcols) %>%
filter(!.[,2] %in% stripcols)
我认为我更喜欢[[
方法(部分原因是我知道tbl_df
和data.frame
处理[,1]
的方式略有不同……尽管它可以它,我仍然更喜欢[[
)的明确性:
df %>%
filter(!.[[1]] %in% stripcols) %>%
filter(!.[[2]] %in% stripcols)
应该起作用。当然,结合也可以:
df %>%
filter(!.[[1]] %in% stripcols, !.[[2]] %in% stripcols)