2012-10-10 88 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"})