knitr::opts_chunk$set(warning = FALSE, message = FALSE)

package

pacman::p_load(
  tidyverse,
  lubridate,
  tableone,
  skimr,
  duckdb,
  DBI,
  dbplyr,
  arrow,
  RSQLite
)

データベース

Fドライブの Database フォルダ内にある mimic_iv.db にアクセスします。
各自の環境に合わせて、必要であれば以下のパスを修正してください。

db_path <- "F:/Database/mimic_iv.db"

duckdb::duckdb() で接続すると、指定した .db ファイルが存在しない場合は、空のDBファイルが作成されます。
最初に学生自身がMIMIC-IVのCSVをDB化する場合は、この空のDBにテーブルを追加していきます。

con_mimic <- DBI::dbConnect(duckdb::duckdb(), dbdir = db_path)

DB内に入っているテーブルの一覧を確認します。

DBI::dbListTables(con_mimic)
##  [1] "admissions"               "bja_step01_patients_2026"
##  [3] "caregiver"                "chartevents"             
##  [5] "d_hcpcs"                  "d_icd_diagnoses"         
##  [7] "d_icd_procedures"         "d_items"                 
##  [9] "d_labitems"               "datetimeevents"          
## [11] "diagnoses_icd"            "drgcodes"                
## [13] "emar"                     "emar_detail"             
## [15] "hcpcsevents"              "icustays"                
## [17] "ingredientevents"         "inputevents"             
## [19] "labevents"                "microbiologyevents"      
## [21] "omr"                      "outputevents"            
## [23] "patients"                 "pharmacy"                
## [25] "poe"                      "poe_detail"              
## [27] "prescriptions"            "procedureevents"         
## [29] "procedures_icd"           "provider"                
## [31] "sepsis3"                  "services"                
## [33] "transfers"

その他の処理

テーブルを削除する場合の例です。通常は実行しません。

# DBI::dbRemoveTable(con_mimic, "caregivers")

最後に接続解除する場合は、以下を使います。

# DBI::dbDisconnect(con_mimic, shutdown = TRUE)

dataの読み込み

ファイル名リストの抽出

MIMIC-IVのCSVファイルが以下のフォルダに保存されている前提です。

data_path <- "F:/BigDatas/mimic_iv"

MIMIC-IVでは、hospicu などのサブフォルダにCSVファイルが入っています。
そのため、recursive = TRUE を使って、サブフォルダ内の .csv.gz ファイルもすべて取得します。

csv_list <-
  list.files(
    path = data_path,
    pattern = ".csv.gz$",
    recursive = TRUE,
    full.names = TRUE
  )

csv_list
##  [1] "F:/BigDatas/mimic_iv/hosp/admissions.csv.gz"        
##  [2] "F:/BigDatas/mimic_iv/hosp/d_hcpcs.csv.gz"           
##  [3] "F:/BigDatas/mimic_iv/hosp/d_icd_diagnoses.csv.gz"   
##  [4] "F:/BigDatas/mimic_iv/hosp/d_icd_procedures.csv.gz"  
##  [5] "F:/BigDatas/mimic_iv/hosp/d_labitems.csv.gz"        
##  [6] "F:/BigDatas/mimic_iv/hosp/diagnoses_icd.csv.gz"     
##  [7] "F:/BigDatas/mimic_iv/hosp/drgcodes.csv.gz"          
##  [8] "F:/BigDatas/mimic_iv/hosp/emar.csv.gz"              
##  [9] "F:/BigDatas/mimic_iv/hosp/emar_detail.csv.gz"       
## [10] "F:/BigDatas/mimic_iv/hosp/hcpcsevents.csv.gz"       
## [11] "F:/BigDatas/mimic_iv/hosp/labevents.csv.gz"         
## [12] "F:/BigDatas/mimic_iv/hosp/microbiologyevents.csv.gz"
## [13] "F:/BigDatas/mimic_iv/hosp/omr.csv.gz"               
## [14] "F:/BigDatas/mimic_iv/hosp/patients.csv.gz"          
## [15] "F:/BigDatas/mimic_iv/hosp/pharmacy.csv.gz"          
## [16] "F:/BigDatas/mimic_iv/hosp/poe.csv.gz"               
## [17] "F:/BigDatas/mimic_iv/hosp/poe_detail.csv.gz"        
## [18] "F:/BigDatas/mimic_iv/hosp/prescriptions.csv.gz"     
## [19] "F:/BigDatas/mimic_iv/hosp/procedures_icd.csv.gz"    
## [20] "F:/BigDatas/mimic_iv/hosp/provider.csv.gz"          
## [21] "F:/BigDatas/mimic_iv/hosp/services.csv.gz"          
## [22] "F:/BigDatas/mimic_iv/hosp/transfers.csv.gz"         
## [23] "F:/BigDatas/mimic_iv/icu/caregiver.csv.gz"          
## [24] "F:/BigDatas/mimic_iv/icu/chartevents.csv.gz"        
## [25] "F:/BigDatas/mimic_iv/icu/d_items.csv.gz"            
## [26] "F:/BigDatas/mimic_iv/icu/datetimeevents.csv.gz"     
## [27] "F:/BigDatas/mimic_iv/icu/icustays.csv.gz"           
## [28] "F:/BigDatas/mimic_iv/icu/ingredientevents.csv.gz"   
## [29] "F:/BigDatas/mimic_iv/icu/inputevents.csv.gz"        
## [30] "F:/BigDatas/mimic_iv/icu/outputevents.csv.gz"       
## [31] "F:/BigDatas/mimic_iv/icu/procedureevents.csv.gz"

