<jupyter_start><jupyter_text>패혈증의 concept_id 찾기CDM 은 표준용어체계(Standard Vocabulary)를 사용한다. 질병을 나타내는 표준용어체계는 SNOMED가 대표적이다. 만약 원본 진단 레코드가 SNOMED 코드가 아니라면 질병 테이블에 데이터를 적재할 때 원본 레코드의 코드를 원본 레코드와 같거나 비슷한 개념을 갖는 SNOMED concept_id 로 변환해 저장해주어야 한다. 따라서 MIMIC 데이터의 진단 용어인 ICD9 코드는 SNOMED concept_id 로 맵핑된다. 예를 들어, ICD9 코드 77181 “Septicemia [sepsis] of newborn” 은 SNOMED condition_concept_id 4071063 “Sepsis of the newborn” 으로 변환된다. 원본 ICD9 코드정보 버려지지 않고  condition_source_value 칼럼에 기록된다. MIMIC 데이터에서 패혈증을 뜻하는 ICD9 코드가 '77181', '99591', '99592', '67020', '67022', '67024' 라는 정보를 이용하여 MIMIC-CDM 질병 테이블에 존재하는 패혈증 관련 SNOMED concept_id 를 바로 확인할 수 있다.<jupyter_code>sql = """
SELECT distinct condition_concept_id, condition_source_value
FROM mimiccdm.condition_occurrence 
WHERE condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024') 
"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>패혈증 환자 찾기위에서 구한 패혈증 concept_id 를 기준으로 질병 테이블에서 패혈증 환자를 찾고 어떤 병명으로 진단받았는지 확인해보자. 여기에 진단 테이블을 활용한다.| 칼럼명                      | 설명                        | 예시                             ||-----------------------------|-----------------------------|----------------------------------|| condition_occurrence_id     | 레코드 식별자               | 336322064                        || person_id                   | 환자번호                    | 392807711                        || condition_concept_id        | 특정 진단에 대한 concept_id | 320128  (Essential Hypertension) || condition_start_date        | 진단 시작일                 | 2150-04-17                       || condition_end_date          | 진단 종료일                 | 2150-04-21                       || condition_source_value      | 원본 진단코드               | 4019                             || condition_source_concept_id | 원본 진단코드의 concept_id  | 44821949                         |<jupyter_code>sql = """
SELECT co.condition_concept_id, c.concept_name,
       co.person_id, 
       co.condition_start_date, co.condition_end_date
FROM mimiccdm.condition_occurrence co 
JOIN mimiccdm.concept c 
   ON co.condition_concept_id = c.concept_id -- 해석 1번
WHERE co.condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024');
"""
df = pd.read_sql(sql, engine)
df.shape
df.head()
sql = """
SELECT count(distinct co.person_id)
FROM mimiccdm.condition_occurrence co 
WHERE co.condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024');
"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>패혈증 진단받은 환자 비율 구하기MIMIC-CDM 데이터에 존재하는 환자 중 패혈증 환자의 비율은 얼마나 될까? 패혈증 환자를 추출하면서 확인한 환자ID(person_id) 정보를 이용해 전체 환자 중 패혈증 환자의 비율을 구해보자.<jupyter_code>sql = """
with all_patients as ( -- mimiccdm 전체환자
		SELECT distinct person_id
		FROM mimiccdm.person ),
