Shiyuan Li

V1

2022/02/26阅读:207主题:橙心

Applied Econometrics: TA Session I (Shiyuan Li)

作者:李适源 (北京大学光华管理学院 博士研究生)
邮箱:shiyuanli@pku.edu.cn
注:如需转载,请联系作者

0. 写在前面:引言与实用的资源

很开心在这里遇见大家!王老师的这门课将会要求大家使用Stata完成一些作业,包括对课上讲到的因果识别方法的实现、一些简单的随机模拟,基于观测数据展开实证研究等等(作业内容以王老师的讲解为准)。因此,我们建议选课同学最好能对Stata的常用操作有基本的了解(例如整理数据、描述性统计、OLS等回归分析)。

0.1 关于 Stata 的相关资源

如果Stata软件过期,或尚未安装的同学,可以点击这个链接安装Stata16。(我们课上的内容使用Stata14及以上版本就可以完成啦)

如果对Stata的操作不够熟悉(或生疏了)的同学,推荐阅读高级计量经济学及Stata应用(陈强, 2014)第四章(“Stata简介”),以快速入手Stata。另外,这本教材的第28章(“处理效应”)基本上涵盖了本课讲解方法对应的Stata命令(如双重差分、断点回归等)。

在这里,推荐给大家一个好用的Stata命令:在Stata命令窗口中键入ssc install lianxh安装此命令。该命令由中山大学连玉君老师团队开发,汇集了绝大多数常用的Stata命令使用方法介绍。语法格式是 lianxh 填入任何你想了解的计量操作(例如 lianxh DID, 又如 lianxh 断点回归),Stata将自动帮你检索出与此内容相关的推文链接,方便大家快速了解与此命令有关的操作。

0.2 关于“因果推断基本框架”的介绍

本课程将会从潜在结果框架(又称为Rubin因果模型)出发,为大家介绍适用于不同研究情境的因果识别方法。

王老师在第一节课将会引入潜在结果框架,对此不太了解的同学,推荐在课前阅读(亦可在课后复习时阅读)以下书籍的相关章节,有助于快速了解因果推断的基本概念,例如 Potential outcomes, Counterfactual, Average treatment effect,等等。

下列资料都可以在课程群中的 “实用资料包” 中找到。数学推导的难度大致由易到难(中英文分开),大家可以挑一本自己喜欢的读(内容是大同小异的)

  • Introduction to Econometrics. Stock & Watson, 2015. 相关章节:Chapter 13 Experiments and Quasi-Experiments
  • Mastering 'metrics: The Path from Cause to Effect. Angrist and Pischke, 2014. 相关章节:Chapter 1, Section 1.1 In Sickness and in Health
  • Mostly Harmless Econometrics: An Empiricist's Companion. Angrist and Pischke, 2014. 相关章节:Chapter 2 The Experimental Ideal, Section 2.1 and 2.2
  • 基本有用的计量经济学》. 赵西亮,2017. 相关章节:第二章 潜在结果框架
  • 高级计量经济学》. 陈强,2014. 相关章节:第28章 处理效应;第28.1节 处理效应与选择难题
  • 因果推断的逻辑线索。 这是助教小哥自己写的介绍因果推断基本框架的推文,如果大家睡前喜欢玩手机,不妨看看这个助眠。

在开始正题之前,我想送给大家两个字 “别怕!” (这也是上学期的最后一次计量习题课我分享给大家的话)。无论是Stata操作还是看起来花哨的计量方法,它们都只是纸老虎!我们一起来了解它,战胜它!

1. 研究问题:课外补习有用吗?

当下,"双减政策"等教育改革方兴未艾。在这场改革中,面对中小学生的有偿课外补习受到了严厉限制。我们想知道,对于全国的八年级学生而言,参加课外补习(语文、数学、英语)对于这些初中生学业成绩的因果效应(treatment effect)。 (注:这个研究问题可以使用中国教育追踪调查CEPS数据展开真实的实证研究)

  • 结果变量 : 2014 年秋季学期,期中考试的标准化数学成绩 (该成绩具有个体间可比性)
  • 处理变量 : 从2013 年到2014 年(秋季学期前),此期间是否参加数学相关的课外补习 (我们将处理变量简称为“是否参加课外补习”)
  • 简便起见,假设所有人参加的课外补习班是同质的,也即课外补习的授课内容,授课质量,补习班的环境、规模等特征也都是类似的。

