我有一个包含邮政编码和状态列(以及其他(的数据集。它很大,但并不可怕(4M行,70列(,但过滤错误的观察结果需要很长时间。具体来说,我试图删除邮政编码与州不加在一起的观察结果(例如,新泽西州的邮政编码以0开头,但数据中的许多邮政编码以7开头(。这是我目前的方法,但我相信一定有更快的方法。任何建议都将不胜感激!
df_clean <- df_tmp %>%
filter(!(startsWith(zip, c("7", "8")) & state == "NJ")) %>%
filter(!(startsWith(zip, c("0", "1")) & state == "FL")) %>%
filter(!(startsWith(zip, "4") & state == "ME")) %>%
filter(!(startsWith(zip, c("1", "2")) & state == "MA")) %>%
filter(!(startsWith(zip, "6") & state == "CT"))
我希望它是不言自明的,但让我知道一个样本数据集是否会有帮助。谢谢
这里有一种更具编程性的方法,包括按状态创建一个具有正确起始数字的查找表,将其与数据连接起来,并删除所有起始数字与该状态的预期数字不匹配的行。
digits_by_state <- data.frame(state = c("NJ", "FL", "ME", "MA", "CT"),
correct_digit = c(0,3,0,0,0))
df_clean <- df_tmp %>%
mutate(starting_digit = as.integer(substr(zip, 1, 1))) %>%
left_join(digits_by_state) %>%
filter(starting_digit == correct_digit)
问题是,如果数据帧很大,每个过滤器都会删除其中的一部分,然后将仍然很大的数据集传递给下一个过滤器,因此速度会变慢。
如果您可以将所有条件组合到一个筛选器表达式中,它会运行得更快。像这样:
df_clean <- df_tmp %>%
filter(
!(startsWith(zip, c("7", "8")) & state == "NJ") |
!(startsWith(zip, c("0", "1")) & state == "FL") |
!(startsWith(zip, "4") & state == "ME") |
!(startsWith(zip, c("1", "2")) & state == "MA") |
!(startsWith(zip, "6") & state == "CT")
)
不要麻烦把&在|之前带有((的表达式,因为|的优先级较低。通过这种方式,你的表达变得更加易读。