r-使用dplyr过滤邮政编码前缀错误的更快方法



我有一个包含邮政编码和状态列(以及其他(的数据集。它很大,但并不可怕(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")
  )

不要麻烦把&在|之前带有((的表达式,因为|的优先级较低。通过这种方式,你的表达变得更加易读。

最新更新