1.1 理想:潜在结果与个体因果效应

  • : 假若个体 参加了课外补习,那么她将会在2014年秋季获得的数学考试期中成绩。
  • : 假若个体 没参加课外补习,那么她将会在2014年秋季获得的数学考试期中成绩。
  • : 参加课外补习(相比未参加),对于个体 数学考试成绩的个体因果效应。
  • 社会科学因果推断的根本性问题:对于同一个个体 , 我们不可能同时观察到她的两个潜在结果

1.2 现实:处理状态与观测结果

  • 如果个体 事实上参加了课外补习( ),那么我们可以观测到她的数学成绩 (也即,潜在结果 被个体 实现了)
  • 如果个体 事实上没参加课外补习( ),那么我们可以观测到她的数学成绩 (也即,潜在结果 被个体 实现了)

2. 何为“模拟”:扮演上帝!

2.1 潜在结果的生成过程

现在,设想聪明的你就是全知的“上帝”(注:本课尊重同学们的信仰,坚决拥护我党的宗教政策,此处的上帝是为了阐释的方便,仅为一个比喻)。

换句话说,你知道每一个人的潜在结果 的生成过程,因此你可以非常容易地计算出,参加课外补习对每一位中学生数学成绩的个体因果效应。此后,将个体因果效应进行加总平均,也就得到了总体(全国八年级学生)的平均因果效应。

具体地,我们设定每位个体 的潜在结果(有待实现的数学成绩)是三个协变量(covariates, 包括学生性别、家庭收入、学习动力)以及误差项 的线性函数。

  • Female:女孩相比男孩,八年级时的数学期中考试成绩(的潜在结果)相对更高
  • Income:家庭收入越高的学生,八年级时的数学期中考试成绩(的潜在结果)相对更高
  • Motive: 学习动力越强的学生,八年级时的数学期中考试成绩(的潜在结果)相对更高
  • :其他未观测到的,影响潜在结果的因素

在这里,我们假定参加课外补习对于成绩的因果效应在不同个体间“完全同质”。也即个体因果效应为一个常数。容易看出,个体因果效应 总体的平均因果效应

2.1.1 使用 Stata 生成服从特定分布的随机变量

现在,我们使用Stata生成上述的三个协变量, 使得它们满足如下的概率分布

set obs 10000 // 设定我们的随机样本容量为10000人
set seeds 123 // 设定生成随机数的种子,保证"可复制性"
gen female=rbinomial(1,0.3) // 生成二值变量"性别";女性=1
gen income=0.1*rchi2(3)    // 生成连续变量"家庭收入"(万元)
gen motivation=0.3*female-2*income+rnormal() // 生成连续变量"学习动力"

2.1.2 使用 Stata 生成每个人的潜在结果取值

注意,这一模块是在模拟"上帝"的操作;在真实世界中,潜在结果 的生成方式、每个人的个体因果效应、总体平均因果效应都是未知的!

gen e=rnormal(0,1)  // 生成一个服从标准正态分布的error term
gen Y1=0.5+0.1*female+0.2*income+0.3*motivation+e // 生成Y_1i
gen Y0=0.1*female+0.2*income+0.3*motivation+e     // 生成Y_0i

现在,由于我们知道每一个人的潜在结果取值,也就知道了每个人的个体因果效应(Individual Treatment Effect,ITE), 此乃“上帝视角”。我们可以直接使用定义式,计算平均因果效应(Average Treatment Effect, ATE),也即直接将每位个体的ITE进行加总平均。

需要注意,由于我们使用的是总体的一个随机样本(N=10000人),求出来的ATE其实是每个人的个体因果效应的样本均值(而非总体期望)。所以求出来的ATE值与真实值( )仍存在细微的差距。

可以想象,当样本容量无限大时,使用上述方式求出来的ATE应该就等于我们设定的真实的平均因果效应 (回忆大数定律,Law of Large Number)。

gen ITE=Y1-Y0    
// 这是每位个体i的个体因果效应
mean ITE    
// 使用定义计算平均因果效应,也即ITE的加总平均

2.2 处理变量的生成方式 I:随机实验情形

个体 是否参加课外补习,是由实验者随机分配的。例如通过丢硬币、摇骰子、摸球等随机化的方式来决定个体 是否参加课外补习。