DBに登録するときのテーブル名を作成します。
たとえば、hosp/admissions.csv.gzadmissionsicu/icustays.csv.gzicustays になります。

short_list <-
  list.files(
    path = data_path,
    pattern = ".csv.gz$",
    recursive = TRUE,
    full.names = FALSE
  )

name_list <- short_list |>
  str_replace_all("\\\\", "/") |>   # Windowsの \ を / に統一
  basename() |>                     # hosp/admission.csv.gz → admission.csv.gz
  str_remove("\\.csv\\.gz$") |>      # admission.csv.gz → admission
  str_to_lower()

name_list
##  [1] "admissions"         "d_hcpcs"            "d_icd_diagnoses"   
##  [4] "d_icd_procedures"   "d_labitems"         "diagnoses_icd"     
##  [7] "drgcodes"           "emar"               "emar_detail"       
## [10] "hcpcsevents"        "labevents"          "microbiologyevents"
## [13] "omr"                "patients"           "pharmacy"          
## [16] "poe"                "poe_detail"         "prescriptions"     
## [19] "procedures_icd"     "provider"           "services"          
## [22] "transfers"          "caregiver"          "chartevents"       
## [25] "d_items"            "datetimeevents"     "icustays"          
## [28] "ingredientevents"   "inputevents"        "outputevents"      
## [31] "procedureevents"

CSVファイルとテーブル名の対応を確認します。

tibble(
  csv_file = csv_list,
  table_name = name_list
)
## # A tibble: 31 × 2
##    csv_file                                          table_name      
##    <chr>                                             <chr>           
##  1 F:/BigDatas/mimic_iv/hosp/admissions.csv.gz       admissions      
##  2 F:/BigDatas/mimic_iv/hosp/d_hcpcs.csv.gz          d_hcpcs         
##  3 F:/BigDatas/mimic_iv/hosp/d_icd_diagnoses.csv.gz  d_icd_diagnoses 
##  4 F:/BigDatas/mimic_iv/hosp/d_icd_procedures.csv.gz d_icd_procedures
##  5 F:/BigDatas/mimic_iv/hosp/d_labitems.csv.gz       d_labitems      
##  6 F:/BigDatas/mimic_iv/hosp/diagnoses_icd.csv.gz    diagnoses_icd   
##  7 F:/BigDatas/mimic_iv/hosp/drgcodes.csv.gz         drgcodes        
##  8 F:/BigDatas/mimic_iv/hosp/emar.csv.gz             emar            
##  9 F:/BigDatas/mimic_iv/hosp/emar_detail.csv.gz      emar_detail     
## 10 F:/BigDatas/mimic_iv/hosp/hcpcsevents.csv.gz      hcpcsevents     
## # ℹ 21 more rows

各ファイルをDB上に登録する

以下は、MIMIC-IVの .csv.gz ファイルを1つずつ読み込み、DuckDB上のテーブルとして登録するコードです。

注意: この処理は、各CSVファイルをDuckDB上の新しいテーブルとして登録する処理です。
同じテーブル名がすでにDB内に存在する場合は、上書きも追記もせず、そのテーブルをスキップする設定にしています。
そのため、同じコードを再実行してもデータが重複して追加されることはありません。

