Обработка данных MIMIC-III и eICU с использованием Google Big Query

Как можно использовать Google Big Query для выполнения типичных шагов обработки данных, предшествующих обучению и настройке любой модели машинного обучения.

В этой статье я расскажу вам, как можно использовать Google Big Query для выполнения типичных шагов обработки данных, предшествующих обучению и настройке любой модели машинного обучения. В качестве примера мы будем использовать медицинский вариант обучения модели для прогнозирования остановки сердца у пациентов отделения интенсивной терапии.

Общие сведения о проблеме данных прогнозирования сердечной деятельности

SCA (внезапная остановка сердца) — это неотложная медицинская помощь, при которой сердце внезапно перестает биться, что приводит к смерти пациента в течение нескольких минут. Показатели выживаемости при SCA составляют ‹25% в больницах. SCA можно предотвратить, если основная причина выявлена ​​и устранена. Цель этого проекта omdena состояла в том, чтобы расширить алгоритм прогнозирования остановки сердца на электрическую активность без пульса и асистолию, предоставив алгоритм прогнозирования остановки сердца по любой причине для более чем 90% пациентов. Более подробная информация об этом вызове доступна здесь.

Данные, необходимые для построения моделей прогнозирования остановки сердца, были получены из двух источников: MIMIC-III и eICU.

  1. MIMIC-III («Медицинская информационная витрина для интенсивной терапии») — это большая одноцентровая база данных, содержащая информацию о пациентах, поступивших в отделения интенсивной терапии в крупной больнице третичной помощи.
  2. eICU — это совместная исследовательская база данных, содержащая данные из множества отделений интенсивной терапии на всей территории континентальной части США. Данные в совместной базе данных охватывают пациентов, поступивших в отделения интенсивной терапии в 2014 и 2015 годах.

Доступ к обеим этим базам данных можно получить через сайт Физинет. После получения доступа данные доступны для запроса в больших наборах данных запроса, как показано на рисунке 1 ниже.

На рисунке 2 ниже показаны типичные этапы обработки данных перед подгонкой модели машинного обучения к данным. Эти шаги включают в себя извлечение, очистку данных, вменение пропущенных значений, формирование данных и выполнение разработки признаков. Большую часть времени обработка данных выполняется на питоне с использованием pandas, NumPy и т. д. Здесь мы выполняем все этапы обработки данных, используя большой запрос Google Google. Ниже я подробно расскажу о каждом из этих шагов.

Для простоты понимания запросов, описанных в этой статье, имена наборов данных и таблиц приведены для справки в таблицах 1 и 2 ниже.

  1. Извлечение данных

Первым шагом любого этапа обработки данных является извлечение данных из исходной системы. Этого можно легко добиться с помощью SQL, поскольку данные MIMIC-III и eICU размещаются в большом запросе Google. Одной из ключевых характеристик, которая потребуется модели прогнозирования остановки сердца, будут жизненно важные показатели пациента, т. е. систолическое артериальное давление, диастолическое артериальное давление, температура, частота сердечных сокращений и т. д. Давайте сначала извлечем жизненно важные показатели из обеих исходных систем с помощью SQL. Для простоты по приведенному ниже запросу извлекается только жизненная частота сердечных сокращений, и результаты представлены на рисунках 3 и 4 ниже. Пребывание в отделении интенсивной терапии уникально и определяется идентификатором пребывания в отделении интенсивной терапии в источнике данных.

-- heart rate for every ICU Stay for a patient from MIMIC-III
select
ce.icustay_id -- icu stay id
,ce.charttime -- date/time when reading was taken
,di.label -- vital name
,ce.value as vital_reading -- vital reading
from
`physionet-data.mimiciii_clinical.chartevents` ce
join `physionet-data.mimiciii_clinical.d_items` di
ON ce.itemid = di.itemid
where lower(di.LABEL) = 'heart rate'
limit 10;
-- heart rate for every ICU Stay for a patient from eICU
select
d.patientunitstayid -- icu stay id
,d.nursingchartoffset -- date/time offset when reading was taken
,lower(d.nursingchartcelltypevallabel) as vital_name -- vital name
,d.nursingchartvalue as vital_reading -- vital reading
from `physionet-data.eicu_crd.nursecharting` d
where lower(d.nursingchartcelltypevallabel) = 'heart rate'
and lower(d.nursingchartcelltypevalname) = 'heart rate'
limit 10;

