当前位置: 首页 > news >正文

因果推断 | 双重机器学习(DML)算法原理和实例应用

文章目录

  • 1 引言
  • 2 DML算法原理
    • 2.1 问题阐述
    • 2.2 DML算法
  • 3 DML代码实现
    • 3.1 策略变量为0/1变量
    • 3.2 策略变量为连续变量
  • 4 总结
  • 5 相关阅读

1 引言

小伙伴们,好久不见呀。

距离上次更新已经过去了一个半月,上次发文章时还信誓旦旦地表达自己后续目标是3周更新一篇文章,然后马上就打脸了。

其实第3周的时候,有想过把当时的一些学习心得总结一下,先发出来。但是宁缺毋滥的理性很快打败了内心的小心机,毕竟骗自己的态度不可取。看清目标与现实间的差异,逐渐认识自身有限的学习能力,本身也是一种收获。

回到文章本身,今天要说的主题是:一种结合机器学习做因果推断任务的算法,学术名叫Double Machine Learning(DML),双重机器学习

围绕DML,本文将首先介绍DML的算法原理;然后使用简单的模拟数据手动实现该算法,并和已有的工具包做对比,以此加深对该算法的理解;在此基础上,针对更实际的案例,尝试求解物理意义更强的因果推断问题。

正文见下。

2 DML算法原理

2.1 问题阐述

先回顾一下潜在因果框架中因果推断问题的定义:样本数据集为: D = { d 1 , d 2 , . . . , d n } D=\{d_1,d_2,...,d_n\} D={d1,d2,...,dn} n n n为样本数量;策略变量为 T ∈ { 0 , 1 } T\in \{0, 1\} T{0,1} T = 0 T=0 T=0表示不施加策略, T = 1 T=1 T=1表示施加策略;协变量 X X X,一般指与策略无关的变量;结果变量 Y Y Y Y 0 i Y_{0i} Y0i表示无策略时第 i i i个样本的结果变量, Y 1 i Y_{1i} Y1i表示有策略时第 i i i个样本的结果变量。目标是:基于数据集 D = { T i , X i , Y i } i n D=\{T_i,X_i,Y_i\}_i^n D={Ti,Xi,Yi}in,估计 T T T Y Y Y之间的因果效应。

在这个定义里面,有个前提假设很容易不满足,那就是 X X X T T T无关。一方面,在寻找 X X X时,很难确认 X X X T T T无关。举个例子,我们想知道冰淇淋的价格与销量间的因果效应,此处 T T T是价格, Y Y Y是销量。 X X X很容易想到有:当时的天气温度、当地的生活水平等等。但当地的生活水平和价格之间大概率是正相关的,比如同一款巧乐兹在北京卖的价格和十八线小城市的价格,大概率是有差别的。

另一方面,为了更全面考虑问题,变量 X X X中会纳入尽可能多的特征,而特征越多,就越难保证其和策略变量 T T T是否相关。

X X X T T T相关后,就会产生混淆变量 W W W,该类变量既影响 Y Y Y,又影响 T T T,如下图所示。

在此情况下,要得到 T T T Y Y Y之间纯净的因果效应就更难了。

2.2 DML算法

为了解决包含混淆变量的因果推断问题,本节介绍一种被称为双重机器学习的算法,英文是:Double Machine Learning (DML)。

该算法考虑如下一种线性模型:
Y = T θ 0 + X β 0 + U , E [ U ( X , T ) ] = 0 Y=T\theta_0+X\beta_0+U, \quad E[U(X,T)]=0 Y=Tθ0+Xβ0+U,E[U(X,T)]=0
T = X γ 0 + V , E [ V ∣ X ] = 0 T=X\gamma_0+V, \quad E[V|X]=0 T=Xγ0+V,E[VX]=0
解释一下上述两个公式:第一个公式表达的是 Y Y Y T T T X X X之间为线性关系,其中 U U U为随机扰动项;第二个公式表达的是 T T T X X X之间也是线性关系,其中 V V V是为随机扰动项。

在该模型中,变量 X X X会同时影响 T T T Y Y Y,即 X X X被看做一个混淆变量,只是限定了变量间为线性关系。

