Skip to content

Latest commit

ย 

History

History
102 lines (73 loc) ยท 5.34 KB

File metadata and controls

102 lines (73 loc) ยท 5.34 KB

OpenMIMIC: MIMIC Preprocessing Library

github_action_PyPI_upload

MIMIC_preprocessing์€ ๋Œ€๊ทœ๋ชจ ์ „์ž๊ฑด๊ฐ•๊ธฐ๋ก(EHR) ๋ฐ์ดํ„ฐ, ํŠนํžˆ MIMIC-III/IV ๋ฐ์ดํ„ฐ์…‹์„ ํšจ์œจ์ ์œผ๋กœ ์ „์ฒ˜๋ฆฌํ•˜๊ณ  ๋ถ„์„ํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋œ Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

EHR ๋ฐ์ดํ„ฐ๋Š” ๋ฐฉ๋Œ€ํ•œ ์–‘์˜ ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด ์ผ๋ฐ˜์ ์ธ Pandas ์—ฐ์‚ฐ๋งŒ์œผ๋กœ๋Š” ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋งค์šฐ ๋А๋ฆฝ๋‹ˆ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ™˜์ž(ICUSTAY_ID) ๋‹จ์œ„์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€ ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ ์ •๋ ฌ(Alignment) ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ฐ€์†ํ™”ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ์ „์ฒ˜๋ฆฌ ๋ฐฉ์‹

์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ์ „์ฒ˜๋ฆฌ ํ๋ฆ„์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

  1. ํ™˜์ž ํ•„ํ„ฐ๋ง: ICUSTAY_ID๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์œ ํšจํ•œ ํ™˜์ž ์„ ๋ณ„ (์˜ˆ: 48์‹œ๊ฐ„ ์ด์ƒ ์ž…์› ํ™˜์ž ํ•„ํ„ฐ๋ง check_48h).
  2. ์‹œ๊ณ„์—ด ์ •๋ ฌ (Time Alignment): ๋ถˆ๊ทœ์น™ํ•œ ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฅผ 1์‹œ๊ฐ„, 4์‹œ๊ฐ„, 24์‹œ๊ฐ„ ๋“ฑ ํŠน์ • ๊ฐ„๊ฒฉ(intv_h)์œผ๋กœ ์ •๋ ฌํ•˜๊ณ  ์ง‘๊ณ„(Aggregation)ํ•ฉ๋‹ˆ๋‹ค (process_interval_shift_alignment).
  3. ๋ฐ์ดํ„ฐ ํด๋ Œ์ง•: ์—ฐ๊ด€ ์—†๋Š” ์ปฌ๋Ÿผ ์ œ๊ฑฐ, ์ด์ƒ์น˜ ์ฒ˜๋ฆฌ ๋ฐ ๋‹จ์œ„(UOM) ๋งคํ•‘์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. ๋ณ‘๋ ฌ ๊ฐ€์†ํ™”: @ParallelEHR ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ๋ฉ€ํ‹ฐ์ฝ”์–ด๋ฅผ ํ™œ์šฉํ•œ ๊ณ ์† ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์„ค์น˜ ๋ฐฉ๋ฒ• (Installation)

PyPI๋ฅผ ํ†ตํ•ด ์†์‰ฝ๊ฒŒ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

pip install openmimic

๐Ÿš€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ: @ParallelEHR

@ParallelEHR์€ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์œผ๋กœ, Pandas DataFrame ์—ฐ์‚ฐ์„ CPU ์ฝ”์–ด ์ˆ˜์— ๋งž์ถฐ ์ž๋™์œผ๋กœ ๋ณ‘๋ ฌํ™”ํ•ด์ฃผ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

์™œ ์œ ์šฉํ•œ๊ฐ€์š”?

MIMIC๊ณผ ๊ฐ™์€ ์˜๋ฃŒ ๋ฐ์ดํ„ฐ๋Š” ๋ณดํ†ต ์ˆ˜๋ฐฑ๋งŒ ํ–‰(Row)์„ ๊ฐ€์ง€์ง€๋งŒ, ๋ถ„์„ ๋‹จ์œ„๋Š” ํ™˜์ž(ICUSTAY_ID)๋ณ„๋กœ ๋…๋ฆฝ์ ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ df.groupby().apply()๋Š” ๋‹จ์ผ ์ฝ”์–ด๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋งค์šฐ ๋А๋ฆฝ๋‹ˆ๋‹ค.

