PyTorch深度學習框架60天進階學習計劃-第57天:因果推理模型(一)

第57天:因果推理模型(一)- 揭開因果關系的神秘面紗

🎯 學習目標概覽

今天我們要踏入一個既古老又前沿的領域——因果推理!如果說傳統的機器學習是在找"相關性",那因果推理就是在挖掘"因果性"。想象一下,你不僅要知道"下雨時人們會帶傘",更要理解"是因為要下雨所以人們帶傘,還是因為人們帶傘所以下雨"。聽起來有點繞?別擔心,我會用最通俗易懂的方式帶你進入這個fascinating的世界!


第一部分:因果推理的理論基礎與反事實推理框架

🧠 1. 因果推理:從相關到因果的華麗轉身

在開始我們的因果推理之旅之前,讓我先給你講個小故事。假設你是一個電商平臺的數據科學家,發現了一個有趣的現象:購買紅色商品的用戶轉化率比購買藍色商品的用戶高30%。傳統的機器學習會告訴你"紅色和高轉化率相關",但因果推理會問:“是紅色導致了高轉化率,還是喜歡紅色的用戶本身就更容易轉化?”

這就是**相關性(Correlation)因果性(Causation)**的根本區別!

1.1 因果推理的核心概念

讓我們用一個經典的框架來理解因果推理的三個層次:

層次名稱問題類型典型問題所需信息PyTorch應用場景
第一層關聯/觀測看到了什么?癥狀X和疾病Y的相關性是多少?觀測數據P(Y|X)傳統預測模型、分類器
第二層介入/干預如果我們這樣做會怎樣?如果給病人藥物X,康復率會提高多少?實驗數據P(Y|do(X))A/B測試分析、策略優化
第三層反事實如果當時不這樣做會怎樣?如果病人沒有服用藥物X,他還會康復嗎?因果模型P(Y_x|X’,Y’)個性化推薦、決策解釋

關鍵區別說明:

  • P(Y|X):在觀測到X的條件下Y的概率(被動觀測)
  • P(Y|do(X)):主動設置X后Y的概率(主動干預)
  • P(Y_x|X’,Y’):在觀測到X’和Y’的情況下,如果X被設置為x時Y的概率(反事實推理)
1.2 反事實推理:時光機器般的思維實驗

反事實推理可以說是因果推理的"終極形態"。它不僅要求我們理解"如果做X會發生Y",還要能回答"如果當時沒做X,現在會是什么樣?"

想象你是一個推薦系統的工程師,用戶小明點擊了你推薦的電影A并給了好評。反事實推理會問:“如果我當時推薦的是電影B,小明還會給好評嗎?” 這種思維方式能幫我們更好地理解推薦策略的真實效果。

🔍 2. 介入分布 vs 觀測分布:數據背后的兩個世界

這是因果推理中最容易讓人困惑,但也是最重要的概念之一。讓我用一個生動的例子來解釋:

2.1 觀測分布:被動的旁觀者

觀測分布 P(Y|X) 就像是一個被動的攝像頭,只能記錄發生的事情。比如:

  • 觀測到:下雨天80%的人會帶雞
  • 數學表達:P(帶傘=是|下雨=是) = 0.8

但這個分布包含了所有的"混淆因素":

  • 天氣預報的影響
  • 個人習慣的差異
  • 季節性因素
  • 地域文化等等
2.2 介入分布:主動的實驗者

介入分布 P(Y|do(X)) 就像是一個主動的實驗者,能夠人為地設置某個變量的值。比如:

  • 實驗:強制讓一部分人在晴天也帶傘,觀察他們的行為變化
  • 數學表達:P(心情=好|do(帶傘=是)) = ?

介入分布"切斷"了X的所有上游因素,只關注X對Y的直接影響。### 🎯 3. 因果圖:讓因果關系可視化

因果圖(Causal Graph)是理解復雜因果關系的神器!它就像是一張"關系地圖",能清晰地顯示變量之間的因果流向。

觀測分布 vs 介入分布:深度對比

核心差異表

維度觀測分布 P(Y|X)介入分布 P(Y|do(X))
定義在觀測到X條件下Y的概率人為設置X后Y的概率
數據來源自然觀測數據實驗/隨機化數據
混淆因素包含所有混淆消除了X的混淆
因果解釋不能確定因果關系可以確定因果關系
計算復雜度簡單統計需要因果模型

經典案例:Simpson悖論

考慮一個醫院的治療效果研究:

觀測數據顯示:
  • 治療A總體成功率:78% (78/100)
  • 治療B總體成功率:83% (83/100)
  • 結論:治療B更好