DML的算法方案分为两步:第一步是基于机器学习模型使用协变量 X X X分别拟合 Y Y Y T T T,得到 Y ^ , T ^ \hat Y, \hat T Y^,T^,此时残差分别为 Y − Y ^ Y-\hat Y YY^ T − T ^ T-\hat T TT^

第二步是对残差,用任意机器学习模型(很多是最小二乘法)拟合,得到参数 τ \tau τ,即认为是 T T T Y Y Y之间的真正因果效应值。

( Y − Y ^ ) = τ ⋅ ( T − T ^ ) (Y-\hat Y) = \tau·(T-\hat T) (YY^)=τ(TT^)

DML算法不复杂,不过有几点需要额外说明:

(1) 基于对 T T T Y Y Y残差的拟合,可以得到真正的因果效应值,直观上可以理解为:先剔除 X X X的影响后,再评估 T T T Y Y Y的因果效应,就会比较纯粹;理论上也是有证明的,只不过其推导证明对我来说有些复杂了,感兴趣的同学可以参考原文献:Double/debiased machine learning for treatment and structural parameters。B站上和CSDN上也有关于这篇文章的部分讲解,都可以参考一下。

(2) DML有个基本假设是: T T T Y Y Y之间是线性关系。所以如果 T T T不是0/1变量,而是个连续值,那么得到的因果效应值仅在 T T T附近有效。例如在上文提到的冰淇淋价格和销量的因果推断问题中, T T T是价格, Y Y Y是销量,设定 τ = 2 \tau=2 τ=2,我们可以说价格减少1个单位后销量能增加2个单位,但如果价格减少10个单位,就不能确认销量是否可以增加20个单位。

(3) 原问题中, X X X中有混杂变量 W W W;DML模型中,并没有刻意区分 W W W X X X。而且在实际操作时,由于拟合残差时使用的是机器学习模型,也不必仔细区分每个 X X X是不是混杂变量,直接扔进模型就行。

3 DML代码实现

本节通过两个实例,描述如何将DML应用于求解实际的业务问题。考虑到DML其中一种版本——因果森林DML,在业界很常用,本文也会更多关注因果森林DML的实践应用。

3.1 策略变量为0/1变量

策略变量为0/1变量是标准的因果推断问题,所以从这类问题入手比较适合。

本节的问题实例是个虚拟的合成数据,实现函数是causalml.dataset.synthetic_data,这是causalml自带的数据集,而causalml是Uber开源的因果推断工具包,未来肯定还会经常遇到它。

针对这个问题实例,下面的代码分别使用三种策略实现因果森林DML的技术方案:

(1) 自己编写代码实现。在计算 Y Y Y T T T的残差时,使用sklearn.ensemble.RandomForestRegressor;在拟合残差时,使用sklearn.linear_model.LinearRegression。

(2) 工具包+手动设置机器学习模型。工具包使用econml.dml.DML,然后依次设置计算残差和残差拟合的机器学习模型。

(3) 工具包一键完成。直接调用econml.dml.CausalForestDML。

这里的工具包需要单独描述一下。econml是微软开源的因果推断工具包,没有继续使用causalml,是因为causalml中暂时还不支持DML。在econml中,DML可以理解为一个简单框架,允许用户自行设置每个步骤上的机器学习模型;CausalForestDML可以理解为一个已经集成好的因果森林DML。