Чтобы извлечь все необходимые жизненно важные данные, используя тот же запрос, который использовался выше, но без явного написания каждого основного имени, мы создаем простую справочную таблицу с именем «feature_lookup», которая содержит список всех основных показателей, которые мы хотим извлечь из источников. В рамках этой статьи мы сосредоточимся на 7 основных жизненно важных показателях — частоте сердечных сокращений, систолическом и диастолическом артериальном давлении, температуре, шкале комы Глазго, частоте дыхания и насыщении кислородом. Эту справочную таблицу feature_lookup можно создать вручную с помощью файла .csv или листа Google и загрузить в большой набор данных mimic_iii_staging.

Взгляд на CSV-файл поиска признаков показан ниже на рисунке 5 для источника данных mimic-iii. Таблица feature_lookup содержит item_codes для каждой жизненно важной метки в базе данных mimic-iii, а также сведения о том, может ли жизненно необходимая информация быть преобразована в единую единицу измерения. Аналогичный можно построить и для данных eICU.

Теперь мы готовы извлечь все 7 основных показателей, как указано в файле feature_lookup. Мы переписываем приведенный выше SQL-запрос, используя таблицу feature_lookup, и удаляем жестко запрограммированное предложение where, включенное в предыдущие запросы.

-- all vitals for every ICU Stay for a patient from MIMIC-III
select
ce.icustay_id -- icu stay id
,ce.charttime -- date/time when reading was taken
,di.label -- vital name
,ce.value as vital_reading -- vital reading
from
`physionet-data.mimiciii_clinical.chartevents` ce
join `physionet-data.mimiciii_clinical.d_items` di
ON ce.itemid = di.itemid
join `mimic_iii_staging.feature_lookup` fl
on di.itemid = fl.item_code
where lower(di.LABEL) = 'heart rate'
limit 10;
-- all vitals for every ICU Stay for a patient from eICU
select
d.patientunitstayid -- icu stay id
,d.nursingchartoffset -- date/time offset when reading was taken
,lower(d.nursingchartcelltypevallabel) as vital_name -- vital name
,d.nursingchartvalue as vital_reading -- vital reading
from `physionet-data.eicu_crd.nursecharting` d
join `eICU_staging.feature_lookup` f
on d.nursingchartcelltypevallabel =f.string_field_0
and d.nursingchartcelltypevalname = f.string_field_1
where lower(d.nursingchartcelltypevallabel) = 'heart rate'
and lower(d.nursingchartcelltypevalname) = 'heart rate'
limit 10;

В отличие от данных mimic-iii, данные eICU не содержат время диаграммы, а вместо этого содержат смещение, которое представляет собой смещение в минутах от времени приема ICU. Мы можем справиться с этим, создав фиктивное время графика, чтобы оно соответствовало данным mimic-iii. Для краткости я рассмотрел запросы только для данных mimic-iii, но запросы для eICU будут очень похожи на запросы mimic-iii.

2. Очистка данных

Далее мы сосредоточимся на очистке данных. Этот шаг включает в себя стандартизацию показателей жизнедеятельности в единой единице измерения и обработку выбросов.

2.1 Стандартизация единиц измерения

Некоторые жизненно важные параметры в исходных данных были зафиксированы в разных единицах измерения, например, температура захвата хранится в градусах Фаренгейта, а не в градусах Цельсия.

Как видно из раздела 1, таблица feature_lookup уже указывает, какие жизненно важные показатели и единицы измерения необходимо стандартизировать, и мы используем это в приведенном ниже запросе для mimic-iii. Используя оператор case SQL, если необходимо преобразовать витальное значение, мы применяем необходимую формулу для преобразования значения из одной единицы в другую. После стандартизации основных показателей мы сохраняем результаты вывода в промежуточной таблице vital_std, чтобы последующая обработка могла ссылаться на эту таблицу.