ただし、途中でエラーが出た場合は、一部のテーブルだけが作成済みになっていることがあります。
その場合は、DBI::dbListTables(con_mimic) で作成済みテーブルを確認してから、再実行してください。

for (i in seq_along(name_list)) {

  message("Importing: ", csv_list[i], " -> ", name_list[i])

  if (DBI::dbExistsTable(con_mimic, name_list[i])) {
    message("Skip existing table: ", name_list[i])
    next
  }

  table_name <- DBI::dbQuoteIdentifier(con_mimic, name_list[i])
  file_path <- DBI::dbQuoteString(
    con_mimic,
    normalizePath(csv_list[i], winslash = "/", mustWork = TRUE)
  )

  sql <- paste0(
    "CREATE TABLE ", table_name,
    " AS SELECT * FROM read_csv_auto(",
    file_path,
    ", header = true, quote = '\"', escape = '\"', strict_mode = false, sample_size = -1);"
  )

  DBI::dbExecute(con_mimic, sql)
}

以下は以前の方法です。処理に時間がかかり、append = TRUE による重複追加の危険があるため、今回は使用しません。

# for (i in seq_along(name_list)) {
# 
#   message("Importing: ", csv_list[i], " -> ", name_list[i])
# 
#   callback <- function(df, pos) {
#     DBI::dbWriteTable(
#       conn = con_mimic,
#       name = name_list[i],
#       value = df,
#       append = TRUE
#     )
#   }
# 
#   readr::read_csv_chunked(
#     file = csv_list[i],
#     callback = readr::DataFrameCallback$new(callback),
#     chunk_size = 100000
#   )
# }

登録後は、テーブル一覧を再度確認します。

DBI::dbListTables(con_mimic)
##  [1] "admissions"               "bja_step01_patients_2026"
##  [3] "caregiver"                "chartevents"             
##  [5] "d_hcpcs"                  "d_icd_diagnoses"         
##  [7] "d_icd_procedures"         "d_items"                 
##  [9] "d_labitems"               "datetimeevents"          
## [11] "diagnoses_icd"            "drgcodes"                
## [13] "emar"                     "emar_detail"             
## [15] "hcpcsevents"              "icustays"                
## [17] "ingredientevents"         "inputevents"             
## [19] "labevents"                "microbiologyevents"      
## [21] "omr"                      "outputevents"            
## [23] "patients"                 "pharmacy"                
## [25] "poe"                      "poe_detail"              
## [27] "prescriptions"            "procedureevents"         
## [29] "procedures_icd"           "provider"                
## [31] "sepsis3"                  "services"                
## [33] "transfers"

データの確認

(charteventsは4.3億行!)

以降では、MIMIC-IVの基本テーブルを確認します。
テーブル名は、上のDB化コードに従うと、admissions, patients, icustays になります。

admissions

admissions は入院単位のテーブルです。
1人の患者が複数回入院している場合があるため、subject_id は重複します。

db_ad <- tbl(con_mimic, "admissions")

db_ad |> colnames()
##  [1] "subject_id"           "hadm_id"              "admittime"           
##  [4] "dischtime"            "deathtime"            "admission_type"      
##  [7] "admit_provider_id"    "admission_location"   "discharge_location"  
## [10] "insurance"            "language"             "marital_status"      
## [13] "race"                 "edregtime"            "edouttime"           
## [16] "hospital_expire_flag"
db_ad |> count()
## # Source:   SQL [?? x 1]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##        n
##    <dbl>
## 1 546028
db_ad |> head(5)
## # Source:   SQL [?? x 16]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   subject_id hadm_id admittime           dischtime           deathtime
##        <dbl>   <dbl> <dttm>              <dttm>              <dttm>   
## 1   10000032  2.26e7 2180-05-06 22:23:00 2180-05-07 17:15:00 NA       
## 2   10000032  2.28e7 2180-06-26 18:27:00 2180-06-27 18:49:00 NA       
## 3   10000032  2.57e7 2180-08-05 23:44:00 2180-08-07 17:50:00 NA       
## 4   10000032  2.91e7 2180-07-23 12:35:00 2180-07-25 17:55:00 NA       
## 5   10000068  2.50e7 2160-03-03 23:16:00 2160-03-04 06:26:00 NA       
## # ℹ 11 more variables: admission_type <chr>, admit_provider_id <chr>,
## #   admission_location <chr>, discharge_location <chr>, insurance <chr>,
## #   language <chr>, marital_status <chr>, race <chr>, edregtime <dttm>,
## #   edouttime <dttm>, hospital_expire_flag <dbl>

