我有一个" CSV"具有28个变量和7400个观测值的格式数据集。我导入R中的数据集,名称为" films"而我想要清理它。通过这种方式,我使用" sqldf"和#34; 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
有什么问题?
答案 0 :(得分:2)
这里有几个问题。
<强>第一强>:
# 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
允许您查询R变量,就像它们是实际的SQL表一样。当您执行此类查询时,它会抓取当前查找的data.frame,将其插入临时数据库表(无论是RSQLite
还是其他),运行SQL代码,然后返回所需内容。
第三:尽管存在这种明显的联系,但它的功能非常强大,因为它在R环境中不会产生side-effects。这意味着如果您想以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 ...
的通话中添加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
等的误解。
您正在为直接SQL查询创建db
句柄(不是sqldf
),但您从不使用它。正如您稍后将看到的,(a)使用dbExecute
(和相关函数)与db
句柄,或(b)使用sqldf
,不需要dbConnect
和朋友们。
使用sqldf
时,在对sqldf
的每次调用中,它会执行当前实例的完整副本变量到数据库中。 (这有用,有时效率低。使用较小的数据集时,可能感觉不到时间损失,但仍然......)所以当你继续引用表 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)
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'))
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'))
你真的需要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)
})