假设处理变量 (1=参加补习,0=未参加补习),服从 的两点分布。

gen D = rbinomial(1,0.4) // 生成服从两点分布的随机变量
tab D

大家可以这样理解:在全国随机地选出一批人(随机样本),让每一个人通过“摸球”的方式,来决定这个人是进入处理组还是控制组。

设想每个人都从同一个不透明的袋子中摸球,袋子中有4个白球和6个黑球(除了颜色外其他完全相同)。摸出白球的人进入处理组( )参加补习,摸出黑球的人进入控制组( ),不参加补习。

注意到,每一个人在处理变量 上的取值是完全随机分配的。这里的随机分配是指,个体“是否接受处理(参加课外补习)”完全取决于这个人的运气(或者说摸球的“手气”)。个体的处理状态(参加或不参加补习),与此人的社会特征、经济特征、心理与生理特征几乎没有任何关系。

因此,虽然上述协变量(性别、家庭收入、学习动力)是决定个体潜在结果(有待实现的数学成绩)的重要因素,但由于处理状态是完全随机分配的,因此处理变量 的取值与这些协变量的取值不存在任何的关联,两者是相互独立的。

换言之,处理变量 的取值与这些协变量的取值满足“独立性假定”(Independence Assumption)。

2.2.1 将潜在结果转化为观测结果:处理状态决定了“实现”

根据潜在结果与观测结果的关系,事实上参加补习的个体(处理组),他们的潜在结果 得到了实现(转化为观测结果);事实上没有参加补习的个体(控制组),他们的潜在结果 得到了实现(转化为观测结果)。

  • 事实上参加了补习的个体,他们的观测结果为:
  • 事实上未参加补习的个体,他们的观测结果为:

基于上述关系,我们使用Stata生成每位个体的观测结果。需要注意,在现实世界中,只有观测结果 是我们真正能够获取的信息,我们在实证研究中不可能使用个体的潜在结果来进行分析(除非你拥有上帝视角)。

gen Y_obs=Y1 if D==1
replace Y_obs=Y0 if D==0

2.2.2 基于观测结果来估计因果效应

由于每个人的处理状态是完全随机分配的。此时,“处理组与控制组在结果变量上的均值差异”可以无偏、一致地估计出总体的平均因果效应。

sum Y_obs if D==1 // 处理组在结果变量上的样本均值 Y_bar(D=1)
scalar Y_bar_D1=r(mean) // 将上述样本均值 储存为 Y_bar_D1 这个标量

sum Y_obs if D==0 // 控制组在结果变量上的样本均值 Y_bar(D=0)
scalar Y_bar_D0=r(mean) // 将上述样本均值 储存为 Y_bar_D0 这个标量 

* 之后在计算中,可以直接使用Y_bar_D0这个名字,它就是我们存入的那个具体数值)

* 计算两组的样本均值差异,并将结果储存为 diff 这个标量
scalar diff=Y_bar_D1-Y_bar_D0 

* 展示 diff 里面储存的具体数值
display diff 
* 发现:两组的样本均值差异=.516,与真实的总体平均因果效应(0.5)很接近!

reg Y_obs D,r  // 使用OLS回归的方法,获得"组间均值差异"

上述代码块的最后一行,是使用OLS回归的方法来获得"组间均值差异"。

可以证明,使用结果变量 对 处理状态 进行一元 OLS 回归, 所对应的样本回归系数 就等于“处理组与控制组在结果变量上的均值差异”。

2.3 处理变量的生成过程 II:个体自己选择是否补习

在真实世界中,初中学生是否接受处理(参加课外补习),更可能是学生自己(或学生家长)做出的参与决策,而不是由丢硬币/摸球等方式来随机决定的。

那么,个体 是基于什么准则来决定自己是否接受处理呢?一个简单的解释就是,基于效用:如果接受处理的"净效用" 为正,那么个体 就参加补习。否则,个体 就不会参加补习。

现在,再次开启上帝视角。我们设定 个体 接受处理(参加补习) 的净效用 是 三个协变量(性别、收入、学习动力)以及一个标准正态误差项 的线性函数。

当净效用 时,个体 的处理变量取值 ; 当净效用 时,个体 的处理变量取值

在这样的设定下,处理变量 是与协变量(性别、收入、学习动力)存在着非线性关系;而与此同时,这些协变量又是影响个体"潜在结果"的重要因素(回忆一下我们如何生成的潜在结果)。

