0

我有一个包含 28 个变量和 7400 个观察值的“CSV”格式数据集。我在 R 中以“电影”的名称导入数据集,我想清理它。这样,我使用“sqldf”和“SQLite”库。但是当我使用“sqldf”时,我会收到警告,因此我的数据集也不会更新:

在此处输入图像描述

color   director_name   num_critic_for_reviews  duration
Color   James Cameron   723                       178
Color   Gore Verbinski  302                       169
Color   Sam Mendes      602                       148

我使用的代码如下:

library(RSQLite) 
library(sqldf)
db <- dbConnect(SQLite(), "tempdb")  

dbWriteTable(db,"films",films, overwrite=TRUE)

d <- sqldf(c('update films set movie_title=lower(movie_title)', 'select * from films'))
d <- sqldf(c('update films set actor_3_name=lower(actor_3_name)', 'select * from films'))
d <- sqldf(c('update films set actor_2_name=lower(actor_2_name)', 'select * from films'))
d <- sqldf(c('update films set actor_1_name=lower(actor_1_name)', 'select * from films'))
d <- sqldf(c('update films set director_name=lower(director_name)', 'select * from films'))


# Warning message:
# In rsqlite_fetch(res@ptr, n = n) :
#   Don't need to call dbFetch() for statements, only for queries

问题是什么?

4

1 回答 1

3

这里有几个问题。

首先

# Warning message:
# In rsqlite_fetch(res@ptr, n = n) :
#   Don't need to call dbFetch() for statements, only for queries

这是一个警告,而不是错误。事实上,它似乎是一个新问题RSQLite,并且在一个开放问题中被引用:https ://github.com/r-dbi/RSQLite/issues/227 。

(为了简洁起见,我将在此答案的其余部分中将其从输出中删除,尽管每个非select查询都会发生这种情况。)

RSQLite处理数据库,期。它对 R 环境中的变量没有意见或意识,因此没有建议 R 中的变量是数据库表的直接和永久表示。(粗略地说,有类似的方法可以dbplyr做到一点。)

为了在 R 和某种形式的 SQL 查询之间提供这种类型的联系,sqldf您可以像查询实际的 SQL 表一样查询 R 变量。当您执行这样的查询时,它会抓取当前看起来的 data.frame,将其插入到临时数据库表中(无论是RSQLite另一个),运行 SQL 代码,然后返回您需要的内容。

第三:尽管有这种明显的联系,但它非常实用,因为它不会在 R 环境中产生副作用。这意味着,如果您想以 R 可以使用的方式存储结果数据,则需要将新表显式捕获到 R 变量中。

例如:

library(sqldf)
(mt <- mtcars[1:5,1:5])
#                    mpg cyl disp  hp drat
# Mazda RX4         21.0   6  160 110 3.90
# Mazda RX4 Wag     21.0   6  160 110 3.90
# Datsun 710        22.8   4  108  93 3.85
# Hornet 4 Drive    21.4   6  258 110 3.08
# Hornet Sportabout 18.7   8  360 175 3.15

更新后,原始数据保持不变。

sqldf('update mt set cyl=5 where cyl>5')
mt
#                    mpg cyl disp  hp drat
# Mazda RX4         21.0   6  160 110 3.90
# Mazda RX4 Wag     21.0   6  160 110 3.90
# Datsun 710        22.8   4  108  93 3.85
# Hornet 4 Drive    21.4   6  258 110 3.08
# Hornet Sportabout 18.7   8  360 175 3.15

select * from ...您可以通过在调用中包含 a 来单独或在同一行中获取数据sqldf

mt2 <- sqldf(c('update mt set cyl=5 where cyl>5', 'select * from mt'))
mt2
#    mpg cyl disp  hp drat
# 1 21.0   5  160 110 3.90
# 2 21.0   5  160 110 3.90
# 3 22.8   4  108  93 3.85
# 4 21.4   5  258 110 3.08
# 5 18.7   5  360 175 3.15

(在这种情况下,我将它保存到mt2,但您可以轻松地覆盖它。)

sqldf所有这些都在FAQ 8中以各种形式进行了讨论,“8. 为什么我在更新时遇到问题?”

编辑

