【问题标题】:Dropping containing NA rows with dbplyr使用 dbplyr 删除包含 NA 行
【发布时间】:2021-03-24 08:55:14
【问题描述】:

这是我通过 dbplyr 运行一些 SQL 查询的方式

library(tidyverse)
library(dbplyr)
library(DBI)
library(RPostgres)
library(bit64)
library(tidyr)

drv <- dbDriver('Postgres')

con <- dbConnect(drv,dbname='mydb',port=5432,user='postgres')

table1 <- tbl(con,'table1')
table2 <- tbl(con,'table2')
table3 <- tbl(con,'table3')

table1 %>% mutate(year=as.integer64(year)) %>% left_join(table2,by=c('id'='id')) %>%
left_join(table3,by=c('year'='year'))

我想删除一些行,其中包括 NA 然后 collect 我的决赛桌,但找不到任何有用的 dbplyr 查询。

我试图从tidyr 和其他一些基本函数(complete.cases() 等)中传递drop_na()。你能建议我什么来实现我的目标吗?也欢迎将 SQL 查询(如 WHERE FOO IS NOT NULL)传递到 dbplyr 查询。

提前致谢。

【问题讨论】:

  • na.omit(table) 呢?
  • @PaulG 嗨,table 指的是什么?如果您建议我在我的 dbplyr 查询结束时使用管道 na.omit(),我尝试了这个,这是令人失望的地方之一。我想在收集之前省略 NA,因为它会在我的磁盘中创建一个巨大的临时文件。
  • table 应该是一个数据框或小标题。你的结果表是什么类?也许先尝试转换它。
  • @PaulG 好吧,实际上还不是你所说的。这是一个惰性查询,分类为“tbl_lazy”、“tbl_sql”和“tbl”。问题从那里开始,我需要做任何我必须做的事情,然后才能将它变成数据框或小标题等。
  • SQL 查询 in this answer 似乎正在做你需要的事情。

标签: sql r dplyr dbplyr


【解决方案1】:

尝试使用!is.na(col_name) 作为过滤器的一部分:

library(dplyr)
library(dbplyr)

df = data.frame(my_num = c(1,2,3))
df = tbl_lazy(df, con = simulate_mssql())

output = df %>% filter(!is.na(my_num))

调用show_query(output)检查生成的sql给出:

<SQL>
SELECT *
FROM `df`
WHERE (NOT(((`my_num`) IS NULL)))

额外的括号是 dbplyr 如何进行翻译的一部分。

如果您想对多个列执行此操作,请尝试基于this 答案的以下方法:

library(rlang)
library(dplyr)
library(dbplyr)

df = data.frame(c1 = c(1,2,3), c2 = c(9,8,7))
df = tbl_lazy(df, con = simulate_mssql())

colnames = c("c1","c2")
conditions = paste0("!is.na(",colnames,")")

output = df %>%
  filter(!!!parse_exprs(conditions))

调用show_query(output) 显示两列都出现在生成的查询中:

<SQL>
SELECT *
FROM `df`
WHERE ((NOT(((`c1`) IS NULL))) AND (NOT(((`c2`) IS NULL))))

【讨论】:

  • 是的,看起来更通用且易于阅读。感谢您的宝贵工作!
【解决方案2】:

嗯,实际上我仍然没有得到令人满意的解决方案。我真正想做的是在 R 环境中删除包含 NA 行而不键入 SQL 查询,我认为 dbplyr 尚不支持此功能。

然后我写了一个小而简单的代码来实现我的愿望;

main_query<-table1 %>% mutate(year=as.integer64(year)) %>% left_join(table2,by=c('id'='id')) %>%
left_join(table3,by=c('year'='year'))

colnames <- main_query %>% colnames

query1 <- main_query %>% sql_render %>% paste('WHERE')

query2<-''


for(i in colnames){

    if(i == tail(colnames,1)){query2<-paste(query2,i,'IS NOT NULL')}
    
    else{query2<-paste(query2,i,'IS NOT NULL AND')}

}

desiredTable <- dbGetQuery(con,paste(query1,query2))

是的,我知道它看起来并不神奇,但也许有人可以利用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 2021-03-06
    • 2013-08-09
    • 2016-07-10
    • 1970-01-01
    相关资源
    最近更新 更多