import pandas as pd
from causalml.metrics import auuc_score, plot_gain
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from causalml.dataset import synthetic_data
from econml.dml import CausalForestDML, DML# 自编代码实现因果森林DML
def algo_by_self_cf_dml(y, treat, X):# 计算y的残差rf_y = RandomForestRegressor()rf_y.fit(X, y)y_res = y - rf_y.predict(X)# 计算treat的残差rf_t = RandomForestRegressor()rf_t.fit(X, treat)treat_res = treat - rf_t.predict(X)# 计算因果效果lr = LinearRegression(fit_intercept=False).fit(treat_res.reshape(-1, 1), y_res.reshape(-1, 1))print('self_cf_dml: w = {:.2f}'.format(lr.coef_[0, 0]))# econml工具包实现因果森林DML
def algo_by_econml_dml(y, treat, X):# dml + 手动设置dml = DML(model_y=RandomForestRegressor(),model_t=RandomForestRegressor(),model_final=LinearRegression(fit_intercept=False))dml.fit(y, treat, X=X)print('DML: {}'.format(dml.ate(X)))# 因果森林DMLcf_dml = CausalForestDML()cf_dml.fit(y, treat, X=X)print('CausalForestDML: {}'.format(cf_dml.ate(X)))return dml, cf_dml# 计算AUUC和绘制gain曲线
def auuc_score_and_plot(y, treat, X, dml, cf_dml):# 使用dataframe组织计算AUUC的必要数据df = pd.DataFrame({'y': y,'treat': treat,'cf_dml': cf_dml.effect(X),'dml': dml.effect(X)})# 计算AUUC值auuc = auuc_score(df, outcome_col='y', treatment_col='treat', normalize=True, tmle=False)print(auuc)# 绘制gain曲线plot_gain(df, outcome_col='y', treatment_col='treat', normalize=True, random_seed=10, n=100, figsize=(8, 8))if __name__ == '__main__':# 使用synthetic_data生成数据y, X, treat, _, _, _ = synthetic_data(mode=1, n=10000, p=8, sigma=1.0)# 自编代码实现因果森林DMLalgo_by_self_cf_dml(y, treat, X)# econml工具包实现因果森林DMLdml, cf_dml = algo_by_econml_dml(y, treat, X)# 计算AUUC和绘制gain曲线auuc_score_and_plot(y, treat, X, dml, cf_dml)

使用多种策略实现因果森林DML,最重要的价值是可以加深对DML算法原理和工具包的理解。结合实践过程和以下的输出结果,可以发现一些新认知:

(1) 前文介绍的DML算法原理中,直接求解得到的 τ \tau τ,看起来应该是平均因果效应 A T E ATE ATE
至于如何使用 τ \tau τ去预测新样本的个体因果效应 I T E ITE ITE,并没有提到;但在econml.dml中,dml.effect(X)却可以得到 I T E ITE ITE

(2) 从 A T E ATE ATE的计算结果上可以看出,三种策略的结果是相似的,说明对DML算法原理的认知是没有多大问题的;第二种策略和第三种策略得到的结果并不完全相同,说明econml.dml.CausalForestDML相比econml.dml.DML,在代码层面还存在一些不同。

(3) 从auuc的结果来看,econml.dml.CausalForestDML的表现显著优于econml.dml.DML。但由于数据是虚拟的,下钻分析的意义不大,就不继续深入了。

关于auuc的计算还需要再描述一下。目前econml不支持针对auuc的计算和绘图,但是causalml可以。所以在代码中,我用到了 causalml.metrics.auuc_score和plot_gain这两个函数。这两个函数需要的数据,至少是2列:第1列是 Y Y Y值,第2列是 T T T值,其他的列都会被认为是不同模型输出的因果效应值,然后分别评估和输出。

self_cf_dml: w = 0.47
DML: 0.48424327569296155
CausalForestDML: 0.4705562443255083
cf_dml    0.716144
dml       0.505681
Random    0.498693
dtype: float64

3.2 策略变量为连续变量

通过上一节的实例,我们应该对因果森林DML有一个比较直观的感受了。本节尝试使用该模型解决一个业务场景中经常遇到的问题实例:推断商品价格和销量之间的因果效应。

本节实例的数据来源是kaggle竞赛中提供的在线零售销售数据。train_test_date_split函数参考其他内容对原始数据做了预处理,这部分的内容和因果森林DML无关,可以略过其中的逻辑细节(感兴趣的小伙伴可以在相关阅读中找到链接)。

为了将原问题转化为因果推断问题,需要设置: Y Y Y为销量的对数, T T T为价格的对数, X X X包括:month、DoM、DoW、stock_age_days和sku_avg_p。