-- standardisation of vitals in mimic-iii data
create or replace table mimic_iii_staging.vital_std
as
SELECT
ce.icustay_id -- icu stay id
,ce.charttime -- date/time when reading was taken
,fl.level_0 as vital_name -- vital name
,ce.value as vital_reading -- vital reading
,case
when conversion_unit = 'celsius' and SAFE_CAST(REGEXP_REPLACE(ce.value,'[^0-9.]','') AS FLOAT64) > 79 then (SAFE_CAST(REGEXP_REPLACE(ce.value,'[^0-9.]','') AS FLOAT64) - 32) * 5./9
when conversion_unit = 'percent' and SAFE_CAST(REGEXP_REPLACE(ce.value,'[^0-9.]','') AS FLOAT64) <= 1 then SAFE_CAST(REGEXP_REPLACE(ce.value,'[^0-9.]','') AS FLOAT64) * 100
else SAFE_CAST(REGEXP_REPLACE(ce.value,'[^0-9.]','') AS FLOAT64) end as std_vital_reading -- standard vital reading
FROM
`physionet-data.mimiciii_clinical.chartevents` ce
join `mimic_iii_staging.feature_lookup` fl
on ce.itemid = fl.item_code;

2.2 Обработка выбросов

После того, как измерения стандартизированы, следует обработка выбросов. Выбросы могут оказать непропорциональное влияние на модели машинного обучения и исказить результаты. Для жизненно важных показателей отделения интенсивной терапии мы определяем диапазоны выбросов для каждого жизненно важного показателя в таблице variable_range набора данных mimic_iii_staging и eICU_staging.

Данные таблицы variable_range взяты из документа MIMIC-Extract, а методология обработки выбросов, описанная в документе, используется в приведенном ниже запросе. Таблица variable_range в большом запросе сначала создается путем загрузки файла variable_range.csv, доступного в git repo из документа MIMIC-Extract. Снимок таблицы variable_range показан на рисунке 9 ниже.

Теперь мы соединяем ранее созданную таблицу vital_std с таблицей variable_range для обработки выбросов и сохранения данных в новой таблице vital_outlier. Если жизненно важное значение находится за границей выброса, жизненно важное значение заменяется нулем. В противном случае, если жизненный показатель находится внутри границы выброса, применяется допустимое высокое или допустимое низкое значение.

Исключительный запрос показан ниже. Результат обработки выбросов сохраняется в таблице vital_outlier. Аналогичный запрос выполняется для данных eICU путем объединения таблицы Nurcharting со справочной таблицей variable_range.

--outlier handling for mimic-iii data
create or replace table mimic_iii_staging.vital_outlier
as
SELECT
vs.icustay_id
, vs.charttime
, vs.vital_name --vital name
, case
when vs.std_vital_reading < OUTLIER_LOW or vs.std_vital_reading > OUTLIER_HIGH then Null
when vs.std_vital_reading < VALID_LOW then VALID_LOW
when vs.std_vital_reading > VALID_HIGH then VALID_HIGH
else vs.std_vital_reading
end as outlier_handled_vital_reading --outlier corrected vital reading
, vr.*
FROM `mimic_iii_staging.vital_std` vs
left join `mimic_iii_staging.variable_range` vr
on lower(vs.vital_name) = lower(vr.LEVEL2);

3. Агрегирование и сводка

Данные жизненно важных функций необходимо дополнительно агрегировать, поскольку жизненно важные показатели фиксируются в разные часы и время для каждого пациента в отделении интенсивной терапии, а также могут различаться по частоте их появления. Мы агрегируем данные, беря среднее жизненное значение за каждый час для каждого пациента.

