dplyr & изящно работает со значениями SQL NULL - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь использовать dplyr для работы с SQL базами данных, используя R , и я хотел бы изящно обработать SQL Значения NULL - либо просто отфильтровывая их, либо обрабатывая их как нули при появлении, в зависимости от сценария - без внесения каких-либо изменений в саму базовую базу данных.(Другими словами, я не спрашиваю о преобразовании всех значений NULL в ноль из SQL.)

По сути, я пытаюсь использовать dplyr для работы с SQL базами данных, но я продолжаю получать неожиданные результаты.

# Using Lahman's Database, available here:
# https://www.kaggle.com/seanlahman/the-history-of-baseball

library(dplyr)

db.path <- '~/data/SQLite Databases/the-history-of-baseball/database.sqlite'
con <- DBI::dbConnect(RSQLite::SQLite(), db.path)

batting_db <- tbl(con, 'batting')

# the result of this code is at least (seemingly) correct--the columns appear
# to be the correct type and the entries shown are all accurate:
batting_db %>% 
    filter(hr >= 50)

# however, when the additional constraint is added, columns get coerced to 
# characters and rows where hr == '' start showing up
batting_db %>% 
    filter(hr >= 50, year >= 1985)

Во-первых, почему это вообще проблема?Почему пустые строки не будут отфильтрованы, так как '' >= 50 оценивается как ЛОЖЬ?(Примечание: добавление дополнительного ограничения, которое, по-видимому, hr != '' исправило это поведение, хотя я до сих пор не понимаю, почему ...)

Кроме того, теперь я могу преобразовать эти пустые строки в ноль.Я даже не уверен, что это необходимо, так как, очевидно, dplyr рассматривает их как ноль в вычислениях (?!).

# mutate appears to treat these empty strings as '0' in calculations
batting_db %>% 
    filter(hr >= 30, year >= 1985) %>%
    select(player_id:g, h, hr) %>%
    mutate(hr2 = hr + 5, hr3 = g * hr)

По сути, я просто не получаю Поведение dplyr при использовании его для доступа к базам данных, и я был бы признателен за любую информацию.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Я подозреваю, но не знаю, что dplyr превратит любые NULL s в базе данных SQL в NA.Я не могу создать фрейм данных с NULL s для проверки, так как это недопустимая конструкция R.Мне нужно увидеть пример.Если мы предположим, что NULL s изменено на NA, этот пример обернёт NA к нулю и будет работать с копией таблицы, не изменяя базу данных.

library(RSQLite)
library(dplyr)

#create dummy SQL database
set.seed(123)
tax<-tibble(taxpayer_id=1:10,income=runif(10,50,60),income_misc=runif(10,0,5)) %>% 
  mutate(income_misc=ifelse(income_misc<2,NA,income_misc))
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con,"tax_tbl",tax,overwrite=TRUE)


# now extract
tax_db <- tbl(con, 'tax_tbl')
tax_db
#> # Source:   table<tax_tbl> [?? x 3]
#> # Database: sqlite 3.22.0 [:memory:]
#>    taxpayer_id income income_misc
#>          <int>  <dbl>       <dbl>
#>  1           1   52.9        4.78
#>  2           2   57.9        2.27
#>  3           3   54.1        3.39
#>  4           4   58.8        2.86
#>  5           5   59.4       NA   
#>  6           6   50.5        4.50
#>  7           7   55.3       NA   
#>  8           8   58.9       NA   
#>  9           9   55.5       NA   
#> 10          10   54.6        4.77

tax <- tax_db %>% 
  as_tibble() %>% #have to create a data frame, not database, to modify NAs
  mutate_all(funs(replace(., is.na(.), 0)))

dbDisconnect(con)

tax
#> # A tibble: 10 x 3
#>    taxpayer_id income income_misc
#>          <dbl>  <dbl>       <dbl>
#>  1           1   52.9        4.78
#>  2           2   57.9        2.27
#>  3           3   54.1        3.39
#>  4           4   58.8        2.86
#>  5           5   59.4        0   
#>  6           6   50.5        4.50
#>  7           7   55.3        0   
#>  8           8   58.9        0   
#>  9           9   55.5        0   
#> 10          10   54.6        4.77
Created on 2019-02-20 by the reprex package (v0.2.1)
0 голосов
/ 20 февраля 2019

Это решает проблему плохо построенной таблицы SQL , представленной в примере выше, путем преобразования всех столбцов в тип character, замены пустых строк на NA и преобразования обратно в integer, где это необходимо.,Если вы пытаетесь вычислить статистику по статистике, вы, конечно, не хотите, чтобы пропущенные значения рассматривались как ноль, но вы уже это знаете.

library(dplyr)
library(DBI)

db.path <- "database.sqlite"
con <- DBI::dbConnect(RSQLite::SQLite(), db.path)
batting_db <- tbl(con, 'batting')

batting <- batting_db %>% 
  mutate_all(as.character) %>% 
  as_tibble %>% # must be a data frame for na_if to work
  na_if("") %>%  #replace empty strings with NA
  #convert numerics back to numerics
  mutate_at(vars(-one_of(c("player_id","team_id","league_id"))),as.integer)

# add a new table to the database with our clean data
dbWriteTable(con,"batting_mod",batting,overwrite=TRUE)
# back to where we started from but with a clean table
batting_db <- tbl(con, 'batting_mod')
batting_db

# Source:   table<batting_mod> [?? x 22]
# Database: sqlite 3.22.0 [C:\Users\nsteinm\Documents\R\temp\database.sqlite]
   player_id  year stint team_id league_id     g    ab     r     h double triple    hr   rbi    sb
   <chr>     <int> <int> <chr>   <chr>     <int> <int> <int> <int>  <int>  <int> <int> <int> <int>
 1 abercda01  1871     1 TRO     NA            1     4     0     0      0      0     0     0     0
 2 addybo01   1871     1 RC1     NA           25   118    30    32      6      0     0    13     8
 3 allisar01  1871     1 CL1     NA           29   137    28    40      4      5     0    19     3
 4 allisdo01  1871     1 WS3     NA           27   133    28    44     10      2     2    27     1
 5 ansonca01  1871     1 RC1     NA           25   120    29    39     11      3     0    16     6
 6 armstbo01  1871     1 FW1     NA           12    49     9    11      2      1     0     5     0
 7 barkeal01  1871     1 RC1     NA            1     4     0     1      0      0     0     2     0
 8 barnero01  1871     1 BS1     NA           31   157    66    63     10      9     0    34    11
 9 barrebi01  1871     1 FW1     NA            1     5     1     1      1      0     0     1     0
10 barrofr01  1871     1 BS1     NA           18    86    13    13      2      1     0    11     1
# ... with more rows, and 8 more variables: cs <int>, bb <int>, so <int>, ibb <int>, hbp <int>,
#   sh <int>, sf <int>, g_idp <int>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...