按病情嚴重程度分層后:

輕癥患者:

  • 治療A成功率:93% (93/100)
  • 治療B成功率:87% (87/100)

重癥患者:

  • 治療A成功率:73% (73/100)
  • 治療B成功率:69% (69/100)

真實結論:治療A在每個分層中都更好!

為什么會出現這種悖論?

因為病情嚴重程度是一個混淆變量:

  • 重癥患者更多選擇治療A(最后的希望)
  • 輕癥患者更多選擇治療B(保守治療)

這就是觀測分布的陷阱!

3.1 因果圖的基本元素

在這里插入圖片描述

3.2 因果圖中的關鍵路徑

在上面的因果圖中,我們可以識別出幾種重要的路徑類型:

  1. 直接因果路徑:X → Y(工作技能直接影響收入)
  2. 混淆路徑:X ← Z1 → Y 和 X ← Z2 → Y(教育水平和家庭背景同時影響技能和收入)
  3. 后門路徑:需要被"阻斷"的非因果路徑

🔧 4. PyTorch實現:從理論到實踐

現在讓我們用PyTorch來實現一個簡單而實用的因果推理模型!我們將構建一個能夠區分觀測分布和介入分布的框架。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')# 設置隨機種子確保結果可重復
torch.manual_seed(42)
np.random.seed(42)class CausalDataGenerator:"""因果數據生成器:模擬具有已知因果結構的數據結構化因果模型:Z (混淆變量) -> X (處理變量)Z (混淆變量) -> Y (結果變量)  X (處理變量) -> Y (結果變量)"""def __init__(self, n_samples=1000, causal_effect=2.0, confounding_strength=1.5):self.n_samples = n_samplesself.causal_effect = causal_effect  # X對Y的真實因果效應self.confounding_strength = confounding_strength  # 混淆變量的影響強度def generate_data(self):"""生成具有已知因果結構的數據"""# 1. 生成混淆變量Z(比如:社會經濟地位)Z = np.random.normal(0, 1, self.n_samples)# 2. 生成處理變量X(比如:是否接受培訓)# X受到Z的影響(有錢人更容易接受培訓)prob_treatment = torch.sigmoid(torch.tensor(0.5 + self.confounding_strength * Z)).numpy()X = np.random.binomial(1, prob_treatment, self.n_samples)# 3. 生成結果變量Y(比如:收入水平)# Y同時受到Z和X的影響noise = np.random.normal(0, 0.5, self.n_samples)Y = (self.confounding_strength * Z +          # 混淆變量的影響self.causal_effect * X +                 # 真實的因果效應noise)                                   # 隨機噪聲# 創建數據框data = pd.DataFrame({'Z': Z,           # 混淆變量'X': X,           # 處理變量'Y': Y,           # 結果變量'prob_treatment': prob_treatment  # 處理概率(用于分析)})return datadef calculate_true_effects(self):"""計算真實的因果效應(已知答案)"""return {'ATE': self.causal_effect,  # 平均處理效應'observational_bias': self.confounding_strength**2 / 2  # 觀測偏差的近似值}class ObservationalModel(nn.Module):"""觀測模型:直接從X預測Y,不考慮混淆變量這個模型會高估因果效應!"""def __init__(self, input_dim=1):super(ObservationalModel, self).__init__()self.linear = nn.Linear(input_dim, 1)def forward(self, x):return self.linear(x)class AdjustedModel(nn.Module):"""調整模型:同時考慮X和Z,試圖消除混淆偏差這個模型應該能給出更準確的因果效應估計"""def __init__(self, input_dim=2):super(AdjustedModel, self).__init__()self.layers = nn.Sequential(nn.Linear(input_dim, 16),nn.ReLU(),nn.Linear(16, 8),nn.ReLU(), nn.Linear(8, 1))def forward(self, x):return self.layers(x)class CausalInferenceFramework:"""因果推理框架:對比觀測估計和調整估計"""def __init__(self):self.observational_model = ObservationalModel()self.adjusted_model = AdjustedModel()# 優化器self.obs_optimizer = optim.Adam(self.observational_model.parameters(), lr=0.01)self.adj_optimizer = optim.Adam(self.adjusted_model.parameters(), lr=0.01)# 損失函數self.criterion = nn.MSELoss()def train_models(self, data, epochs=500):"""訓練兩個模型"""# 準備數據X = torch.tensor(data['X'].values.reshape(-1, 1), dtype=torch.float32)Z = torch.tensor(data['Z'].values.reshape(-1, 1), dtype=torch.float32)XZ = torch.cat([X, Z], dim=1)  # X和Z的組合Y = torch.tensor(data['Y'].values.reshape(-1, 1), dtype=torch.float32)# 訓練歷史obs_losses = []adj_losses = []for epoch in range(epochs):# 訓練觀測模型(只用X)self.obs_optimizer.zero_grad()obs_pred = self.observational_model(X)obs_loss = self.criterion(obs_pred, Y)obs_loss.backward()self.obs_optimizer.step()obs_losses.append(obs_loss.item())# 訓練調整模型(用X和Z)self.adj_optimizer.zero_grad()adj_pred = self.adjusted_model(XZ)adj_loss = self.criterion(adj_pred, Y)adj_loss.backward()self.adj_optimizer.step()adj_losses.append(adj_loss.item())if epoch % 100 == 0:print(f'Epoch {epoch}: Obs Loss = {obs_loss:.4f}, Adj Loss = {adj_loss:.4f}')return obs_losses, adj_lossesdef estimate_causal_effects(self, data):"""估計因果效應"""# 準備數據X0 = torch.zeros(len(data), 1)  # 不接受處理X1 = torch.ones(len(data), 1)   # 接受處理Z = torch.tensor(data['Z'].values.reshape(-1, 1), dtype=torch.float32)# 觀測模型的估計(有偏差)with torch.no_grad():obs_y0 = self.observational_model(X0)obs_y1 = self.observational_model(X1)obs_ate = (obs_y1 - obs_y0).mean().item()# 調整模型的估計(去除偏差)with torch.no_grad():X0Z = torch.cat([X0, Z], dim=1)X1Z = torch.cat([X1, Z], dim=1)adj_y0 = self.adjusted_model(X0Z)adj_y1 = self.adjusted_model(X1Z)adj_ate = (adj_y1 - adj_y0).mean().item()return obs_ate, adj_atedef analyze_confounding_bias(self, data):"""分析混淆偏差"""# 觀測分布中的關聯treated_group = data[data['X'] == 1]['Y'].mean()control_group = data[data['X'] == 0]['Y'].mean()naive_estimate = treated_group - control_groupreturn naive_estimatedef run_causal_analysis():"""運行完整的因果分析流程"""print("=" * 60)print("🚀 PyTorch因果推理實驗開始!")print("=" * 60)# 1. 生成數據print("\n📊 步驟1:生成具有已知因果結構的數據...")generator = CausalDataGenerator(n_samples=2000, causal_effect=2.0, confounding_strength=1.5)data = generator.generate_data()true_effects = generator.calculate_true_effects()print(f"? 生成了 {len(data)} 個樣本")print(f"📈 數據統計:")print(data.describe())# 2. 訓練模型print("\n🧠 步驟2:訓練觀測模型和調整模型...")framework = CausalInferenceFramework()obs_losses, adj_losses = framework.train_models(data, epochs=500)# 3. 估計因果效應print("\n🔍 步驟3:估計因果效應...")obs_ate, adj_ate = framework.estimate_causal_effects(data)naive_estimate = framework.analyze_confounding_bias(data)# 4. 結果對比print("\n📊 因果效應估計結果對比:")print("-" * 50)print(f"真實因果效應(ATE):        {true_effects['ATE']:.3f}")print(f"樸素估計(觀測差異):      {naive_estimate:.3f}")print(f"觀測模型估計:             {obs_ate:.3f}")print(f"調整模型估計:             {adj_ate:.3f}")print("-" * 50)print(f"樸素估計偏差:             {abs(naive_estimate - true_effects['ATE']):.3f}")print(f"觀測模型偏差:             {abs(obs_ate - true_effects['ATE']):.3f}")print(f"調整模型偏差:             {abs(adj_ate - true_effects['ATE']):.3f}")# 5. 可視化結果print("\n📈 步驟4:可視化訓練過程...")plt.figure(figsize=(15, 5))# 訓練損失plt.subplot(1, 3, 1)plt.plot(obs_losses, label='觀測模型', alpha=0.7)plt.plot(adj_losses, label='調整模型', alpha=0.7)plt.xlabel('訓練輪次')plt.ylabel('損失值')plt.title('模型訓練過程')plt.legend()plt.grid(True, alpha=0.3)# 因果效應對比plt.subplot(1, 3, 2)methods = ['真實值', '樸素估計', '觀測模型', '調整模型']estimates = [true_effects['ATE'], naive_estimate, obs_ate, adj_ate]colors = ['green', 'red', 'orange', 'blue']bars = plt.bar(methods, estimates, color=colors, alpha=0.7)plt.ylabel('因果效應估計')plt.title('不同方法的因果效應估計')plt.axhline(y=true_effects['ATE'], color='green', linestyle='--', alpha=0.8, label='真實值')plt.xticks(rotation=45)plt.grid(True, alpha=0.3)# 數據分布plt.subplot(1, 3, 3)treated = data[data['X'] == 1]['Y']control = data[data['X'] == 0]['Y']plt.hist(control, alpha=0.6, label='對照組 (X=0)', bins=30, density=True)plt.hist(treated, alpha=0.6, label='處理組 (X=1)', bins=30, density=True)plt.xlabel('結果變量 Y')plt.ylabel('密度')plt.title('處理組vs對照組分布')plt.legend()plt.grid(True, alpha=0.3)plt.tight_layout()plt.show()return data, framework, true_effects# 運行實驗
if __name__ == "__main__":data, framework, true_effects = run_causal_analysis()print("\n🎉 實驗完成!我們成功展示了觀測分布和介入分布的差異!")