因此,处理变量 不再独立于 潜在结果。简单的组间均值差异(或等价地说,一元OLS回归系数),不能无偏、一致地估计出真实的总体平均因果效应;在传统计量框架下,这就是大家熟知的遗漏变量偏误。

下面,我们使用Stata重新生成处理变量的取值;然后基于新的处理状态,重新生成每位个体的观测结果;基于新的观测结果,重新估计处理组和控制组在观测结果上的“组间均值差异”,验证一下它是否与真实的平均因果效应“相去甚远”。


*首先删去在随机分配情形(Case I)下的处理变量和结果变量
drop Y_obs D

* 生成"接受处理"的净效用 D_star
gen D_star=0.1+0.1*female+0.1*income+0.8*motivation+rnormal(0,1)

* 基于净效用的取值是否为正,个体决定是否接受处理
gen D=(D_star>0)

*事实上被处理的个体,他们的观测结果Y_obs为Y1
gen Y_obs=Y1 if D==1

*事实上未被处理的个体,他们的观测结果Y_obs为Y0
replace Y_obs=Y0 if D==0

*重新估计 "处理组与控制组在结果变量上的样本均值差异"
reg Y_obs D,r

很遗憾,“处理组与控制组在结果变量上的样本均值差异” 为 ,对应的95%置信区间为 ,显著地超过了真实的总体平均因果效应( )。

3. 蒙特卡洛模拟:理论与实践

3.1 思想:重复地从总体中抽取样本数据

上面的两个章节,严格意义上不能算是随机模拟。因为,我们只从总体中抽取(生成)了1个随机样本(样本容量N=10000)。我们基于这个特定的随机样本包含的数据,可以估计出1个样本回归系数(处理组与控制组在结果变量上的样本均值差异)。

但是,由于抽样误差的存在(Sampling error),这个特定的随机样本与总体的信息“多多少少存在一些出入”。可能有同学会觉得,是因为我们运气不好,得到的样本回归系数为 ;说不定再抽取另一个随机样本,(利用这个新样本所包含的数据),得到的样本回归系数就很接近 (真实的因果效应)。

对于这样的疑问,我们有一个简单而直截了当的方式来解答:蒙特卡洛模拟。也即,从给定的总体中,不断地抽取样本容量为N的随机样本;也就是说,在每一个随机样本当中,都包含N个人以及他们相应的结果变量和处理变量的取值( ),变量取值的生成方式就是我们第一章、第二章预先设定好的“数据生成过程”。

需要注意,在每一个随机样本当中,数据的生成方式是一模一样的;但是,在每个样本当中,N位个体在随机变量( )上的具体取值,完全可能 “因样本数据而异”。

针对每一个随机样本所包含的数据 ( ),我们都用相同的估计方法,获得1个样本回归系数 (其中,下标 代表这个样本回归系数是基于第 个随机样本所包含的数据)。

设想我们抽取了 份样本数据;在每份样本数据中,都包含 个数据点(受访者/企业/地区)。如此一来,我们就能获得 个不同的样本回归系数估计值:

现在,我们把 个估计值看作是 个“观测值” (observations)。我们利用这 估计值,可以计算出它们的样本均值、样本方差。

根据大数定律,当我们反复抽取随机样本的次数 充分大的时候,利用这 个估计值们计算出的(样本)均值、样本方差将会非常接近 (估计量) 的总体期望 、总体方差

因此,我们可以基于这 个估计值计算出它们的(样本)均值,与真实的平均因果效应( )进行比较,就可以评估OLS估计结果是否是无偏的(unbiased)。

3.2 使用Stata进行随机模拟 (以下内容很重要)

现在,我们在Stata中编写一个简单的小程序,来实现上述的“反复抽取样本数据,并进行估计”的模拟过程。请大家一定要耐心掌握下列命令的编写逻辑,后续的课后作业可能会要求同学们编写类似的程序来进行随机模拟。

3.2.1 有关随机模拟的学习资料

如果课后对模拟程序仍然不是特别理解,建议同学们参考以下资源(尤其推荐下列第一项):

3.2.2 随机模拟的程序编写