Y Y Y T T T需要取对数的原因是:价格和销量间的关系大致应该为
τ = d Q / Q d P / P \tau=\frac{dQ/Q}{dP/P} τ=dP/PdQ/Q
此处, Q Q Q是销量, P P P是价格。该式和DML的基本公式有些出入,需要调整一下:对上述公式两边取对数,得到
log ⁡ Q = log ⁡ P + 截距 \log Q = \log P +截距 logQ=logP+截距
所以 Q Q Q P P P本身不是线性,但是取对数后,就变为线性,满足DML的使用条件了。

X X X的维度不多,如果在实际场景中,大概率还会包含商品的信息特征、用户历史购买特征等,本节的主要目标不在于精确给出其因果效应值,而是展现完整的计算过程,所以可以接受特征维度不那么全面的现状。

有了训练集后,使用因果森林DML进行训练,这个过程比较简单,一行代码便可以解决,就不赘述了。

得到模型后,依然需要使用auuc去验证模型的效果。不过在这里尤其需要注意两个方面:

(1) plot_gain和auuc_score中使用的treat只能接受0/1变量,而当前场景中价格是连续变量。代码里设置的逻辑是: log ⁡ P \log P logP<0认为是1,反之是0,物理意义可以理解为1为降价,0为不降价。

(2) 价格和销量间的因果效应值为负数,所以在传入auuc计算时,需要先取负号,将其转为正数。

import pandas as pd
import numpy as np
from datetime import datetime, date
from causalml.metrics import plot_gain, auuc_score
from sklearn.model_selection import train_test_split
from econml.dml import CausalForestDMLdef train_test_date_split():# 数据预处理df = pd.read_csv('OnlineRetail.csv', encoding="unicode_escape")df = df[(df['UnitPrice'] > 0) & (df['Quantity'] > 0)].reset_index(drop=True)df = df[~df.StockCode.isin(['POST', 'DOT', 'M', 'AMAZONFEE', 'BANK CHARGES', 'C2', 'S'])]df['InvoiceDate'] = pd.to_datetime(df.InvoiceDate)df['Date'] = pd.to_datetime(df.InvoiceDate.dt.date)df['revenue'] = df.Quantity * df.UnitPricedf = (df.assign(dNormalPrice=lambda d: d.UnitPrice / d.groupby('StockCode').UnitPrice.transform('median')).pipe(lambda d: d[(d['dNormalPrice'] > 1. / 3) & (d['dNormalPrice'] < 3.)]).drop(columns=['dNormalPrice']))df = df.groupby(['Date', 'StockCode', 'Country'], as_index=False).agg({'Description': 'first','Quantity': 'sum','revenue': 'sum'})df['Description'] = df.groupby('StockCode').Description.transform('first')df['UnitPrice'] = df['revenue'] / df['Quantity']df_dml = df[(df.groupby('StockCode').UnitPrice.transform('std') > 0)]df_dml = df_dml.assign(LnP=np.log(df_dml['UnitPrice']),LnQ=np.log(df_dml['Quantity']),)df_dml['dLnP'] = np.log(df_dml.UnitPrice) - np.log(df_dml.groupby('StockCode').UnitPrice.transform('mean'))df_dml['dLnQ'] = np.log(df_dml.Quantity) - np.log(df_dml.groupby('StockCode').Quantity.transform('mean'))df_dml = df_dml.assign(month=lambda d: d.Date.dt.month,DoM=lambda d: d.Date.dt.day,DoW=lambda d: d.Date.dt.weekday,stock_age_days=lambda d: (d.Date - d.groupby('StockCode').Date.transform('min')).dt.days,sku_avg_p=lambda d: d.groupby('StockCode').UnitPrice.transform('median'))y = df_dml['dLnQ']treat = df_dml['dLnP']X = df_dml[['month', 'DoM', 'DoW', 'stock_age_days', 'sku_avg_p']]y_train, y_test, treat_train, treat_test, X_train, X_test = train_test_split(y, treat, X, test_size=.2)return X_train, y_train, treat_train, X_test, y_test, treat_testif __name__ == '__main__':# 整合训练和测试数据X_train, y_train, treat_train, X_test, y_test, treat_test = train_test_date_split()# 因果森林DML训练cf_dml = CausalForestDML(n_jobs=1).fit(y_train, treat_train, X=X_train)# AUUC评估训练集效果train_df = pd.DataFrame({'y': y_train,'treat': np.where(treat_train.values < 0, 1, 0),'cf_dml': -cf_dml.effect(X_train)})plot_gain(train_df, outcome_col='y', treatment_col='treat', normalize=True, random_seed=10, n=100, figsize=(8, 8))auuc = auuc_score(train_df, outcome_col='y', treatment_col='treat', normalize=True, tmle=False)print('train set auuc:')print(auuc)# AUUC评估测试集效果test_df = pd.DataFrame({'y': y_test,'treat': np.where(treat_test.values < 0, 1, 0),'cf_dml': -cf_dml.effect(X_test)})plot_gain(test_df, outcome_col='y', treatment_col='treat', normalize=True, random_seed=10, n=100, figsize=(8, 8))auuc = auuc_score(test_df, outcome_col='y', treatment_col='treat', normalize=True, tmle=False)print('\ntest set auuc:')print(auuc)