🎪 5. 混淆變量:因果推理的"隱形殺手"

混淆變量就像是因果推理中的"隱形殺手"——它們悄悄地影響著我們的結論,讓我們誤以為找到了因果關系,實際上只是發現了虛假的相關性。

5.1 混淆變量的識別與處理

在我們的PyTorch代碼中,變量Z就是一個經典的混淆變量。它同時影響了處理變量X(是否接受培訓)和結果變量Y(收入水平)。這創造了一個"后門路徑":X ← Z → Y,使得X和Y之間產生了非因果的關聯。

混淆變量處理方法詳細對比

方法分類表

方法類別具體方法適用場景優勢劣勢PyTorch實現難度
觀測數據方法后門調整已知所有混淆變量理論基礎扎實需要強假設??
前門調整存在中介變量不需要觀測所有混淆變量需要滿足前門準則???
工具變量存在合適的工具變量可處理未觀測混淆工具變量難找???
實驗方法隨機對照試驗可進行隨機化金標準成本高、倫理限制?
自然實驗存在外生變異接近隨機化機會稀少??
機器學習方法雙重機器學習高維數據處理復雜非線性關系理論要求高????
因果森林異質性處理效應個性化效應估計計算復雜?????

混淆偏差的數學表達

假設真實的因果效應為 τ,觀測到的關聯為 β,那么:

β = τ + 偏差其中偏差 = Cov(X,U) × Effect(U,Y) / Var(X)
  • X: 處理變量
  • Y: 結果變量
  • U: 未觀測混淆變量
  • τ: 真實因果效應
  • β: 觀測關聯

我們的PyTorch實驗中的偏差分析

在代碼中,我們設置了:

  • 真實因果效應:2.0
  • 混淆強度:1.5
  • 理論偏差:≈ 1.52 / 2 = 1.125

這解釋了為什么樸素估計會系統性地高估因果效應!

🔬 6. 因果發現算法:從數據中挖掘因果結構

因果發現算法就像是一個"偵探",它試圖從觀測數據中推斷出變量之間的因果關系結構。這是因果推理中最具挑戰性的任務之一!

6.1 因果發現的基本思路

想象你是一個數據偵探,面前有一堆變量:X?, X?, X?, …, X?。你的任務是回答:

  • 哪些變量之間存在直接的因果關系?
  • 因果關系的方向是什么?
  • 是否存在潛在的混淆變量?
6.2 主流因果發現算法分類

基于約束的方法(Constraint-Based)

  • PC算法:通過條件獨立性測試來識別因果結構
  • FCI算法:能處理潛在混淆變量的情況

基于分數的方法(Score-Based)

  • GES算法:通過最大化某個分數函數來搜索最優因果圖
  • LINGAM:假設線性非高斯噪聲模型

基于函數因果模型的方法

  • ANM(Additive Noise Models):假設因果關系為加性噪聲模型
  • PNL(Post-Nonlinear Models):允許更復雜的函數關系