sepsis as ( -- sepsis 진단환자
	SELECT distinct person_id
	FROM mimiccdm.condition_occurrence co 
	WHERE co.condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024')),
sepsis_table as (
		SELECT count(*) AS all_cnt,
			 sum(case when person_id in (select person_id
  								from sepsis)
 					   then 1 else 0 end) sepsis_cnt,
			 sum(case when person_id not in (select person_id
  								from sepsis)
 					   then 1 else 0 end) sepsis_not_cnt
		FROM all_patients )
SELECT all_cnt, sepsis_cnt, sepsis_not_cnt, 
       ROUND(sepsis_cnt * 100.0 / all_cnt, 2) AS sepsis_percentage
FROM sepsis_table;
"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>첫 진단시점의 연령 구하기질병 테이블에서 추출한 패혈증 환자 중 패혈증 진단을 1번만 받은 환자도 있지만 여러 번 패혈증 진단을 받은 환자도 존재할 것이다. 진단 시점마다 환자의 연령이 달라지므로 각 환자의 최초 패혈증 진단 시점 시 연령을 확인해보자. 이는 [ (첫 진단일) - (생년월일) ] 로 계산할 수 있다.환자 테이블을 참고하여 첫 진단 시 18세 이상 환자수를 구해보자.| 칼럼명              | 설명                              | 예시         ||---------------------|-----------------------------------|--------------|| person_id           | 환자 식별자 (환자ID)              | 392776072    || gender_concept_id   | 환자의 성별을 나타내는 concept_id | 8507 (Male)  || year_of_birth       | 태어난 년도                       | 2138         || month_of_birth      | 태어난 월                         | 7            || day_of_birth        | 태어난 일                         | 17           || race_concept_id     | 인종을 나타내는 concept_id        | 8515 (Asian) || gender_source_value | 성별 원본값                       | M            || race_source_value   | 인종 원본값                       | ASIAN        |<jupyter_code>sql = """
with sepsis_1st as (
    SELECT person_id, min(condition_start_date) as min_start_date
    FROM mimiccdm.condition_occurrence
    WHERE condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024')
    GROUP BY person_id)
, sepsis_diag_age as (
    SELECT p.person_id,
        gender_source_value,
        date_part('year', age(s.min_start_date, to_date(concat_ws('-', year_of_birth, month_of_birth, day_of_birth), 'YYYY-MM-DD'))) AS person_age
    FROM mimiccdm.person p 
    JOIN sepsis_1st s 
    ON p.person_id = s.person_id
)
SELECT person_id, person_age
FROM sepsis_diag_age
WHERE person_age >= 18
"""
df = pd.read_sql(sql, engine)
df.shape
df.head()<jupyter_output><empty_output><jupyter_text>패혈증에 처방되는 항생제 약물 찾기약처방 테이블에는 처방된 약물 내역, 화학 요법, 백신과 같이 환자에게 투여되는 약물에 대한 기록이 있다. 약처방 테이블의 주요 칼럼은 아래표와 같다. | 칼럼명                   | 설명                 | 예시       ||--------------------------|----------------------|------------|| drug_exposure_id         | 투약기록 식별자      | 395847254  || person_id                | 환자 식별자 (환자ID) | 392818344  || drug_concept_id          | 약물의 concept_id    | 40221385   || drug_exposure_start_date | 약물 투여시작일      | 2117-09-13 || drug_expousre_end_date   | 약물 투여종료일      | 2117-09-15 || quantity                 | 수량/투여량          | 100        || dose_unit_source_value   | 투여 단위            | mL         || route_concept_id         | 약물 투여경로        | 4112421    |약처방 테이블의 칼럼을 사용하여 분석 대상인 반코마이신을 찾아낼 수 있다. 4.4절에서 했던 방법과 동일하게 약물의 성분명으로 반코마이신이 들어가는 concept_id 를 컨셉 테이블에서 조회해보자.<jupyter_code>sql = """
SELECT distinct concept_id, concept_name
FROM mimiccdm.concept
WHERE concept_name ILIKE '%%vancomycin%%'
AND domain_id = 'Drug' -- 해석 1번
AND vocabulary_id = 'RxNorm';
"""
df = pd.read_sql(sql, engine)
df.shape
df.head()<jupyter_output><empty_output><jupyter_text>정맥주사로 항생제를 처방받은 환자 찾기앞서 반코마이신 항생제와 관련된 concept_id 가 여러개 조회되었다. 컨셉 테이블의 concept_id는 약처방 테이블의 drug_concept_id와 같으므로, 약처방 테이블의 drug_concept_id가 반코마이신 항생제인 처방 기록을 조회할 수 있다. 또한 투여경로 중 정맥주사를 특정하기 위하여 concept_name "Intravenous"인 concept_id 4112421를 사용하여 정맥주사로 반코마이신 항생제를 처방받은 환자를 조회한다.<jupyter_code>sql = """
SELECT concept_id, concept_name
FROM mimiccdm.concept 
where concept_id in (select distinct de.route_concept_id from mimiccdm.drug_exposure de )
"""
df = pd.read_sql(sql, engine)
df.shape
df.head()
sql = """
WITH vancomycin as (
    SELECT concept_id, concept_name
    FROM mimiccdm.concept 
    WHERE concept_name ILIKE '%%vancomycin%%'
        AND domain_id = 'Drug'
        AND vocabulary_id = 'RxNorm'
), vancomycin_patients as (
    SELECT distinct de.person_id, de.drug_concept_id, v.concept_id, v.concept_name, de.route_concept_id
    FROM mimiccdm.drug_exposure de
    JOIN vancomycin v
    ON v.concept_id = de.drug_concept_id
)
SELECT count(distinct person_id)
FROM vancomycin_patients
WHERE route_concept_id = 4112421
"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>패혈증 환자의 진단검사 결과 필터링하기CDM의 검사(Measurement) 테이블은 검사와 관련된 레코드를 갖고 있다. 예를 들어, 검사를 통해 얻은 측정 기록(숫자 또는 범주형), 실험실에서의 측정, 활력징후, 병리학 보고서의 결과와 측정 순서 등이 모두 기록된다. 검사 테이블의 주요 칼럼은 아래표와 같다. | 칼럼명                 | 설명                   | 예시       ||------------------------|------------------------|------------|| measurement_id         | 진단검사 레코드 식별자 | 236343175  || person_id              | 환자 식별자 (환자ID)   | 392818344  || measurement_concept_id | 진단검사 concept_id    | 3024171    || measurement_date       | 진단검사일             | 2118-08-23 || value_as_number        | 검사결과 (숫자)        | 13         || unit_source_value      | 결과 단위              | insp/min   | - 빌리루빈 1.2 mg/dL 이상  - 빌리루빈 검사에 해당하는 concept_id 를 찾기 위해 컨셉 테이블에서 concept_name 에 ‘bilirubin’ 문자열이 들어가는 컨셉을 조회한다. 빌루루빈 검사를 찾는것이므로 domain_id 를 ‘Measurement’ 으로 좁혀서 검색해보자.- 혈소판수 150 K/uL 미만  - 혈소판수를 확인하는 concept_id 를 찾기 위해 컨셉 테이블에서 concept_name 에 ‘platelet%count’ 가 포함되어 있는 컨셉을 조회한다. 빌리루빈 검사와 마찬가지로 domain_id 를 ‘Measurement’ 으로 좁혀서 검색해보자.<jupyter_code>sql = """
with bilirubin as (
	SELECT concept_id, concept_name
	FROM mimiccdm.concept
	WHERE concept_name ILIKE '%%bilirubin%%'
	AND domain_id = 'Measurement'
)
SELECT count(distinct m.person_id)
FROM mimiccdm.measurement m 
JOIN bilirubin b 
ON m.measurement_concept_id = b.concept_id
WHERE m.value_as_number >= 1.2
"""
df = pd.read_sql(sql, engine)
df
sql = """
with platelet_count as (
  SELECT concept_id, concept_name
  FROM mimiccdm.concept
  WHERE concept_name ILIKE '%%platelet%%count%%'
  AND domain_id = 'Measurement')
SELECT count(distinct m.person_id) 
FROM mimiccdm.measurement m 
JOIN platelet_count p 
ON m.measurement_concept_id = p.concept_id
WHERE m.value_as_number < 150

"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>- 빌리루빈과 혈소판수 조건에 모두 해당하는 환자<jupyter_code>sql = """

with bilirubin as (
    SELECT concept_id, concept_name
    FROM mimiccdm.concept
    WHERE concept_name ILIKE '%%bilirubin%%'
    AND domain_id = 'Measurement'
),
platelet_count as (
  SELECT concept_id, concept_name
  FROM mimiccdm.concept
  WHERE concept_name ILIKE '%%platelet%%count%%'
  AND domain_id = 'Measurement'
), bilirubin_platelet as (
SELECT distinct m.person_id
FROM mimiccdm.measurement m 
JOIN bilirubin b 
ON m.measurement_concept_id = b.concept_id
WHERE m.value_as_number >= 1.2

intersect  

SELECT distinct m.person_id 
FROM mimiccdm.measurement m 
JOIN platelet_count p 
ON m.measurement_concept_id = p.concept_id
WHERE m.value_as_number < 150
)
SELECT count(distinct person_id)
FROM bilirubin_platelet
"""
df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output><jupyter_text>모든 조건에 해당하는 환자수<jupyter_code>sql = """

with sepsis_1st as (
    SELECT person_id, min(condition_start_date) as min_start_date
    FROM mimiccdm.condition_occurrence
    WHERE condition_source_value in ('77181', '99591', '99592', '67020', '67022', '67024')
    GROUP BY person_id
), sepsis_diag_age as (
    SELECT p.person_id,
        gender_source_value,
        date_part('year', age(s.min_start_date, to_date(concat_ws('-', year_of_birth, month_of_birth, day_of_birth), 'YYYY-MM-DD'))) AS person_age
    FROM mimiccdm.person p 
    JOIN sepsis_1st s 
    ON p.person_id = s.person_id
), vancomycin as (
    SELECT concept_id, concept_name
    FROM mimiccdm.concept 
    WHERE concept_name ILIKE '%%vancomycin%%'
        AND domain_id = 'Drug'
        AND vocabulary_id = 'RxNorm'
), vancomycin_patients as (
    SELECT distinct de.person_id, de.drug_concept_id, v.concept_id, v.concept_name, de.route_concept_id
    FROM mimiccdm.drug_exposure de
    JOIN vancomycin v
    ON v.concept_id = de.drug_concept_id
), bilirubin as (
    SELECT concept_id, concept_name
    FROM mimiccdm.concept
    WHERE concept_name ILIKE '%%bilirubin%%'
        AND domain_id = 'Measurement'
), platelet_count as (
    SELECT concept_id, concept_name
    FROM mimiccdm.concept
    WHERE concept_name ILIKE '%%platelet%%count%%'
        AND domain_id = 'Measurement'
), bilirubin_platelet as (
    SELECT distinct m.person_id
    FROM mimiccdm.measurement m 
    JOIN bilirubin b 
    ON m.measurement_concept_id = b.concept_id
    WHERE m.value_as_number >= 1.2

    intersect  

    SELECT distinct m.person_id 
    FROM mimiccdm.measurement m 
    JOIN platelet_count p 
    ON m.measurement_concept_id = p.concept_id
    WHERE m.value_as_number < 150
), all_inclusion_criteria as (
    SELECT person_id
    FROM sepsis_diag_age
    WHERE person_age >= 18

    intersect

    SELECT person_id
    FROM vancomycin_patients
    WHERE route_concept_id = 4112421

    --intersect

    --SELECT person_id
    --FROM bilirubin_platelet
)
select count(distinct person_id)
from all_inclusion_criteria
"""

df = pd.read_sql(sql, engine)
df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1077943615257048, 'fraction_numerical': 0.037645107794361525, 'mean_word_length': 2.723680148193887, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '545495', 'license': 'MIT', 'n_tokens_mistral': 5885, 'n_tokens_neox': 6199, 'n_words': 1155, 'path': 'Sepsis-use-case.ipynb', 'repo_name': 'linewalks/feasibility_check_sepsis', 'size': '12060'}