Например, если есть 3 показания частоты сердечных сокращений между 14:00 и 15:00, то одно среднее значение частоты сердечных сокращений по этим трем показаниям будет сохранено по отношению к 15:00 по графику жизненно важных показателей для пребывания в отделении интенсивной терапии. Опять же, SQL для больших запросов упрощает агрегирование данных. Результат этапа агрегации показан на рисунке 11.

--aggregate vital readings by hour for each icu stay for mimic-iii data
create or replace table `mimic_iii_staging.vital_aggs`
as
with icu_vital_data
as
(
select
o.icustay_id
,DATETIME_TRUNC(i.intime, HOUR) as icu_intime -- round it to the nearest hour
,o.charttime - DATETIME_TRUNC(i.intime, HOUR) as diff_chart_intime -- difference between charttime and icu admitted time
,o.vital_name
,o.outlier_handled_vital_reading
from
`mimic_iii_staging.vital_outlier` o
left join `physionet-data.mimiciii_clinical.icustays` i
on o.icustay_id = i.ICUSTAY_ID
)
select
icustay_id
,icu_intime
,EXTRACT(day from diff_chart_intime) * 24 + EXTRACT(HOUR from diff_chart_intime) + case when EXTRACT(MINUTE from diff_chart_intime) >=1 or  EXTRACT(SECOND from diff_chart_intime) >=1 then 1 else 0 end as hour_from_intime -- number of hours from icu admitted time
,replace(lower(vital_name),' ','_') as feature_name
,avg(outlier_handled_vital_reading) as feature_mean_value
from icu_vital_data
group by icustay_id, icu_intime, hour_from_intime, feature_name;

После агрегирования нам теперь нужно повернуть данные, чтобы каждый жизненный показатель стал столбцом, а строка — экземпляром чтения в определенный час для пребывания в отделении интенсивной терапии. Это создаст данные для обучения алгоритмов машинного обучения.

Мы можем повернуть данные, используя функцию PIVOT в большом запросе Google. Для использования сводки мы сначала создаем строку метки, содержащую все основные имена, которые мы хотим преобразовать в столбцы. Затем, используя строку меток, мы используем сводную точку для создания столбца для каждого жизненно важного показателя. Результат этого процесса хранится в таблице vital_aggs_pivot и показан на рисунке 12 ниже.

--pivot aggregate vital readings by hour for each icu stay for mimic-iii data
DECLARE labels STRING;
SET labels = (
SELECT
CONCAT('("', STRING_AGG(DISTINCT feature_name, '", "'), '")'),
from `mimic_iii_staging.vital_aggs`
);
EXECUTE IMMEDIATE format("""
create or replace table `mimic_iii_staging.vital_aggs_pivot`
as
select * from
(
select
icustay_id,
icu_intime,
hour_from_intime,
feature_name,
feature_mean_value
from `mimic_iii_staging.vital_aggs`
)
PIVOT
(
avg(feature_mean_value) as p
for feature_name in %s
)
ORDER BY hour_from_intime ASC
""", labels);

4. Вменение

Последним этапом обработки данных перед разработкой признаков является вменение отсутствующих жизненно важных показателей для пациентов. Для вменения процесс вменения вдохновлен статьей прогнозирование недостаточности кровообращения. Метод вменения очень прост.

Если первое показание отделения интенсивной терапии отсутствует, мы приписываем ему нормальное значение жизненно важного показателя, которое также взято из той же статьи. Затем отсутствующее жизненно важное значение вменяется с использованием последнего доступного значения для этого жизненно важного показателя, а затем, если оно все еще отсутствует, среднее значение для этого жизненно важного показателя для этого пациента используется для условного исчисления отсутствующего значения. Этого можно добиться с помощью SQL, как показано в приведенных ниже запросах, которые выполняются последовательно. SQL для больших запросов предоставляет аналитические функции, которые позволяют вычислять значения по группе строк и возвращать один результат для каждой строки. В приведенном ниже запросе используется last_value() для получения значения конкретного жизненно важного элемента в окне, которое действует как раздел данных. Для этих данных данные разделены по пребыванию в отделении интенсивной терапии и упорядочены по времени записи показаний. Аналогичная аналитическая функция используется для получения среднего жизненного значения для пребывания в отделении интенсивной терапии. Запросы создают окончательную таблицу vital_imputed, которая содержит условное значение для отсутствующих жизненно важных показателей, как показано на рисунке 13c.