import torch
import torch.nn as nn
import numpy as np
import pandas as pd
from scipy import stats
from itertools import combinations, permutations
import matplotlib.pyplot as plt
import seaborn as snsclass SimpleCausalDiscovery:"""簡化版因果發現算法基于條件獨立性測試和非線性回歸的混合方法"""def __init__(self, significance_level=0.05):self.significance_level = significance_levelself.adjacency_matrix = Noneself.causal_strengths = Nonedef conditional_independence_test(self, X, Y, Z=None, method='partial_correlation'):"""條件獨立性測試:檢驗X和Y在給定Z的條件下是否獨立Args:X, Y: 要測試的變量Z: 條件變量(可選)method: 測試方法Returns:p_value: p值is_independent: 是否獨立"""if Z is None:# 無條件獨立性測試if method == 'correlation':corr, p_value = stats.pearsonr(X, Y)is_independent = p_value > self.significance_levelelse:# 使用互信息p_value = self._mutual_information_test(X, Y)is_independent = p_value > self.significance_levelelse:# 條件獨立性測試p_value = self._partial_correlation_test(X, Y, Z)is_independent = p_value > self.significance_levelreturn p_value, is_independentdef _partial_correlation_test(self, X, Y, Z):"""偏相關測試"""try:# 創建數據矩陣if Z.ndim == 1:Z = Z.reshape(-1, 1)data = np.column_stack([X, Y, Z])# 計算相關矩陣corr_matrix = np.corrcoef(data.T)if corr_matrix.shape[0] < 3:return 1.0  # 如果維度不夠,返回高p值# 計算偏相關系數# partial_corr(X,Y|Z) = (corr(X,Y) - corr(X,Z)*corr(Y,Z)) / sqrt((1-corr(X,Z)^2)*(1-corr(Y,Z)^2))r_xy = corr_matrix[0, 1]r_xz = corr_matrix[0, 2:].mean()  # 簡化處理:取平均r_yz = corr_matrix[1, 2:].mean()denom = np.sqrt((1 - r_xz**2) * (1 - r_yz**2))if abs(denom) < 1e-8:return 1.0partial_corr = (r_xy - r_xz * r_yz) / denom# 計算t統計量和p值n = len(X)t_stat = partial_corr * np.sqrt((n - 3) / (1 - partial_corr**2))p_value = 2 * (1 - stats.t.cdf(abs(t_stat), n - 3))return p_valueexcept:return 1.0  # 出錯時返回高p值def _mutual_information_test(self, X, Y):"""互信息測試(簡化版)"""try:# 離散化變量X_discrete = pd.cut(X, bins=10, labels=False)Y_discrete = pd.cut(Y, bins=10, labels=False)# 計算互信息mi = self._calculate_mutual_information(X_discrete, Y_discrete)# 簡化的p值計算(實際應該用更嚴格的統計測試)# 這里我們用一個啟發式方法p_value = np.exp(-mi * len(X) / 100)  # 簡化公式return min(p_value, 1.0)except:return 1.0def _calculate_mutual_information(self, X, Y):"""計算互信息"""try:# 計算聯合分布和邊際分布xy_counts = pd.crosstab(X, Y)x_counts = pd.Series(X).value_counts()y_counts = pd.Series(Y).value_counts()mi = 0n = len(X)for x in xy_counts.index:for y in xy_counts.columns:if xy_counts.loc[x, y] > 0:p_xy = xy_counts.loc[x, y] / np_x = x_counts[x] / np_y = y_counts[y] / nmi += p_xy * np.log(p_xy / (p_x * p_y))return max(mi, 0)except:return 0def discover_causal_structure(self, data, variable_names=None):"""發現因果結構Args:data: numpy數組或DataFramevariable_names: 變量名列表Returns:adjacency_matrix: 鄰接矩陣causal_strengths: 因果強度矩陣"""if isinstance(data, pd.DataFrame):variable_names = data.columns.tolist()data = data.valueselif variable_names is None:variable_names = [f'X{i}' for i in range(data.shape[1])]n_vars = data.shape[1]self.variable_names = variable_names# 初始化矩陣self.adjacency_matrix = np.zeros((n_vars, n_vars))self.causal_strengths = np.zeros((n_vars, n_vars))print(f"🔍 開始因果發現,分析 {n_vars} 個變量...")# 第一步:識別所有可能的邊possible_edges = []for i in range(n_vars):for j in range(n_vars):if i != j:# 測試i和j之間是否有直接關系X_i = data[:, i]X_j = data[:, j]# 收集其他所有變量作為潛在的條件變量other_vars = [k for k in range(n_vars) if k != i and k != j]if len(other_vars) > 0:# 測試條件獨立性(使用所有其他變量)Z = data[:, other_vars]p_value, is_independent = self.conditional_independence_test(X_i, X_j, Z)else:# 無條件獨立性測試p_value, is_independent = self.conditional_independence_test(X_i, X_j)if not is_independent:possible_edges.append((i, j, p_value))print(f"📊 發現 {len(possible_edges)} 個可能的因果邊")# 第二步:確定邊的方向for i, j, p_value in possible_edges:# 使用非線性回歸來估計因果方向strength_i_to_j = self._estimate_causal_strength(data[:, i], data[:, j])strength_j_to_i = self._estimate_causal_strength(data[:, j], data[:, i])# 選擇更強的方向if strength_i_to_j > strength_j_to_i:self.adjacency_matrix[i, j] = 1self.causal_strengths[i, j] = strength_i_to_jprint(f"? 發現因果關系: {variable_names[i]} -> {variable_names[j]} (強度: {strength_i_to_j:.3f})")else:self.adjacency_matrix[j, i] = 1self.causal_strengths[j, i] = strength_j_to_iprint(f"? 發現因果關系: {variable_names[j]} -> {variable_names[i]} (強度: {strength_j_to_i:.3f})")return self.adjacency_matrix, self.causal_strengthsdef _estimate_causal_strength(self, cause, effect):"""估計因果強度使用非線性回歸的R2作為強度指標"""try:# 簡單的非線性特征X_features = np.column_stack([cause,cause**2,np.sin(cause),np.cos(cause)])# 使用PyTorch進行非線性回歸X_tensor = torch.tensor(X_features, dtype=torch.float32)y_tensor = torch.tensor(effect, dtype=torch.float32).reshape(-1, 1)# 簡單的神經網絡model = nn.Sequential(nn.Linear(4, 8),nn.ReLU(),nn.Linear(8, 1))optimizer = optim.Adam(model.parameters(), lr=0.01)criterion = nn.MSELoss()# 快速訓練for _ in range(100):optimizer.zero_grad()pred = model(X_tensor)loss = criterion(pred, y_tensor)loss.backward()optimizer.step()# 計算R2with torch.no_grad():pred = model(X_tensor)ss_res = torch.sum((y_tensor - pred) ** 2)ss_tot = torch.sum((y_tensor - torch.mean(y_tensor)) ** 2)r_squared = 1 - ss_res / ss_totreturn max(r_squared.item(), 0)except:return 0def visualize_causal_graph(self):"""可視化因果圖"""if self.adjacency_matrix is None:print("? 請先運行因果發現算法!")returnplt.figure(figsize=(12, 8))# 創建子圖fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))# 鄰接矩陣熱圖sns.heatmap(self.adjacency_matrix, annot=True, xticklabels=self.variable_names,yticklabels=self.variable_names,cmap='Reds',ax=ax1)ax1.set_title('因果鄰接矩陣\n(行->列表示因果方向)')# 因果強度熱圖sns.heatmap(self.causal_strengths,annot=True,fmt='.3f',xticklabels=self.variable_names,yticklabels=self.variable_names,cmap='Blues',ax=ax2)ax2.set_title('因果強度矩陣\n(數值表示因果強度)')plt.tight_layout()plt.show()# 測試因果發現算法
def test_causal_discovery():"""測試因果發現算法"""print("🚀 測試因果發現算法")print("=" * 50)# 生成測試數據(已知因果結構)np.random.seed(42)n_samples = 1000# 真實因果結構: Z -> X -> Y, Z -> YZ = np.random.normal(0, 1, n_samples)X = 0.8 * Z + np.random.normal(0, 0.5, n_samples)Y = 0.6 * Z + 1.2 * X + np.random.normal(0, 0.3, n_samples)# 添加一個無關變量W = np.random.normal(0, 1, n_samples)data = pd.DataFrame({'Z': Z,'X': X, 'Y': Y,'W': W})print("📊 測試數據生成完成")print("🎯 真實因果結構: Z -> X -> Y, Z -> Y")print(f"📈 數據統計:\n{data.describe()}")# 運行因果發現discovery = SimpleCausalDiscovery(significance_level=0.05)adj_matrix, strengths = discovery.discover_causal_structure(data)# 可視化結果discovery.visualize_causal_graph()return discovery# 運行測試
if __name__ == "__main__":discovery = test_causal_discovery()