admissions の行数は入院数です。
一方、subject_id のユニーク数は患者数に近い値になります。

db_ad |>
  distinct(subject_id) |>
  count()
## # Source:   SQL [?? x 1]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##        n
##    <dbl>
## 1 223452

入院数と患者数を同時に確認します。

db_ad |>
  summarise(
    n_admissions = n(),
    n_subjects = n_distinct(subject_id)
  ) 
## # Source:   SQL [?? x 2]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   n_admissions n_subjects
##          <dbl>      <dbl>
## 1       546028     223452

patients

patients は患者単位のテーブルです。
性別、匿名化された年齢情報、死亡日などが含まれます。

db_pt <- tbl(con_mimic, "patients")

db_pt |> colnames()
## [1] "subject_id"        "gender"            "anchor_age"       
## [4] "anchor_year"       "anchor_year_group" "dod"
db_pt |> count()
## # Source:   SQL [?? x 1]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##        n
##    <dbl>
## 1 364627
db_pt |> head(5)
## # Source:   SQL [?? x 6]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   subject_id gender anchor_age anchor_year anchor_year_group dod       
##        <dbl> <chr>       <dbl>       <dbl> <chr>             <date>    
## 1   10000032 F              52        2180 2014 - 2016       2180-09-09
## 2   10000048 F              23        2126 2008 - 2010       NA        
## 3   10000058 F              33        2168 2020 - 2022       NA        
## 4   10000068 F              19        2160 2008 - 2010       NA        
## 5   10000084 M              72        2160 2017 - 2019       2161-02-13

patients では、基本的に subject_id が患者ごとに一意です。

db_pt |>
  summarise(
    n_rows = n(),
    n_subjects = n_distinct(subject_id)
  ) 
## # Source:   SQL [?? x 2]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   n_rows n_subjects
##    <dbl>      <dbl>
## 1 364627     364627

icustays

icustays はICU滞在単位のテーブルです。
今回のBJA論文再現ではICU患者を対象とするため、今後の講義で重要になります。

db_icu <- tbl(con_mimic, "icustays")

db_icu |> colnames()
## [1] "subject_id"     "hadm_id"        "stay_id"        "first_careunit"
## [5] "last_careunit"  "intime"         "outtime"        "los"
db_icu |> count()
## # Source:   SQL [?? x 1]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##       n
##   <dbl>
## 1 94458
db_icu |> head(5)
## # Source:   SQL [?? x 8]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   subject_id  hadm_id  stay_id first_careunit  last_careunit intime             
##        <dbl>    <dbl>    <dbl> <chr>           <chr>         <dttm>             
## 1   10000032 29079034 39553978 Medical Intens… Medical Inte… 2180-07-23 14:00:00
## 2   10000690 25860671 37081114 Medical Intens… Medical Inte… 2150-11-02 19:37:00
## 3   10000980 26913865 39765666 Medical Intens… Medical Inte… 2189-06-27 08:42:00
## 4   10001217 24597018 37067082 Surgical Inten… Surgical Int… 2157-11-20 19:18:02
## 5   10001217 27703517 34592300 Surgical Inten… Surgical Int… 2157-12-19 15:42:24
## # ℹ 2 more variables: outtime <dttm>, los <dbl>

ICU stay数、入院数、患者数の違いを確認します。

db_icu |>
  summarise(
    n_icustays = n(),
    n_admissions = n_distinct(hadm_id),
    n_subjects = n_distinct(subject_id)
  ) 
## # Source:   SQL [?? x 3]
## # Database: DuckDB 1.4.4 [mihara@Windows 10 x64:R 4.5.0/F:\Database\mimic_iv.db]
##   n_icustays n_admissions n_subjects
##        <dbl>        <dbl>      <dbl>
## 1      94458        85242      65366

事前課題  

事前課題の内容はスライド参照  

接続解除  

作業が終わったら、データベース接続を解除します。

# DBI::dbDisconnect(con_mimic, shutdown = TRUE)

END