LoginSignup
0
1

More than 1 year has passed since last update.

RSQLiteで扱うテーブルの最大カラム数を変更する

Posted at

はじめに

Rで行数、列数が想定外に多いcsvを取り扱う必要があり、その際に試行錯誤したときの忘備録。

やったこと

CSVを単にtidyverse系のパッケージで取り込むにもメモリを喰いすぎるし、動作も重くなるので、DBに突っ込んで使いやすく加工すればいいのではと考えた。

とはいえ、DBサーバたてたりとかはさずがに面倒なので、SQLiteを使えるRSQLiteのパッケージを使うことに。

しかし、通常通りにインストールすると列数が2000を超えたデータはSQLiteの制限に引っかかって取り込めず。

SQLiteはRSQLiteにバンドルされてるってんで、インストール後に変更は難しそうなので、RSQLiteのソースをDLして、SQLiteのソースに手を加えてから、ビルドしてインストールすることにした。

環境

Linux(Ubuntu)
R 4.1.2
RSQLite 2.2.18

通常通りにRSQLiteをインストールして読み込ませた場合

  • 32766列の適当なcsvファイルを作成する
for i in `seq 1 32766`; do if [ ${i} -ne 32766 ]; then echo -n A${i}, >> temp.csv; else echo A${i} >> temp.csv; fi; done
for i in `seq 1 32766`; do if [ ${i} -ne 32766 ]; then echo -n ${i}, >> temp.csv; else echo ${i} >> temp.csv; fi; done
  • Rを起動し、上で作成したCSVを読み込ませる
library(DBI)
library(tidyverse)

con <- dbConnect(RSQLite::SQLite(), "temp.sqlite3")
callback <- function(df, pos) {
   dbWriteTable(con, "temp_table", df, append = TRUE)
}
read_csv_chunked("temp.csv", DataFrameCallback$new(callback))
  • 下のエラーメッセージが出て取り込めず
 エラー: too many columns on temp_table

大規模データの取り込みに参考にさせていただいたサイトはこちら。

テーブルの最大カラム数を変更したRSQLiteをインストール

RSQLiteのソースデータをダウンロード

Rを起動して以下を実行

download.packages(pkgs = 'RSQLite', destdir = ".",type = "source")

(試行時にDLできたのは、RSQLite_2.2.18.tar.gz

tar.gzを解凍

Rは一度終了し、DLしたファイルを解凍

tar -zxvf RSQLite_2.2.18.tar.gz

カレントディレクトリにRSQLiteのディレクトリができる

sqlite3.cを書き換える

./RSQLite/src/vendor/sqlite3/sqlite3.c

を開いて、下の部分を探す

#ifndef SQLITE_MAX_COLUMN
# define SQLITE_MAX_COLUMN 2000
#endif

↑の部分を↓のように書き換える

#ifndef SQLITE_MAX_COLUMN
# define SQLITE_MAX_COLUMN 32766
#endif

32767より大きい値を設定するとエラーで弾かれそうです

DESCRIPTIONも書き換える

パッケージのバージョンが混在しないようにするため、DESCRIPTIONも書き換えときます。
※知識不足なので正しいやり方かどうかはわかりません。正しくはこうすべきってのがあれば教えてください。

./RSQLite/DESCRIPTION

を開いて、下の部分を探す

Version: 2.2.18

↑の部分を↓のように書き換える

Version: 2.2.18.1

末尾に「.1」を追加しただけ
バージョンには数字と記号(「.」、「-」)しか使えなさげ?でした。(詳細わかりません)

devtoolsでビルド

Rを起動し、以下を実行

devtools::build("RSQLite")

実行すると

Building the package will delete...
  '~~~~~~~~/RSQLite/inst/doc'
Are you sure?

1: Yes
2: No

Selection:

と聞かれたので、「1」を入力し、Enter

ここで私の環境では実行時にPandocがないと言われましたが、Pandocをインストールすれば通りました。

成功するとカレントディレクトリにRSQLite_2.2.18.1.tar.gzが作成される

RSQLiteをインストール

Rを起動して以下を実行

install.packages("RSQLite_2.2.18.1.tar.gz", repos = NULL)

これでRSQLiteで32766列以下のデータは扱えるはず

編集したRSQLiteをインストールした状態で、再度csvファイルを読み込ませる

  • Rを起動し、CSVを読み込ませる
library(DBI)
library(tidyverse)

con <- dbConnect(RSQLite::SQLite(), "temp.sqlite3")
callback <- function(df, pos) {
   dbWriteTable(con, "temp_table", df, append = TRUE)
}
read_csv_chunked("temp.csv", DataFrameCallback$new(callback))

読み込める!!

  • 一応確認
dbListFields(con, 'temp_table')
    [1] "A1"     "A2"     "A3"     "A4"     "A5"     "A6"     "A7"     "A8"
    [9] "A9"     "A10"    "A11"    "A12"    "A13"    "A14"    "A15"    "A16"
   [17] "A17"    "A18"    "A19"    "A20"    "A21"    "A22"    "A23"    "A24"
                                    
                                    
                                    
[32745] "A32745" "A32746" "A32747" "A32748" "A32749" "A32750" "A32751" "A32752"
[32753] "A32753" "A32754" "A32755" "A32756" "A32757" "A32758" "A32759" "A32760"
[32761] "A32761" "A32762" "A32763" "A32764" "A32765" "A32766"

Windowsの場合どうやるのかわからん

似たような方法でできるとは思うが、申し訳ない…。

さいごに

本来正しく正規化されたデータであれば、このような列数は必要ないかと思う。
が、現実には「え…?」と思うようなCSVファイル等が渡されるわけで…。
こんな感じでデータベースに取り込んで、一度に全ての列を使うわけでもなければ、SELECT分なりでいい感じに列を抜き出してデータ眺めたり、加工したり、解析したりしてみたらいいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1