📝 總結:

  1. 因果推理的本質:從"相關性"到"因果性"的思維躍遷,理解了觀測、干預、反事實三個層次的遞進關系。

  2. 分布差異的深度理解:掌握了P(Y|X)與P(Y|do(X))的根本區別,明白了為什么Simpson悖論會發生,以及如何通過正確的因果框架來避免錯誤結論。

  3. 混淆變量的識別與處理:學會了如何識別"隱形殺手"般的混淆變量,并掌握了多種處理方法,從簡單的分層調整到復雜的后門調整。

  4. 因果發現的算法思維:了解了如何從純觀測數據中推斷因果結構,掌握了基于條件獨立性測試和非線性回歸的混合方法。

  5. PyTorch實戰能力:通過具體的代碼實現,我們不僅理解了理論,更重要的是學會了如何用PyTorch將這些抽象概念轉化為可執行的程序。


怎么樣今天的內容還滿意嗎?再次感謝朋友們的觀看,關注GZH:凡人的AI工具箱,回復666,送您價值199的AI大禮包。最后,祝您早日實現財務自由,還請給個贊,謝謝!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86851.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86851.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86851.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java反射操作百倍性能優化

歡迎來到啾啾的博客&#x1f431;。 記錄學習點滴。分享工作思考和實用技巧&#xff0c;偶爾也分享一些雜談&#x1f4ac;。 有很多很多不足的地方&#xff0c;歡迎評論交流&#xff0c;感謝您的閱讀和評論&#x1f604;。 目錄 引言避免在性能敏感的熱點代碼中使用反射緩存反射…