以下是代码的输出结果。从结果上来看,模型的auuc优于随机排序的auuc,同时测试集的auuc略低于训练集的auuc,整体上来看是符合预期的。

train set auuc:
cf_dml    0.691234
Random    0.500072
dtype: float64test set auuc:
cf_dml    0.623231
Random    0.499888
dtype: float64

4 总结

文章正文到此就结束了,本节总结一下三个比较重要的内容:

(1) DML的原理是:基于对结果变量和策略变量残差的拟合,可以得到真正的因果效应值。

(2) econml工具包可以调用DML和因果森林DML算法。

(3) 使用auuc评估DML的预测效果时,可以调用causalml工具包。

5 相关阅读

DML算法原文:https://academic.oup.com/ectj/article/21/1/C1/5056401?login=false

DML算法原理讲解1:https://academic.oup.com/ectj/article/21/1/C1/5056401?login=false

DML算法原理讲解2:https://blog.csdn.net/a358463121/article/details/123999934

DML实例1:https://cloud.tencent.com/developer/article/1913864

DML实例2:https://cloud.tencent.com/developer/article/1938132

FWL定理:https://www.bilibili.com/video/BV1dA411H7nP/?spm_id_from=333.788&vd_source=f416a5e7c4817e8efccf51f2c8a2c704

在线零售销售数据:https://www.kaggle.com/datasets/vijayuv/onlineretail

销售数据预处理:https://github.com/Serena-TT/36-methods-for-data-analysis/blob/main/DML.ipynb

相关文章:

因果推断 | 双重机器学习(DML)算法原理和实例应用

文章目录 1 引言2 DML算法原理2.1 问题阐述2.2 DML算法 3 DML代码实现3.1 策略变量为0/1变量3.2 策略变量为连续变量 4 总结5 相关阅读 1 引言 小伙伴们&#xff0c;好久不见呀。 距离上次更新已经过去了一个半月&#xff0c;上次发文章时还信誓旦旦地表达自己后续目标是3周更…...

Flutter 开源库学习

网上看了好多歌词实现逻辑相关资料&#xff0c;封装比较的好的 就 flutter_lyric&#xff0c;核心类是LyricsReader&#xff0c;而且如果实现逐字逐句歌词编辑功能还需要自己实现很多细节 &#xff0c;网友原话是 &#xff1a;歌词的功能真的是不少&#xff0c;写起来也是挺难的…...

自主巡航,目标射击

中国机器人及人工智能大赛 参赛经验&#xff1a; 自主巡航赛道 【机器人和人工智能——自主巡航赛项】动手实践篇-CSDN博客 主要逻辑代码 #!/usr/bin/env python #coding: utf-8import rospy from geometry_msgs.msg import Point import threading import actionlib impor…...

MySQL中EXPLAIN关键字详解

昨天领导突然问到&#xff0c;MySQL中explain获取到的type字段中index和ref的区别是什么。 这两种状态都是在使用索引后产生的&#xff0c;但具体区别却了解不多&#xff0c;只知道ref相比于index效率更高。 因此&#xff0c;本文较为详细地记录了MySQL性能中返回字段的含义、状…...

