2012-10-10 91 views
1

我试图从SQLite数据库中写入一个表到R数据框中,并遇到了一个让我难倒的问题。下面是SQLite的表中的三个第一项我想进口:RSQLite类型转换问题

1|10|0|0|0|0|10|10|0|0|0|6|8|6|20000|30000|2012-02-29 21:27:07.239091|2012-02-29 21:28:24.815385|6|80.67.28.161|||||||||||||||||||||||||||||||33|13.4936||t|t|f||||||||||||||||||4|0|0|7|7|2 
2|10|0|0|0|0|0|0|0|2|2|4|5|4|20000|30000|2012-02-29 22:00:30.618726|2012-02-29 22:04:09.629942|5|80.67.28.161|3|7||0|1|3|0|||4|3|4|5|5|5|5|4|5|4|4|0|0|0|0|0|9|9|9|9|9|||1|f|t|f|||||||||||||k|text|l|||-13|0|3|10||2 
3|13|2|4|4|4|4|1|1|2|5|6|3|2|40000|10000|2012-03-01 09:07:52.310033|2012-03-01 09:21:13.097303|6|80.67.28.161|2|2||30|1|1|0|||4|2|1|6|8|3|5|6|6|7|6|||||||||||26|13.6336|4|f|t|f|t|f|f|f|f|||||||||some text||||10|1|1|3|2|3 

我感兴趣的是通过60列53,其中,为您节省在上述计算的麻烦,看起来像这样的:

|t|t|f|||||| 
|f|t|f|||||| 
|f|t|f|t|f|f|f|f| 

正如你可以看到前两个项目只有那些列前三非NULL而第三项中的所有八个列分配有值。

下面是这些列

sqlite> PRAGMA table_info(observations); 
0|id|INTEGER|1||1 
** snip ** 
53|understanding1|boolean|0||0 
54|understanding2|boolean|0||0 
55|understanding3|boolean|0||0 
56|understanding4|boolean|0||0 
57|understanding5|boolean|0||0 
58|understanding6|boolean|0||0 
59|understanding7|boolean|0||0 
60|understanding8|boolean|0||0 
** snip ** 

SQLite的表信息现在,当我尝试读入读该这里就是那些相同的列最终成为:

> library('RSQLite') 
> con <- dbConnect("SQLite", dbname = 'db.sqlite3)) 
> obs <- dbReadTable(con,'observations') 
> obs[1:3,names(obs) %in% paste0('understanding',1:8)] 
    understanding1 understanding2 understanding3 understanding4 understanding5 understanding6 understanding7 
1    t    t    f    NA    NA    NA    NA 
2    f    t    f    NA    NA    NA    NA 
3    f    t    f    0    0    0    0 
    understanding8 
1    NA 
2    NA 
3    0 

正如你所看到的,而前三列包含的值为't''f',其他列为NA,其中SQLite表中的对应值为NULL,而0他们不是 - 无论SQLite表中的对应值是t还是f。不用说,这不是我预期的行为。问题是,我认为,这些列不正确类型强制转换:

> sapply(obs[1:3,names(obs) %in% paste0('understanding',1:8)], class) 
understanding1 understanding2 understanding3 understanding4 understanding5 understanding6 understanding7 
    "character" "character" "character"  "numeric"  "numeric"  "numeric"  "numeric" 
understanding8 
    "numeric" 

难道RSQLite后的第一个条目看到tf在相应的列中的值设置前三列的character类型但是与numeric一起使用,因为在这些列中第一个条目恰好是NULL?

如果确实发生了这种情况,有什么办法解决这个问题,并将所有这些列转换为character(或者更好,logical)?

+0

我的SQLite的知识是有限的,但我很困惑,你怎么有字符't'和''F'存储在一个布尔列在SQLite中。我的理解是,SQLite没有一个本地布尔类型,它只是将它们存储为整数0和1.此外,列类型没有强制执行,所以如果你插入文本到一个布尔型的字段,SQLite将转换的存储模式柱。 – joran

+0

我并不擅长SQLite(我不知道列的类型是不是强制执行的)。整个DB来自Ruby on Rails网络应用程序,我几乎不得不承认它。但是,如果问题在于列类型没有被强制执行 - 而且RSQLite显然不仅仅使用列类型的R-等价物,那么RSQLite如何推断哪个类要分配给每列,并且是否有任何影响推理? – RoyalTS

+0

我不确定;我在RSQLite的文档中找不到描述(但真正的答案可能会埋在DBI包的文档中)。 [R-SIG-DB](https://stat.ethz.ch/mailman/listinfo/r-sig-db)中的一些肯定会知道RSQLite如何进行类型转换的细节。但在你问那里之前,我还会仔细检查你的分贝数据库,并确保你有一个只有NA和0的列中的t和f值,因为这听起来很奇怪。 – joran

回答

0

以下是哈克,但它的工作原理:

# first make a copy of the DB and work with it instead of changing 
# data in the original 
original_file <- "db.sqlite3" 
copy_file <- "db_copy.sqlite3" 
file.copy(original_file, copy_file) # duplicate the file 
con <- dbConnect("SQLite", dbname = copy_file) # establish a connection to the copied DB 

# put together a query to replace all NULLs by 'NA' and run it 
columns <- c(paste0('understanding',1:15)) 
columns_query <- paste(paste0(columns,' = IfNull(',columns,",'NA')"),collapse=",") 
query <- paste0("UPDATE observations SET ",columns_query) 
dbSendQuery(con, query) 

# Now that all columns have string values RSQLite will infer the 
# column type to be `character` 
df <- dbReadTable(con,'observations') # read the table 
file.remove(copy_file) # delete the copy 

# replace all 'NA' strings with proper NAs 
df[names(df) %in% paste0('understanding',1:15)][df[names(df) %in% paste0('understanding',1:15)] == 'NA'] <- NA 
# convert 't' to boolean TRUE and 'f' to boolean FALSE 
df[ ,names(df) %in% paste0('understanding',1:15)] <- sapply(df[ ,names(df) %in% paste0('understanding',1:15)], function(x) {x=="t"})