@ParallelEHR์€:

  1. ์ง€์ •๋œ ์ปฌ๋Ÿผ(์˜ˆ: ICUSTAY_ID)์„ ๊ธฐ์ค€์œผ๋กœ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„ํ• ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฐ ๊ทธ๋ฃน์„ ๋ณ„๋„์˜ ํ”„๋กœ์„ธ์Šค(Process)์— ํ• ๋‹นํ•˜์—ฌ ๋™์‹œ์— ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ํ•˜๋‚˜์˜ DataFrame์œผ๋กœ ํ•ฉ์ณ(pd.concat) ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  4. cloudpickle์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ํ•จ์ˆ˜๋‚˜ ์˜์กด์„ฑ๋„ ๋ฌธ์ œ์—†์ด ์ง๋ ฌํ™”ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ๋ฐฉ๋ฒ• (Usage Example)

ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•  ๋•Œ @ParallelEHR("๊ธฐ์ค€_์ปฌ๋Ÿผ๋ช…")์„ ๋ถ™์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฃผ์˜: ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ ์šฉ๋œ ํ•จ์ˆ˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž ํ˜น์€ *args ์ค‘ ํ•˜๋‚˜๋กœ ๋ฐ˜๋“œ์‹œ DataFrame์„ ๋ฐ›์•„์•ผ ํ•˜๋ฉฐ, ํ•ด๋‹น DataFrame์—๋Š” ๊ธฐ์ค€_์ปฌ๋Ÿผ๋ช…์ด ์กด์žฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import pandas as pd
import numpy as np
from openmimic.utils import ParallelEHR

# ์˜ˆ์‹œ: ๋Œ€์šฉ๋Ÿ‰ ์ฐจํŠธ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ
# ์‹ค์ œ๋กœ๋Š” pd.read_csv('chartevents.csv') ๋“ฑ์„ ์‚ฌ์šฉ
data = {
    'ICUSTAY_ID': np.random.randint(200000, 200100, 100000),
    'CHARTTIME': pd.date_range(start='1/1/2022', periods=100000, freq='T'),
    'VALUENUM': np.random.randn(100000)
}
df_huge = pd.DataFrame(data)

# ---------------------------------------------------------
# @ParallelEHR ์‚ฌ์šฉ ์˜ˆ์‹œ
# ---------------------------------------------------------

@ParallelEHR(column_name="ICUSTAY_ID")
def complex_feature_engineering(df, param1, param2):
    """
    ๊ฐ ํ™˜์ž ๊ทธ๋ฃน(Chunk)๋ณ„๋กœ ์‹คํ–‰๋  ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
    ๋งˆ์น˜ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋“ฏ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    """
    # ์˜ˆ: ํ™˜์ž๋ณ„๋กœ ๋ณต์žกํ•œ ์ด๋™ ํ‰๊ท ์ด๋‚˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰
    # ์—ฌ๊ธฐ๋กœ ๋“ค์–ด์˜ค๋Š” df๋Š” ์ „์ฒด ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ, 
    # ์ž๋™์œผ๋กœ ๋ถ„ํ• ๋œ ํ™˜์ž๋“ค์˜ ๋ถ€๋ถ„ ๋ฐ์ดํ„ฐ(subset)์ž…๋‹ˆ๋‹ค.
    
    # 1. ์˜ˆ์‹œ ์—ฐ์‚ฐ: ๊ฐ’์ด ํŠน์ • ๋ฒ”์œ„์ธ ๊ฒฝ์šฐ ํ•„ํ„ฐ๋ง
    df['processed_value'] = df['VALUENUM'] * param1 + param2
    
    # 2. ํ™˜์ž๋ณ„ ๊ทธ๋ฃน ์—ฐ์‚ฐ
    df['rolling_mean'] = df.groupby('ICUSTAY_ID')['VALUENUM'].transform(lambda x: x.rolling(5).mean())
    
    return df

# ์‹คํ–‰ (๋‚ด๋ถ€์ ์œผ๋กœ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ์ˆ˜ํ–‰)
if __name__ == '__main__':
    # ์ž๋™์œผ๋กœ CPU ์ฝ”์–ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ๋ณ‘๋ ฌ๋กœ ์ž‘์—… ํ›„ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
    result_df = complex_feature_engineering(df_huge, param1=1.5, param2=10)
    
    print(result_df.head())
    print(f"์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ ํฌ๊ธฐ: {result_df.shape}")

์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

  • @ParallelEHR์€ ๋‚ด๋ถ€์ ์œผ๋กœ mp.cpu_count() * 0.8 ๋งŒํผ์˜ ์ฝ”์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์–ด ์‹œ์Šคํ…œ ๊ณผ๋ถ€ํ•˜๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ์ชผ๊ฐœ๊ณ  ํ•ฉ์น˜๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•œ ์—ฐ์‚ฐ๋ณด๋‹ค๋Š” ์—ฐ์‚ฐ ๋น„์šฉ์ด ๋†’์€ ์ž‘์—…์ด๋‚˜ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€์žฅ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

๊ธฐํƒ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ

  • check_48h(df): ํ™˜์ž์˜ ICU ์žฌ์› ๊ธฐ๊ฐ„์ด 48์‹œ๊ฐ„ ์ด์ƒ์ธ์ง€ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  • process_interval_shift_alignment(df, item_interval_info): ๋‹ค์–‘ํ•œ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ(1์‹œ๊ฐ„, 4์‹œ๊ฐ„ ๋“ฑ)์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ ฌํ•˜๊ณ  ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • print_completion: ํ•จ์ˆ˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜์—ฌ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

License

MIT license