如何理解ref toRef和toRefs

是什么 ref 生成值类型的响应式数据可用于模板和reactive通过.value修改值 ref也可以像vue2中的ref那样使用 toRef 针对一个响应式对象&#xff08;reactive&#xff09;的prop创建一个ref两者保持引用关系 toRefs 将响应式对象&#xff08;reactive封装&#xff09;转换…...

【linux】kernel-trace

文章目录 linux kernel trace配置trace内核配置trace接口使用通用配置Events配置Function配置Function graph配置Stack trace设置 跟踪器tracer功能描述 使用示例1.irqsoff2.preemptoff3.preemptirqsoff linux kernel trace 配置 源码路径&#xff1a; kernel/trace trace内…...

【Golang 面试基础题】每日 5 题(一)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…...

ETCD介绍以及Go语言中使用ETCD详解

ETCD介绍以及Go语言中使用ETCD详解 什么是etcd ETCD是一个分布式、可靠的key-value存储的分布式系统,用于存储分布式系统中的关键数据;当然,它不仅仅用于存储,还提供配置共享及服务发现;基于Go语言实现 。 etcd的特点 完全复制:集群中的每个节点都可以使用完整的存档高…...

03-用户画像+Elasticsearch

优点 es支持海量数据的写入和更新es可以和hadoop&#xff0c;hive及spark进行集成es支持hivesql的操作&#xff0c;可以通过hivesql将数据导入eses的在进行数据检索查询是速度比较快es是分布式存储 应用 全文检索 全文检索流程: 1-对文档数据(文本数据)进行分词 2-将分词…...

初学Mybatis之搭建项目环境

在连接 mysql 数据库时&#xff0c;遇到了个 bug&#xff0c;之前都能连上&#xff0c;但报错说换了个 OS 操作系统什么的 然后搜索怎么连接&#xff0c;找到了解决方法 MySQL MYSQL – 无法连接到本地MYSQL服务器 (10061)|极客教程 (geek-docs.com) 命令行输入 services.msc…...

JMeter使用小功能-(持续更新)

1、jmeter在同一个线程组内&#xff0c;uuid的复用 方式一&#xff1a; 方式二&#xff1a; 2、获得jMeter使用的线程总数 ctx.getThreadGroup().getNumberOfThreads()来表示活动线程总数 int threadNumctx.getThreadGroup().getNumThreads(); String threads Integer…...

科研绘图系列:R语言火山图(volcano plot)

介绍 火山图(Volcano Plot),也称为火山图分析,是一种在生物信息学和基因组学中常用的图形表示方法,主要用于展示基因表达数据的差异。它通常用于基因表达微阵列或RNA测序数据的可视化,帮助研究人员识别在不同条件下表达差异显著的基因。 火山图的基本构成 X轴:通常表示…...

docker firewalld 防火墙设置

1、环境 centos 7 firewalld docker-ce docker 默认会更改防护墙配置 导致添加的防火墙策略不生效&#xff0c;可以启用firewalld 重新设置策略 2、启用防火墙 systemctl start firewalld systemctl enable firewalld3、配置文件禁用docker 的iptables /etc/docker/daemon.js…...

《问题004:报错-JS问题-unknown: Invalid shorthand property initializer.》

问题描述&#xff1a; unknown: Invalid shorthand property initializer. (25:13) unknown:无效的简写属性初始化项 解决方法&#xff1a; “”应该写为“&#xff1a;”&#xff08;globalData 改成 globalData: &#xff09;...

什么是 MLPerf?

什么是 MLPerf&#xff1f; MLPerf 是一个用于衡量机器学习硬件、软件和服务性能的标准化基准测试平台。它由 MLCommons 组织开发&#xff0c;该组织是由多家领先的科技公司和学术机构组成的。MLPerf 的目标是通过一系列标准化的基准测试任务和数据集&#xff0c;提供一个统一…...

【SpringBoot】第3章 SpringBoot的系统配置