STM32 _main 里做了什么

Application startup 在大多數嵌入式系統中&#xff0c;進入 main 函數之前需要執行一段初始化序列來設置好系統環境。下圖展示的就是這段初始化序列的默認流程&#xff1a; Figure 1. Default initialization sequence __main is responsible for setting up the memory and…

Java八股文——MySQL「SQL 基礎篇」

NOSQL和SQL的區別&#xff1f; 面試官您好&#xff0c;SQL&#xff08;關系型數據庫&#xff09;和NoSQL&#xff08;非關系型數據庫&#xff09;是當今數據存儲領域的兩大主流陣營。它們之間不是“誰取代誰”的關系&#xff0c;而是兩種完全不同的設計哲學&#xff0c;適用于…

華為OD機考-數字螺旋矩陣(JAVA 2025B卷)

public class RotateMatrix {public static void main(String[] args) {// 順時針螺旋矩陣printMatrixV1();// 逆時針螺旋矩陣//printMatrixV2();}private static void printMatrixV2() {Scanner scan new Scanner(System.in);while(scan.hasNextLine()){String[] line scan.…

【Java工程師面試全攻略】Day7:分布式系統設計面試精要

一、分布式系統概述 分布式系統已成為現代互聯網應用的標配架構&#xff0c;據LinkedIn統計&#xff0c;分布式系統設計能力是高級Java工程師薪資差異的關鍵因素。今天我們將深入解析分布式系統的核心理論和實踐&#xff0c;幫助你掌握面試中的系統設計問題。 二、分布式理論…

Excel處理控件Aspose.Cells教程:在Excel 文件中創建、操作和渲染時間線

您可以使用數據透視表時間軸&#xff0c;而無需調整過濾器來顯示日期——這是一種動態過濾器選項&#xff0c;可讓您輕松按日期/時間進行過濾&#xff0c;并使用滑塊控件放大所需的時間段。Microsoft Excel 允許您通過選擇數據透視表&#xff0c;然后單擊“插入”>“時間軸”…

Python----神經網絡發(神經網絡發展歷程)

年份網絡名稱突出點主要成就論文地址1989LeNet首個現代卷積神經網絡&#xff08;CNN&#xff09;&#xff0c;引入卷積、池化操作手寫數字識別先驅&#xff0c;奠定CNN基礎MNIST Demos on Yann LeCuns website2012AlexNet首次大規模使用深度卷積神經網絡進行圖像識別&#xff1…

mvc與mvp

mvc MVC 架構中&#xff0c;Activity/Fragment&#xff08;作為 View 和 Controller&#xff09;直接持有 Model 或異步任務的引用&#xff0c;當頁面銷毀時&#xff0c;這些長生命周期對象若未正確釋放&#xff0c;會導致 Activity 無法被 GC 回收&#xff0c;形成內存泄漏。…

商業智能中的地圖可視化模板:助力數據高效呈現

引言 在數字化浪潮席卷的當下&#xff0c;數據可視化的重要性愈發凸顯。企業和組織需要從海量的數據中提取有價值的信息&#xff0c;以便做出明智的決策。而可視化地圖組件作為數據可視化的關鍵部分&#xff0c;能夠將數據與地理位置相結合&#xff0c;以直觀、美觀的方式展示…

Opencv 相機標定相關API及原理介紹

Opencv 相機標定相關API及原理介紹 相機標定是計算機視覺中的基礎任務,旨在確定相機的??內參矩陣??、??畸變系數??以及(可選)??外參??(相機相對于世界坐標系的旋轉和平移)。OpenCV提供了完整的相機標定工具鏈,核心函數為cv2.calibrateCamera,其原理基于張正…

深入剖析AI大模型:Prompt 從理論框架到復雜任務的全場景實現

今天我們就Prompt實戰&#xff0c;實現一下復雜場景&#xff0c;通過這些實戰我們就可以更好的理解大模型工作的原理和機制了。我個人覺得Prompt是AI大模型中非常重要的的環節。首先我們還是溫習一下Prompt的框架和基礎原則。然后我們就文本生成、問答任務及復雜任務三個方面分…

Fractal Generative Models論文閱讀筆記與代碼分析

何愷明分型模型這篇文章在二月底上傳到arXiv預出版網站到現在已經過了三個月&#xff0c;當時我也聽說這篇文章時感覺是大有可為&#xff0c;但是幾個月不知道忙啥了&#xff0c;可能錯過很多機會&#xff0c;但是亡羊補牢嘛&#xff0c;而且截至目前&#xff0c;該文章應該也還…

IntelliJ IDEA代碼提示忽略大小寫設置詳解

目錄 前言一、設置步驟1. 打開設置界面2. 進入代碼補全設置3. 配置大小寫敏感選項新版本&#xff08;2023及以上&#xff09;舊版本&#xff08;2022及以下&#xff09; 4. 保存并應用設置 二、效果驗證示例三、注意事項與常見問題1. **適用范圍**2. **版本兼容性**3. **設置未…

Oracle集群OCR磁盤組掉盤問題處理

問題描述 填寫問題的基礎信息。 系統名稱 - IP地址 - 操作系統 HP-UNIX 數據庫 Oracle 11.2.0.4 兩節點RAC 癥狀表現 問題的癥狀表現如下 集群的OCR磁盤組掉了一塊盤(/dev/rdisk/disk52): 查詢集群仲裁盤發現只有兩塊&#xff08;原來是有三塊&#xff09;&#xff…

在WordPress中徹底關閉生成縮略圖的方法

在WordPress中徹底關閉生成縮略圖有多種方法&#xff0c;以下是幾種常見的方法&#xff1a; 方法一&#xff1a;通過修改主題的functions.php文件 登錄WordPress后臺&#xff1a;進入WordPress后臺管理界面。 編輯主題文件&#xff1a; 在左側菜單中找到“外觀”選項&#…

安全-Linux基線核查項點

Linux基線加固/整改 1.限制超級管理員遠程登錄 修改遠程管理程序ssh的配置文件 vi /etc/ssh/sshd_config PermitRootLogin no 重啟sshd服務 systemctl restart sshd 2. 修改默認密碼生存周期 一個好的密碼時間策略如下&#xff1a; vi /etc/login.defs PASS_MAX_DAY 90 最長…

在微信小程序中使用骨架屏

在微信小程序中使用骨架屏可以優化用戶體驗&#xff0c;避免頁面加載時出現白屏現象。以下是詳細的使用方法和注意事項&#xff1a; 使用方法 生成骨架屏代碼&#xff1a; 打開微信開發者工具&#xff0c;進入需要添加骨架屏的頁面。在模擬器面板右下角點擊三個點&#xff0c…

網絡的那些事——初級——OSPF(1)

&#x1f48e;什么是OSPF? OSPF&#xff08;Open Shortest Path First&#xff0c;開放最短路徑優先&#xff09;是一種基于鏈路狀態的內部網關協議&#xff08;IGP&#xff09;&#xff0c;廣泛應用于中大型企業及運營商網絡。其核心設計目標是解決早期協議&#xff08;如RI…

前端導出PDF(適配ios Safari瀏覽器)

目前市面上常用的前端導出PDF庫組合一般為&#xff1a; 1. html2canvas js-pdf 2. html2canvaspdf-lib 3. domtoimagepdf-lib 因本人項目中導出pdf需求為導出30頁及以上的多頁pdf&#xff0c;考慮性能問題&#xff0c;選擇了 html2canvaspdf-lib 及domtoimagepdf-lib兩種方…

physicsnemo開源程序是開源深度學習框架,用于使用最先進的 Physics-ML 方法構建、訓練和微調深度學習模型

?一、軟件介紹 文末提供程序和源碼下載 NVIDIA PhysicsNeMo 是一個開源深度學習框架&#xff0c;用于使用最先進的 SciML 方法構建、訓練、微調和推理物理 AI 模型&#xff0c;以實現 AI4 科學和工程。PhysicsNeMo 提供 python 模塊來構建可擴展和優化的訓練和推理管道&#…