--impute if first icu reading is missing for mimic-iii data
create or replace table `mimic_iii_staging.vital_impute_first_reading`as
-- fill first missing reading with normal vital values
select
icustay_id,
icu_intime,
hour_from_intime,
case when  p_diastolic_blood_pressure is null or p_diastolic_blood_pressure = 0 then 75 else p_diastolic_blood_pressure end as p_diastolic_blood_pressure,
case when p_heart_rate is null or p_heart_rate= 0 then 70  else p_heart_rate end as p_heart_rate,
case when p_oxygen_saturation is null or p_oxygen_saturation= 0 then 98 else p_oxygen_saturation end as p_oxygen_saturation,
case when p_temperature is null or p_temperature= 0 then 37 else p_temperature end as p_temperature,
case when p_systolic_blood_pressure is null or p_systolic_blood_pressure= 0 then 125 else p_systolic_blood_pressure end as p_systolic_blood_pressure,
case when p_respiratory_rate is null or p_respiratory_rate= 0 then  12 else p_respiratory_rate end as p_respiratory_rate,
case when p_glascow_coma_scale_total is null or p_glascow_coma_scale_total= 0 then  15 else p_glascow_coma_scale_total end as p_glascow_coma_scale_total
from
mimic_iii_staging.vital_aggs_pivot a
where a.hour_from_intime =
(select min(b.hour_from_intime) from mimic_iii_staging.vital_aggs_pivot b
where a.icustay_id = b.icustay_id)
union all
-- other records
select
icustay_id,
icu_intime,
hour_from_intime,
p_diastolic_blood_pressure,
p_heart_rate,
p_oxygen_saturation,
p_temperature,
p_systolic_blood_pressure,
p_respiratory_rate,
p_glascow_coma_scale_total
from
mimic_iii_staging.vital_aggs_pivot a
where a.hour_from_intime not in
(select min(b.hour_from_intime) from mimic_iii_staging.vital_aggs_pivot b
where a.icustay_id = b.icustay_id);
--impute and fill reading if the last hour has a reading for mimic-iii data
create or replace table `mimic_iii_staging.vital_impute_last_reading` as
select
icustay_id,
icu_intime,
hour_from_intime,
case when p_diastolic_blood_pressure is null or p_diastolic_blood_pressure = 0 then
LAST_VALUE(p_diastolic_blood_pressure IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_diastolic_blood_pressure end as i_diastolic_blood_pressure,
case when p_heart_rate is null or p_heart_rate = 0 then
LAST_VALUE(p_heart_rate IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_heart_rate end as i_heart_rate,
case when p_oxygen_saturation is null or p_oxygen_saturation = 0 then 
LAST_VALUE(p_oxygen_saturation IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_oxygen_saturation end as i_oxygen_saturation,
case when p_systolic_blood_pressure is null or p_systolic_blood_pressure = 0  then
LAST_VALUE(p_systolic_blood_pressure IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_systolic_blood_pressure end as i_systolic_blood_pressure,
case when p_respiratory_rate is null or p_respiratory_rate = 0  then
LAST_VALUE(p_respiratory_rate IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_respiratory_rate end as i_respiratory_rate,
case when p_temperature is null or p_temperature = 0 then
LAST_VALUE(p_temperature IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_temperature end as i_temperature,
case when p_glascow_coma_scale_total is null or p_glascow_coma_scale_total = 0 then
LAST_VALUE(p_glascow_coma_scale_total IGNORE NULLS)
over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
else p_glascow_coma_scale_total end as i_gcs
FROM `mimic_iii_staging.vital_impute_first_reading`;
--impute using mean of the vital for each icu stay for mimic-iii data
create or replace table `mimic_iii_staging.vital_imputed` as
select
icustay_id,
icu_intime,
hour_from_intime,
case when i_diastolic_blood_pressure is null or i_diastolic_blood_pressure = 0 then
avg(i_diastolic_blood_pressure) over (partition by icustay_id)
else i_diastolic_blood_pressure end as i_diastolic_blood_pressure,
case when i_heart_rate is null or i_heart_rate = 0 
then
avg(i_heart_rate) over (partition by icustay_id)
else i_heart_rate end as i_heart_rate,
case when i_oxygen_saturation is null or i_oxygen_saturation = 0 then 
avg(i_oxygen_saturation) over (partition by icustay_id)
else i_oxygen_saturation end as i_oxygen_saturation,
case when i_systolic_blood_pressure is null or i_systolic_blood_pressure = 0  
then 
avg(i_systolic_blood_pressure) over (partition by icustay_id)
else i_systolic_blood_pressure end as i_systolic_blood_pressure,
case when i_respiratory_rate is null or i_respiratory_rate = 0  then
avg(i_respiratory_rate)
over (partition by icustay_id)
else i_respiratory_rate end as i_respiratory_rate,
case when i_temperature is null or i_temperature = 0 then avg(i_temperature) over (partition by icustay_id )
else i_temperature end as i_temperature,
case when i_gcs is null or i_gcs = 0 
then
avg(i_gcs) over (partition by icustay_id )
else i_gcs end as i_gcs
FROM `mimic_iii_staging.vital_impute_last_reading`;

5. Разработка функций

Для моделей глубокого обучения, таких как рекуррентные нейронные сети (RNN), этот шаг не требуется, поскольку модели способны находить взаимосвязи между данными с разными временными шагами. Для моделей машинного обучения, таких как деревья решений, логистическая регрессия и т. д., полезно создавать функции временных рядов, такие как минимум, максимум, среднее значение для каждого жизненно важного показателя для разных окон временных рядов в 4, 6, 8 часов.

Для этого мы используем оконные функции SQL. Пример функции временного ряда для диастолического артериального давления показан в запросе ниже, а последнее показание пациента для пребывания в отделении интенсивной терапии отфильтровано. Этот запрос может быть расширен для других 6 жизненно важных функций. Этот запрос выведет одну строку для каждого пребывания в отделении интенсивной терапии, как показано на рисунке 14.

-- time-series features for diastolic blood pressure vital using window functions
with agg_time_series_features
as
(
select
icustay_id,
icu_intime,
hour_from_intime,
i_diastolic_blood_pressure,
max(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) max_4_hr_diastolic_bp,
max(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) max_6_hr_diastolic_bp,
max(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 8 PRECEDING AND CURRENT ROW) max_8_hr_diastolic_bp,
min(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) min_4_hr_diastolic_bp,
min(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) min_6_hr_diastolic_bp,
min(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 8 PRECEDING AND CURRENT ROW) min_8_hr_diastolic_bp,
avg(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) avg_4_hr_diastolic_bp,
avg(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) avg_6_hr_diastolic_bp,
avg(i_diastolic_blood_pressure) over (partition by icustay_id order by hour_from_intime ASC ROWS BETWEEN 8 PRECEDING AND CURRENT ROW) avg_8_hr_diastolic_bp,
rank()  over (partition by icustay_id order by hour_from_intime desc
) as row_number_reverse
from `mimic_iii_staging.vital_imputed` a
)
select * from agg_time_series_features
where row_number_reverse = 1;

Все вышеперечисленные запросы могут быть расширены, чтобы включать лабораторные значения, такие как натрий, калий и т. д. для пациента, и передавать их в модели машинного обучения в качестве признаков. Вышеупомянутые запросы также можно автоматизировать из скриптов Python с помощью big query api для Python.

После этапа разработки функций данные готовы к использованию для обучения моделей машинного обучения.

Спасибо Omdena за предоставленную возможность и огромное спасибо Sijuade Oguntayo за его поддержку и вдохновение на протяжении всего проекта.

Эта статья впервые появилась в блоге Omdena