3.1 系统配置文件 3.1.1 application.properties SpringBoot支持两种不同格式的配置文件&#xff0c;一种是Properties&#xff0c;一种是YML。 SpringBoot默认使用application.properties作为系统配置文件&#xff0c;项目创建成功后会默认在resources目录下生成applicatio…...

ELK日志分析系统部署文档

一、ELK说明 ELK是Elasticsearch&#xff08;ES&#xff09; Logstash Kibana 这三个开源工具组成&#xff0c;官方网站: The Elastic Search AI Platform — Drive real-time insights | Elastic 简单的ELK架构 ES: 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它…...

ue5笔记

1 点光源 聚光源 矩形光源 参数比较好理解 &#xff08;窗口里面&#xff09;环境光混合器&#xff1a;快速创造关于环境光的组件 大气光源&#xff1a;太阳光&#xff0c;定向光源 天空大气&#xff1a;蓝色的天空和大气 高度雾&#xff1a;大气下面的高度感的雾气 体积…...

TCP重传机制详解

1.什么是TCP重传机制 在 TCP 中&#xff0c;当发送端的数据到达接收主机时&#xff0c;接收端主机会返回⼀个确认应答消息&#xff0c;表示已收到消息。 但是如果传输的过程中&#xff0c;数据包丢失了&#xff0c;就会使⽤重传机制来解决。TCP的重传机制是为了保证数据传输的…...

如何使用javascript将商品添加到购物车?

使用JavaScript将商品添加到购物车可以通过以下步骤实现&#xff1a; 创建一个购物车对象&#xff0c;可以是一个数组或者对象&#xff0c;用于存储添加的商品信息。在网页中的商品列表或详情页面&#xff0c;为每个商品添加一个“添加到购物车”的按钮&#xff0c;并为按钮绑…...

【MySQL】:想学好数据库,不知道这些还想咋学

客户端—服务器 客户端是一个“客户端—服务器”结构的程序 C&#xff08;client&#xff09;—S&#xff08;server&#xff09; 客户端和服务器是两个独立的程序&#xff0c;这两个程序之间通过“网络”进行通信&#xff08;相当于是两种角色&#xff09; 客户端 主动发起网…...

1.关于linux的命令

1.关于文件安装的问题 镜像站点服务器&#xff1a;cat /etc/apt/sources.list 索引文件&#xff1a;cd /var/lib/apt/lists 下载文件包存在的路径&#xff1a;cd /etc/cache/apt/archives/2.关于dpkg文件安装管理器的应用: 安装文件:sudo dpkg -i 文件名; 查找文件目录:sudo …...

【人工智能】机器学习 -- 决策树(乳腺肿瘤数)

目录 一、使用Python开发工具&#xff0c;运行对iris数据进行分类的例子程序dtree.py&#xff0c;熟悉sklearn机器实习开源库。 二、登录https://archive-beta.ics.uci.edu/ 三、使用sklearn机器学习开源库&#xff0c;使用决策树对breast-cancer-wisconsin.data进行分类。 …...

【proteus经典实战】LCD滚动显示汉字

一、简介 Proteus是一款功能丰富的电子设计和仿真软件&#xff0c;它允许用户设计电路图、进行PCB布局&#xff0c;并在虚拟环境中测试电路功能。这款软件广泛应用于教育和产品原型设计&#xff0c;特别适合于快速原型制作和电路设计教育。Proteus的3D可视化功能使得设计更加直…...

数据结构复习1

1、什么是集合&#xff1f; 就是一组数据的集合体&#xff0c;就像篮子装着苹果、香蕉等等&#xff0c;这些“水果”就代表数据&#xff0c;“篮子”就是这个集合。 集合的特点&#xff1a; 集合用于存储对象。 对象是确定的个数可以用数组&#xff0c;如果不确定可以用集合…...

订单管理系统需求规范

1. 引言 1.1 目的 本文档旨在明确描述订单管理系统的功能、非功能性需求以及约束条件&#xff0c;以指导系统的分析、设计、开发、测试和部署。 1.2 范围 本系统将支持在线订单处理&#xff0c;从客户下单到完成配送的全过程管理&#xff0c;包括库存管理、支付处理、订单跟…...