下面我们使用Stata来编写一个随机模拟的命令程序。这个程序应该包含以下几个“动作”:

  • (1) 生成10000位个体 (他们就是第一份样本数据中的个体)
  • (2) 生成这10000位个体在以下协变量上的取值:性别、收入、学习动力
  • (3) 生成这10000位个体的潜在结果 ( )
  • (4) 生成这10000位个体的处理变量 的取值
  • (5) 根据处理变量 的取值,生成这10000位个体的观测结果 (也就是结果变量的取值)
  • (6) 基于结果变量 和处理变量 的取值,做简单OLS回归,得到处理变量 对应的样本回归系数

在程序编写结束后,使用 simulate 命令,将自己编写的程序重复运行1000次。也就相当于,我们把“上述步骤”重复运行了1000次,但每一次运行都是基于一份崭新的样本数据 (这些样本数据都是从同一总体中生成的)。最终,我们得到了1000个不同的样本回归系数估计值

*在自己编写新的命令程序之前,一般要加上这句话,意思是把名字为"Sim_1"的自编程序删除。
capture program drop Sim_1
program Sim_1 // 开始编写命令程序,将程序命名为"Sim_1"
 drop _all   // 这一句很关键。在使用第s个样本的数据完成系数估计之后,都会清空数据,重新生成新的样本数据
 set obs 10000 // 设定每次抽取的随机样本容量都为10000人
 gen female=rbinomial(1,0.3) // 生成二值变量"性别";女性=1
 gen income=0.1*rchi2(3)    // 生成连续变量"家庭收入"(万元)
 gen motivation=0.3*female-2*income+rnormal() // 生成连续变量"学习动力"
 gen e=rnormal(0,1)  // 生成一个服从标准正态分布的error term
 gen Y0=0.1*female+0.2*income+0.3*motivation+e     // 生成Y_0i
 gen Y1=0.5+Y0                                     // 生成Y_1i
 *生成"接受处理"的净效用 D_star
 gen D_star=0.1+0.1*female+0.1*income+0.8*motivation+rnormal(0,1)
 *基于净效用的取值是否为正,个体决定是否接受处理
 gen D=(D_star>0)
 *生成观测结果:事实上接受处理的个体,观测结果Y_obs为Y1
 gen Y_obs=Y1 if D==1
 *生成观测结果:事实上未被处理的个体,观测结果Y_obs为Y0
 replace Y_obs=Y0 if D==0
 *使用简单OLS回归,估计"处理组与控制组在结果变量上的样本均值差异"
 reg Y_obs D
 *将处理变量D对应的样本回归系数,_b[D]的取值,存放在"beta_hat"当中
 scalar beta_hat=_b[D]
end // 自己编写的命令程序到此结束

* 模拟程序编写完成后,使用“simulate”命令,将模拟程序重复运行1000次
simulate beta_hat=beta_hat, reps(1000) seed(123):Sim_1

需要注意simulate 命令的语法是:simulate 你想要的输出结果名字(自己取名)=你要求Stata在每次运行完自编程序后保存的输出结果(此例中就是样本回归系数估计值),reps(填写重复运行程序的次数) seed(填写随机数种子):此处填写你自己编写的程序名字

另一个小技巧是,如何查看回归系数的估计值在Stata中的名字呢?可以在回归命令的选项后键入coeflegend来查看。例如,想查看处理变量D对应的回归系数估计值,在Stata缓存中对应的名字是什么,可以用如下的命令:

 reg Y_obs D,coeflegend
 ------------------------------------------------------------------------------
       Y_obs | Coefficient  Legend
-------------+----------------------------------------------------------------
           D |      0.840  _b[D]
       _cons |     -0.201  _b[_cons]
------------------------------------------------------------------------------

3.2.3 使用图形来考察随机模拟的结果

完成上述模拟之后,我们来考察一下这 个样本回归系数(估计值)的分布。

首先,键入sum beta_hat,d,这 样本回归系数估计值的样本均值约为 , 可将之近似视作 的值。(回忆大数定律,样本均值依概率收敛到总体期望)。

容易发现,OLS估计量的期望 ,与真实的总体平均因果效应 可谓 “相去甚远”。(也即,因果效应系数估计是有偏的)

下面,我们用图形的方式,更直观地展示这 个样本回归系数(估计值)的分布。

