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

Ранее мы упоминали предположение Маркова. Чтобы освежить вашу память, вот глобальное предположение Маркова:

Учитывая, что P является марковским по отношению к G (удовлетворяет локальному марковскому предположению), если X и Y d-разделимы в G при условии Z, то X и Y независимы в P при условии Z. Это можно записать как:

При работе с неизвестным причинным графом у нас нет первой составляющей теоремы, но мы можем вычислить вторую. Следовательно, нам нужно сделать предположение о достоверности:

Это предположение довольно сильное и может не выполняться в некоторых структурных моделях. Давайте рассмотрим пример из Брейди Нила:

В этом случае мы можем найти такие параметры альфа, бета, гамма и дельта, что А не зависит от D. Однако, как вы можете видеть на графике, это не так.

В дополнение к ранее упомянутым предположениям нам также необходимо учитывать причинно-следственную достаточность:

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

Кроме того, мы предполагаем, что граф является ациклическим.

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

Эти три графа марковски эквивалентны. Изучая данные, мы обнаруживаем, что X1 и X3 независимы, если обусловлены X2, в то время как все они попарно зависимы без обусловленности. В подобных ситуациях единственная информация, которую мы можем извлечь, — это так называемый скелет:

Таким образом, наш единственный шанс отличить графы — это когда их класс марковской эквивалентности содержит только один граф, то есть они не марковски эквивалентны.

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

Безнравственность и скелеты служат нашими основными инструментами для обнаружения причин в следующем алгоритме, известном как алгоритм ПК:

Алгоритм ПК:

  1. Построить полный график
  2. Определите скелет
  3. Определите и сориентируйте безнравственность
  4. Ориентировать уточняющие ребра, инцидентные коллайдерам

Рассмотрим следующий график:

Нам известны только значения всех пяти переменных. Давайте сначала построим полный граф:

Следующим шагом является идентификация скелета. Для этого нам нужно исключить из графа устаревшие ребра. Исследуя попарные зависимости с пустым набором условий, мы находим, что A и B независимы. Это позволяет нам исключить связь A-B. После увеличения набора условий для включения одной переменной мы снова смотрим на условные зависимости между различными парами переменных. Мы обнаруживаем, что обусловленные С, А и В становятся зависимыми. Это указывает на то, что A-C-B образует аморальность с коллайдером C. Кроме того, все остальные пары (BE, BD, AD, AE, DE) становятся независимыми при условии, что C, что позволяет нам исключить еще пять связей. Получаем следующий график:

Последним шагом является ориентация ребер D-C и E-C. В данном случае это довольно просто. Поскольку мы определили, что C является коллайдером только в аморальности A-C-B, аморальностей больше нет, и можно однозначно сказать, что ребра D-C и E-C не направлены в сторону узла C. Это позволяет нам вывести причинно-следственный граф.

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

Процесс генерации данных выглядит следующим образом:

np.random.seed(11)

alpha = 0.5
beta = -5
delta = 0.4
gamma = -0.7

Z = np.random.normal(loc=1, size=500)
T = alpha * Z + np.random.normal(loc=2, size=500)
M = beta * T + np.random.normal(size=500)
Y = delta * Z + gamma* M + np.random.normal(size=500)
C = T + Y + np.random.normal(size=500)

df = pd.DataFrame(np.stack((Z, T, M, Y, C), axis=1), 
                  columns=['Z', 'T', 'M', 'Y', 'C'])

Чтобы выполнить обнаружение причин, мы будем использовать библиотеку CausalNex и применим алгоритм ПК, который мы обсуждали ранее. Давайте импортируем необходимые библиотеки и проведем анализ.

import networkx as nx
import matplotlib.pyplot as plt
from causalnex.structure.notears import from_pandas_lasso

# Learning the causal graph using the PC algorithm
sm = from_pandas_lasso(df, beta=0, w_threshold=0.3)

Метод from_pandas_lasso использует модификацию алгоритма ПК. Установив бета равным нулю, он становится стандартным алгоритмом ПК с порогом 0,3 для ссылки. Чем выше порог, тем больше ссылок будет обрезано. Давайте визуализируем окончательный график:

# Converting the StructureModel to a networkx graph
G = nx.DiGraph(sm.edges)

# Visualizing the graph
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True, node_color='lightblue', edge_color='gray', 
    node_size=3000, font_size=18, font_weight='bold')
plt.show()

Как мы видим, это именно наш график! Теперь мы можем оценить причинно-следственный эффект T на Y, используя библиотеку doWhy (в которой используются методы, знакомые тем, кто читал предыдущие посты).

from dowhy import CausalModel

# Convert networkX representation to GLM - compatible with Causal Model
nx.write_gml(G, 'test.gml')

# Create the dowhy Causal Model
model = CausalModel(
    data=df,
    treatment='T',
    outcome='Y',
    graph='test.gml'
)

Теперь doWhy позволяет нам явно показать предположения и методы, а затем оценить эффект:

# Identifying the causal effect
identified_estimand = model.identify_effect()
print(identified_estimand)

Это выводит:

Estimand type: nonparametric-ate

### Estimand : 1
Estimand name: backdoor
Estimand expression:
 d                    