swiftui使用ScrollView实现左右滑动和上下滑动的效果,仿小红书页面

实现的效果如果所示&#xff0c;顶部的关注用户列表可以左右滑动&#xff0c;中间的内容区域是可以上下滚动的效果&#xff0c;点击顶部的toolbar也可以切换关注/发现/附近不同页面&#xff0c;实现翻页效果。 首页布局 这里使用了NavigationStack组件和tabViewStyle样式配置…...

深入理解并使用 MySQL 的 SUBSTRING_INDEX 函数

引言 在处理字符串数据时&#xff0c;经常需要根据特定的分隔符来分割字符串或提取字符串的特定部分。MySQL 提供了一个非常有用的函数 SUBSTRING_INDEX 来简化这类操作。本文将详细介绍 SUBSTRING_INDEX 的使用方法、语法&#xff0c;以及通过实际案例来展示其在数据库查询中…...

elementUI在手机端使用遇到的问题总结

之前的博客有写过用vue2elementUI封装手机端选择器picker组件&#xff0c;支持单选、多选、远程搜索多选&#xff0c;最终真机调试的时候发现有很多细节样式需要调整。此篇博客记录下我调试过程中遇到的问题和解决方法。 一、手机真机怎么连电脑本地代码调试&#xff1f; 1.确…...

【初阶数据结构】5.栈和队列

文章目录 1.栈1.1 概念与结构1.2 栈的实现2.队列2.1 概念与结构2.2 队列的实现3.栈和队列算法题3.1 有效的括号3.2 用队列实现栈3.3 用栈实现队列3.4 设计循环队列 1.栈 1.1 概念与结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操…...

网站上的个人词条怎么做的/推广普通话文字素材

为什么80%的码农都做不了架构师&#xff1f;>>> Read-Write Lock 当不同操作之间会对对象临界区造成不同区别的时候&#xff0c;可以考虑Read-Write锁模式&#xff0c;就是操作中有些会改变有些不会改变&#xff08;有点绕&#xff0c;但只要理解了的应该可以懂&am…...

wordpress局域网自定义域名/百度知道在线问答

用户管理这块包含用户和用户组两部分。 用户组包括浏览 用户组列表&#xff0c;添加、修改、删除用户组等。按照前面思路系统是依据用户组来判断用户权限的&#xff0c;用户组的最主要目的是划分权限。权限这块以后单独在做。 下面实现用户组浏览。 首先还是打开Home/Header.cs…...

php网站建设制作设计/优秀网站

STL 基础引入—迭代器一&#xff0c;pair双元组1&#xff0c;构造2&#xff0c;提取值二&#xff0c;map&#xff08;内部有序&#xff09;三、nth_element四&#xff0c;set&#xff08;有序平衡树&#xff09;引入—迭代器 1&#xff0c;.end()返回的不是最后一个元素的位置…...

广州市研发网站建设价格/免费推广的平台都有哪些

CGI是干嘛的&#xff1f;CGI是为了保证web server传递过来的数据是标准格式的&#xff0c;方便CGI程序的编写者。 web server&#xff08;比如说nginx&#xff09;只是内容的分发者。比如&#xff0c;如果请求/index.html&#xff0c;那么web server会去文件系统中找到这个文件…...

wordpress 登录美化/网络营销怎么做

随便挑了一张看起来比较高端的图片有些朋友可能玩过按键精灵&#xff0c;一个用来操作键盘鼠标完成一些自动化工作的软件。其实如果你学了Python的话&#xff0c;完全用不着按键精灵这种东西了。因为广泛的Python类库里&#xff0c;就有PyAutoGUI这样可以变成控制键盘鼠标的类库…...

wordpress iis 404页面/线下引流推广方法

你不知道的JavaScript博文相关代码托管至Github&#xff0c;每次写完博客会把代码提交上去。 代码地址&#xff1a;https://github.com/rongbo-j/you-dont-know-js 点击Download Zip可下载源码&#xff0c;或者安装git版本控制工具&#xff0c;在控制台或终端敲两行命令可以检出…...