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

Причинный вывод — это формальный метод определения того, в какой степени обработка X вызывает результат y при наличии искажающих факторов C. Линейные модели вида:

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

Нелинейные вмешивающиеся отношения

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

Изменение вероятности поедания креветок с 4 до 5 утра, вероятно, отличается от изменения вероятности поедания креветок с 15 до 16 часов. Точно так же изменение вероятности расстройства желудка с 3 до 4 часов утра, вероятно, не совпадает с изменением вероятности расстройства желудка в часы бодрствования. (Примечание: даже если бы мы моделировали изменение логарифмических шансов, используя логистическую регрессию, а не изменение вероятности, мы все равно не смогли бы предположить линейную зависимость.)

Двойное машинное обучение

Чтобы решить проблемы, возникающие из-за нелинейных взаимосвязей между искажающими факторами, методами лечения и результатами, Черножуков и др. предложить метод, называемый двойным машинным обучением. В этом методе Черножуков и др. рассматривают частично линейную модель, принимающую форму E(y) = aX + f(C)где взаимосвязь между вмешивающимися факторами и результатом f(C) может быть нелинейным. Кроме того, E(X) = m(C) представляет взаимосвязь между вмешивающимися факторами и результатом; m(C) не предполагается линейной функцией.

Чтобы оценить a в этой модели, Черножуков и др. сначала обучили модель машинного обучения прогнозировать результат от вмешивающихся факторов E[y] = g(C), а другую машину модель обучения для прогнозирования лечения от вмешивающихся факторов E[X] = m(C). Остатки от этих моделей рассчитываются:

и линейная модель вида:

используется для оценки причинного параметра. Если этот процесс использования остатков для оценки причинного параметра сбивает вас с толку, в этой записи в блоге есть хорошее объяснение.

Разделение проб

Когда в моделях машинного обучения, используемых для оценки a, используется переобучение, оценки для a также оказываются смещенными. Чтобы преодолеть это, используется разделение выборки (например, реализованное с помощью k-кратной перекрестной проверки). Модели машинного обучения для оценки X и y обучаются с использованием 4/5 выборки, а оставшаяся 1/5 выборки используется для оценки a. Эта процедура повторяется, и оценки a по всем сгибам усредняются для повышения эффективности (уменьшения стандартной ошибки) оценки a.

Моделирование частично линейной причинно-следственной модели

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

transform_data <- function(c, i){
    randnum = runif(1)
    if (round(i/3) == i/3){
        return(cos(c + 1))
    }
    else if (round(i/4) == i/4){
        return(sin(c + 1))
    }
    else if (round(i/2) == i/2){
        return(c^2)
    }
    else {
        return(exp(c)    )        
}
}

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

generate_data <- function (n, n_confounders = 6, effect_size = 2){

    c0 = rnorm(n)
    df = data.frame(c0 = c0) #at least one confounder with a linear effect
    m1 = c0 + rnorm(n)
    m2 = c0 + rnorm(n)

    for (i in 1:(n_confounders - 1)){
        c = rnorm(n) 
        m1 = m1 + transform_data(c, i)
        m2 = m2 + transform_data(c, i + 1)

        df[,paste0("c", as.character(i))] = c
    }

    x = rnorm(n, sd = sd(m1) / 2) + m1 #we want x to be mostly comprised of effects from the confounders
    x = (x - mean(x)) / sd(x) #rescale to be the same as other covariates

    y = x * effect_size + m2 + rnorm(n, sd = sd(m2) /10)
    df$x = x
    df$y = y
    return(df)
}

Наконец, мы определяем функцию, которая получает причинно-следственные оценки, используя 4 различных метода: DoubleML с использованием машины опорных векторов (SVM), DoubleML с использованием XGBoost, простой модели линейной регрессии и модели линейной регрессии, использующей сплайны. Мы будем использовать пакет R DoubleML для проведения наших оценок DoubleML.

get_estimates <- function(n = 500){
    df = generate_data(n)
    df_doubleml = DoubleML::double_ml_data_from_data_frame(df, y_col = c("y"), d_cols = c("x"))
    dml_xgb = DoubleML::DoubleMLPLR$new(df_doubleml, mlr3::lrn("regr.xgboost"), mlr3::lrn("regr.xgboost"))
    dml_xgb$fit()
    dml_xgb_df = data.frame(dml_xgb$confint())
    colnames(dml_xgb_df) <- c("dml_xgb_lower", "dml_xgb_upper")
    dml_xgb_df$dml_xgb_estimate = dml_xgb$all_coef[1,1]
    
    dml_svm = DoubleML::DoubleMLPLR$new(df_doubleml, mlr3::lrn("regr.svm"), mlr3::lrn("regr.svm"))
    dml_svm$fit()
    dml_svm_df = data.frame(dml_svm$confint())
    colnames(dml_svm_df) <- c("dml_svm_lower", "dml_svm_upper")
    dml_svm_df$dml_svm_estimate = dml_svm$all_coef[1,1]
    
    x_var = summary(lm(y ~ ., data = df))$coefficients["x",] 

    linear_df = data.frame((x_var["Estimate"] + c(-1,0, 1) *qnorm(.975) * x_var["Std. Error"]) |> t())
    colnames(linear_df) <- c("linear_lower", "linear_estimate", "linear_upper")
    
    spline_mod = lm(y ~ x +  splines::ns(c0) + splines::ns(c1, df = 3) + splines::ns(c2, df = 3) + splines::ns(c3, df = 3), data = df)

    x_var = summary(spline_mod)$coefficients["x",] 
    spline_df = data.frame((x_var["Estimate"] + c(-1,0, 1) * qnorm(.975) * x_var["Std. Error"]) |> t())
    colnames(spline_df) <- c("spline_lower","spline_estimate", "spline_upper")
    
    output_df = cbind(spline_df, linear_df, dml_xgb_df, dml_svm_df)
    return(c(output_df[1,]))
    
}

Наконец, мы запускаем эту функцию 500 раз и записываем точечные оценки, а также доверительные интервалы для aоценки с помощью различных процедур.

Производительность

Во-первых, давайте посмотрим на вероятности покрытия: долю времени, когда доверительный интервал, оцененный процедурой, включал истинное значение a. Поскольку для этой симуляции мы использовали доверительные интервалы 95 %, хороший оценщик будет иметь охват 95 %. Как видите, DoubleML, использующий SVM в качестве модели машинного обучения, имел почти идеальное покрытие, причем гораздо лучшее, чем любая другая модель.

Теперь давайте посмотрим, были ли точечные оценки для a объективными. Идеальный оценщик восстановит оценки a, которые симметрично сгруппированы вокруг истинной оценки (в данном случае 2). Как мы видим, DoubleML с использованием SVM и здесь показал себя лучше всего.

Боковое примечание: при использовании DoubleML по-прежнему важно вытягивать DAG. Отношение к посредникам как к искажающим факторам в DoubleML вернет необъективные оценки.

Заключение

У меня есть два основных вывода из этой симуляции: во-первых, причинные эффекты могут быть восстановлены даже при наличии искажающих факторов, которые ведут себя нелинейно. Во-вторых, очень важно, какую модель машинного обучения вы используете в алгоритме DoubleML. XGBoost, который, как правило, является хорошей универсальной моделью прогнозирования, показал худшие результаты из всех моделей, которые я рассматривал в этой симуляции.

В будущем я надеюсь провести больше симуляций, чтобы определить, когда какие типы моделей машинного обучения использовать, а также изучить производительность DoubleML в условиях разреженности (когда многие «вмешивающиеся факторы» не оказывают реального влияния на результат) и когда f(C) — более сложная функция с взаимодействиями.