twoway ///
(hist beta_hat,frac yaxis(2) fcolor(ltbluishgray%50) lcolor(ltblue%50)) ///
(kdensity beta_hat,lcolor(red%80) yaxis(1)), ///
xline(0.5,lp(dash) lcolor(blue)) xline(0.84,lp(dash) lcolor(red)) ///
xscale(range(0.4 1)) xlabel(#8 0.84)   ///
xtitle("Value of beta_hat") title("Figure I: Simulation Results")

别怕!这么多行命令只是“纸老虎”,我们一行行地来理解就好啦。

  • 第一行twoway表示一般的(双变量)绘图命令。虽然我们这里只涉及一个随机变量 的分布, 但是我们要将两张图叠加到一起,所以也使用twoway开头。

  • 第二行。这是我们要画的第一幅图,它是这 个样本回归系数的频次分布直方图。它的主命令是hist beta_hat。逗号的选项依次是:

    • frac要求报告“频次”(默认是报告“频次密度”)
    • yaxis(2)命令在“绘图窗口的右边缘”生成这幅图的纵轴 (因为待会还要画一幅图,我们想把下一幅图的纵轴放在窗口的左边缘)
    • fcolor(ltbluishgray%50) 规定了直方图“内部填充”的颜色为浅蓝灰色,透明度为50%
    • lcolor(ltblue%50)规定了直方图“内部填充”的颜色为浅蓝色,透明度为50%
    • 如果想了解Stata中不同颜色对应的英文单词,可以help colorstyle
  • 第三行。这是我们要画的第二幅图。它基于这 个样本回归系数的分布情况,估计出的 的概率密度曲线 (Stata使用的是非参数的方法来估计概率密度)。它的主命令是kdensity beta_hat。逗号后的选项设定了概率密度曲线的颜色为红色(透明度为80%),yaxis(1)规定将概率密度曲线的纵轴放在窗口的左边缘。

  • 第四行。这一行是用来添加两条垂直的“参考线”。

    • 第 1 条参考线是 (这里的 不是变量,是指横轴)。这条参考线所处的位置,就是真实的总体平均因果效应(ATE)。
    • 第 1 条参考线的主命令是xline(0.5,);逗号的选项,lp(dash)规定了参考线的类型(line pattern)是虚线(dash); lcolor(blue)规定了参考线的颜色是蓝色。
    • 第 2 条参考线是 (这里的 不是变量,是指横轴)。这条参考线所处的位置,是这 个样本回归系数的均值。
    • 第 2 条参考线的主命令是xline(0.84,);逗号的选项,lp(dash)规定了参考线的类型(line pattern)是虚线(dash); lcolor(red)规定了参考线的颜色是红色。
  • 第五行。这一行是对横轴的刻度值进行了规定。xscale(range(0.4 1)) 规定了横轴的取值范围最小为0.4,最大为1;xlabel(#8 0.84) 规定了横轴中要显示的刻度线总数为8个,其中要显示的7个刻度线就是0.4, 0.5, ... , 1;另外1个要显示的刻度线是 0.84。(加起来刚好是8个刻度线)

  • 最后一行。给我们这副“花哨”(fancy)的图形加上标题。xtitle("Value of beta_hat") 用来加横轴的标题;title("Figure I: Simulation Results") 用来添加整张图的标题。

  • 小结:我们的画图命令之所以有这么多行,是因为我们想把很多东西叠加到一张图里。比如,我们想把直方图和概率密度曲线叠放在一张图里。 这时就需要注意,一般绘图命令开头要用twoway(简写为tw),在tw之后紧跟两个括号,每个括号中分别写入你要做的两幅图对应的命令,也即tw (hist beta_hat)(kdensity beta_hat)。这样一来,就可以实现将两幅图叠放在一起展示。

3.2.4 有关 Stata 作图的实用资料

说心里话,助教小哥本人对Stata作图功底也相当一般 (与我的前任搭档景鹏助教相差甚远)。但是大家不用担心,Stata作图有一个很友好的地方,我们可以先用简单的主命令把基本的图形画出来(不用设置那么多复杂的选项)。然后,我们可以在图形中直接通过 “鼠标-菜单” (也即点点点) 的方式把图形进行修饰和美化。

当然了,通过“点点点”来美化图形的效率比较低,也比较欠缺可重复性。因此强烈推荐大家阅读下面的一些绘图指导。下列中文资料我都细读过,内容详实,可读性和实操性很强 (读了就能上手作图啦)。

分类:

数学

标签:

其他

作者介绍

Shiyuan Li
V1

PhD student GSM,PKU