似乎有一些关于sqldf等的误解。

  1. db您正在为直接 SQL 查询(不是)创建句柄sqldf,但您从不使用它。正如您稍后将看到的,要么 (a) use dbExecute(和相关函数)与db句柄,要么 (b) use sqldf,不需要dbConnect和朋友。

  2. 使用时sqldf,在每次调用sqldf它时都会将变量的当前实例完整复制到数据库中。(这既有用又有时效率低下。对于较小的数据集,可能感觉不到时间损失,但仍然......)所以当你继续引用table films时,它​​会忽略d你创建的,因为它没有在它的调用之外推断你试图做什么的方法......它只是复制、查询和丢弃。

    # assuming this is something like what you do ... but it doesn't matter
    films <- read.csv("films.csv", ...)
    #    `-<---<---<---<---<---<---<---<---<---<---<---<---<---<---<-+-<--.
    db <- dbConnect(SQLite(), "tempdb") # not used in sqldf          ^     \
    dbWriteTable(db, "films", films, overwrite=TRUE) # never used    ^      \
    #                             `--- is referring to --->--->--->--'       \
    d <- sqldf(c('update films set movie_title=lower(movie_title)', #         \
                                 'select * from films')) #                     \
    #                        \                      `--- (internal to sqldf)    ^
    #                         `--- refers to the original 'films' --->--->--->--'
    

    选项 1,使用RSQLite功能,而不是sqldf

    db <- dbConnect(SQLite(), "tempdb")
    dbWriteTable(db,"films",films, overwrite=TRUE)
    dbExecute(db, 'update films set actor_3_name=lower(actor_3_name)')
    #        `--- repeat for all updates
    films <- dbGetQuery(db, 'select * from films')
    

    选项 2,(不是我的首选)使用在上一行创建的变量:

    films <- read.csv("films.csv", ...)
    #   `--<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<-.
    d <- sqldf(c('update films set movie_title=lower(movie_title)', #         \
                                 'select * from films')) #                     \
    #\                        \                      `--- (internal to sqldf)    ^
    # \                        `--- refers to original 'films' --->--->--->--->--'
    #  `--<---<---<---<---<---<---<---<---<---<---<---<---<---<---<---<--.
    d <- sqldf(c('update d set actor_3_name=lower(actor_3_name)', #       \
                                 'select * from d')) #                     \
    #                    \                      `--- (internal to sqldf)    ^
    #                     `--- refers to previously-created 'd' --->--->--->'
    #                         (repeat for other updates)
    

    选项 3,始终引用/覆盖原始films变量:

    films <- read.csv("films.csv", ...)
    #   `--<---<---<---<---<---<---<---<---<---<---<---+--<---<---<---<---<---.
    films <- sqldf(c('update films set movie_title=lower(movie_title)', #      \
                                  'select * from films')) #                     \
    #   \                        \                   `--- (internal to sqldf)    ^
    #    \                        ` --- refers to the first 'films' -->--->--->--'
    #     `-<---<---<---<---<---<---<---<---<---<---<---+--<---<---<---<---<--.
    films <- sqldf(c('update films set actor_3_name=lower(actor_3_name)', #    \
                                  'select * from films')) #                     \
    #                            \                   `--- (internal to sqldf)    ^
    #                             ` --- refers to the second 'films' -->--->--->-'
    #                              (repeat for other updates)
    
  3. sqldf效率低下。每次调用 时sqldf,它都会将整个数据集复制到一个临时表中。每一个。时间。您可以通过将所有查询字符串组合到一个调用中来减少一些开销,如下所示:

    films <- read.csv("films.csv", ...)
    films <- sqldf(c('update films set actor_3_name=lower(actor_3_name)',
                     'update films set actor_2_name=lower(actor_2_name)',
                     'update films set actor_1_name=lower(actor_1_name)',
                     'update films set director_name=lower(director_name)',
                     'select * from films'))
    
  4. SQL 效率低下。您的原始代码可能会针对该问题进行简化(这很好),但如果不是,那么就到这里。由于您似乎根本没有调整您的更新,因此您可以将数据清理合并到一个更新中。(这也可以使用dbExecute。)

    films <- read.csv("films.csv", ...)
    films <- sqldf(c('update films set actor_3_name=lower(actor_3_name),
                                       actor_3_name=lower(actor_3_name),
                                       actor_2_name=lower(actor_2_name),
                                       actor_1_name=lower(actor_1_name),
                                       director_name=lower(director_name)',
                     'select * from films'))
    
  5. 你真的需要 SQL 吗?这可以在 R 中非常容易/快速地完成:

    films <- read.csv("films.csv", ...)
    films <- within(films, {
      actor_3_name <- tolower(actor_3_name)
      actor_2_name <- tolower(actor_2_name)
      actor_1_name <- tolower(actor_1_name)
      director_name <- tolower(director_name)
    })
    
于 2017-12-08T22:05:08.120 回答