────(Expectation(Y|Z))
d[T]                  
Estimand assumption 1, Unconfoundedness: If U→{T} and U→Y then P(Y|T,Z,U) = P(Y|T,Z)

### Estimand : 2
Estimand name: iv
No such variable(s) found!

### Estimand : 3
Estimand name: frontdoor
Estimand expression:
Expectation(Derivative(Y, [M])*Derivative([M], [T]))
Estimand assumption 1, Full-mediation: M intercepts (blocks) all directed paths from T to Y.
Estimand assumption 2, First-stage-unconfoundedness: If U→{T} and U→{M} then P(M|T,U) = P(M|T)
Estimand assumption 3, Second-stage-unconfoundedness: If U→{M} and U→Y then P(Y|M, T, U) = P(Y|M, T)

Вывод показывает, что к этому графу можно применить как бэкдор, так и фронтдор. Давай попробуем:

# Estimating the causal effect
estimate = model.estimate_effect(identified_estimand, 
                 method_name='backdoor.linear_regression', 
                                 confidence_intervals=True)

print("Causal Estimate:", estimate.value)
print("Confidence Intervals: ", estimate.get_confidence_intervals())

Это обеспечивает:

Causal Estimate: 3.5563634704585154
Confidence Intervals:  [[3.45063871 3.66208824]]

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

DoWhy также предлагает еще один полезный инструмент — возможность проверки результатов на надежность (этап опровержения). Мы будем использовать несколько методов опровержения:

  1. Случайная общая причина. Этот метод добавляет случайный фактор в набор данных и переоценивает причинно-следственный эффект. Если новая оценка похожа на исходную, это указывает на то, что исходная оценка устойчива к присутствию ненаблюдаемого искажающего фактора.
  2. Опровержение лечения плацебо: этот метод заменяет исходную переменную лечения случайно сгенерированной переменной плацебо (не связанной с результатом) и переоценивает причинно-следственный эффект. Если новая оценка близка к нулю, это предполагает, что исходная оценка не является просто результатом ложных корреляций.
  3. Опровержение подмножества данных: этот метод переоценивает причинно-следственный эффект для случайных подмножеств данных. Если новые оценки аналогичны исходным, это указывает на то, что исходная оценка устойчива к вариациям данных.

Давайте рассмотрим результаты:

refutation = model.refute_estimate(identified_estimand, estimate, method_name='random_common_cause')
print(refutation)
Refute: Add a random common cause
Estimated effect:3.5563634704585154
New effect:3.5564561606343172
p value:0.5

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

Аналогичные результаты мы получаем и с другими опровергателями. Это дает нам уверенность в надежности наших результатов.

Теперь давайте углубимся в некоторые теоретические бонусы:

Теорема марковской полноты утверждает:

Если у нас есть полиномиальные распределения или линейные структурные уравнения Гаусса, мы можем идентифицировать граф только до его класса марковской эквивалентности.

Это означает, что не существует метода, который помог бы нам идентифицировать такие структуры, как вилки, цепочки, или отличить X → Y от Y → X. Таким образом, без каких-либо предположений используемые нами результаты должны удовлетворять теореме. Однако, если мы предположим нелинейные структурные уравнения Гаусса и немультиномиальные распределения, что произойдет?

Рассмотрим линейное негауссово структурное уравнение:

где f — линейная функция, а U — негауссовская случайная величина. В этом случае у нас есть теорема, которая гласит:

В линейной негауссовой модели, если истинная структурно-причинная модель (SCM):

тогда не существует SCM в обратном направлении:

которые могут генерировать данные, согласующиеся с P(x, y).

Доказательство довольно простое. Я призываю вас исследовать это в книге Брэди Нила.

Пример негауссова

Давайте рассмотрим простой пример с двумя соединенными узлами A и B (A→B). Из теории мы знаем, что мы можем только определить, соединены они или нет — другими словами, мы можем найти только скелет, а не направление ребер.

np.random.seed(11)

A = 3 + np.random.uniform(-1,1, size=500)
B = A + np.random.standard_t(5, size=500)
df = pd.DataFrame(np.stack((A,B), axis=1), 
                  columns=['A', 'B'])

Давайте визуализируем зависимость:

Транспонировано:

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

Однако, если мы исследуем распределение остатков этих регрессий по ковариате, мы увидим следующее:

Мы можем видеть, что левый (который показывает остатки из причинно-следственной модели) имеет остатки, которые не зависят от ковариаты A. Напротив, правый демонстрирует серьезную гетероскедастичность, и, несмотря на E(остатки|B) = 0, мы не можем рассмотрим невязку и B как независимые.

В заключение, причинное обнаружение — это мощный инструмент в области причинно-следственного вывода, позволяющий нам обнаруживать причинно-следственные связи непосредственно из данных, когда у нас нет доступа к причинно-следственной диаграмме. Используя такие допущения, как Верность, Причинно-следственная достаточность и Ацикличность, мы можем применять алгоритмы, подобные алгоритму ПК, для выявления скелетов и безнравственности, которые в свою очередь, помогают нам сделать вывод о причинно-следственных структурах.

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

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

Оставайтесь со мной в этом путешествии в мир причинно-следственных связей, и мы рассмотрим инструментальные переменные, CATE и многое другое в будущих постах!