北京化工大学数据结构第十次作业(计算机类)(2022.11.17)

本文详细介绍了一种图算法——拓扑排序,并通过多个示例代码展示了如何实现和应用该算法解决不同场景的问题,包括计算节点的出入度、进行拓扑排序并输出结果、计算任务完成的最短时间等。

A(附加代码模式)

遍历一遍矩阵算入度出度即可。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph
{
    int nodeNumber;
    string vexInfo[MAX_SIZE];
    int adjMatrix[MAX_SIZE][MAX_SIZE];
};
void CalculateDegree(const Graph &g,int inDegree[],int outDegree[])
{
    int n=g.nodeNumber;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(g.adjMatrix[i][j])
            inDegree[j]++,
            outDegree[i]++;
        }
    }
    return;
}

B

和C是一样的题,只多一步:把出栈顺序储存后输出。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100];
    memset(b,0,sizeof(b));
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cin>>a[i][j];
            if(a[i][j]) b[j]++;
        }
    }
    int count=0;
    stack<int> s;
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) s.push(i);
    }
    int c[n];
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        c[count]=t;
        count++;
        for(int i=0;i<n;i++)
        {
            if(a[t][i]==1) 
            {
                b[i]--;
                if(b[i]==0) s.push(i);
            }
        }
    }
    if(count<n) cout<<"ERROR"<<endl;
    else
    {
        for(int i=0;i<n;i++)
        {
            cout<<c[i];
            if(i!=n-1) cout<<" ";
            else cout<<endl;
        }
    }
    return 0;
}

C

把入度为0的点入栈,然后每次点出栈时就把这个点通向的点入度-1,直到没有点可以入栈为止。判断点数和出栈的点数是否相等。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100];
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0 && m==0) break;
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        for(int i=0;i<m;i++)
        {
            int q1,q2;
            cin>>q1>>q2;
            a[q1-1][q2-1]=1;
            b[q2-1]++;
        }
        int count=0;
        stack<int> s;
        for(int i=0;i<n;i++)
        {
            if(b[i]==0) s.push(i);
        }
        int c[n];
        while(!s.empty())
        {
            int t=s.top();
            s.pop();
            c[count]=t;
            count++;
            for(int i=0;i<n;i++)
            {
                if(a[t][i])
                {
                    b[i]--;
                    if(b[i]==0) s.push(i);
                }
            }
        }
        if(count!=n) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

D

对每个询问,两重循环模拟拓扑排序时的情况,如果序列中的点入度不为0,就输出no。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,0,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        a[q1][q2]=1;
        b[q2]++;
    }
    int o;
    cin>>o;
    int c[100],d[100];
    for(int r=0;r<o;r++)
    {
        for(int i=0;i<n;i++)
        {
            c[i]=b[i];
            cin>>d[i];
        }
        for(int i=0;i<n;i++)
        {
            int g=d[i];
            if(c[g]==0)
            {
                for(int j=0;j<n;j++)
                {
                    if(a[g][j]) c[j]--;
                }
            }
            else
            {
                cout<<"NO"<<endl;
                break;
            }
            if(i==n-1) cout<<"YES"<<endl;
        }
    }
    return 0;
}

E

题面描述很有问题,根本看不懂,其实意思就是拓扑排序,每行输入x,y,z表示完成y前必须完成x,耗时为z。求最小时间。

只要在拓扑排序出栈的基础上,用一个数组动态维护最大值就行。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        cin>>a[q1][q2];
        b[q2]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    if(count!=n) cout<<"Impossible"<<endl;
    else cout<<maxm<<endl;
    return 0;
}

F

F-I这4个题都是J题的一部分。

F和E是一样的题。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        cin>>a[q1][q2];
        b[q2]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        cout<<dp[i];
        cout<<endl;
    }
    return 0;
}

G

G题是建立在F题上的题。

F题把最大值找到后,再把图逆过来(其实就是转置邻接矩阵)后再找一遍最大值,然后用第一遍找到的最大值去减。(或者直接维护最小值,效果一样)

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100],c[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        cin>>a[q1][q2];
        b[q2]++;
        c[q1]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    int minm,dp2[n];
    memset(dp2,-1,sizeof(dp2));
    for(int i=0;i<n;i++)
    {
        if(c[i]==0) 
        {
            s.push(i);
            dp2[i]=maxm;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[i][t]>=0)
            {   
                if(dp2[i]!=-1) dp2[i]=min(dp2[t]-a[i][t],dp2[i]);    
                else dp2[i]=dp2[t]-a[i][t];
                minm=min(dp2[i],minm);
                c[i]--;
                if(c[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        cout<<dp2[i];
        cout<<endl;
    }
    return 0;
}

H

和F一样的题,注意输出的是什么

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100],c[100];
    pair<int,int> d[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        d[i].first=q1;
        d[i].second=q2;
        cin>>a[q1][q2];
        b[q2]++;
        c[q1]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    int minm,dp2[n];
    memset(dp2,-1,sizeof(dp2));
    for(int i=0;i<n;i++)
    {
        if(c[i]==0) 
        {
            s.push(i);
            dp2[i]=maxm;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[i][t]>=0)
            {   
                if(dp2[i]!=-1) dp2[i]=min(dp2[t]-a[i][t],dp2[i]);    
                else dp2[i]=dp2[t]-a[i][t];
                minm=min(dp2[i],minm);
                c[i]--;
                if(c[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    for(int i=0;i<m;i++)
    {
        cout<<dp[d[i].first]<<endl;
        //cout<<dp2[i];
        //cout<<endl;
    }
    return 0;
}

I

和G一样的题,注意输出的是什么。

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100],c[100];
    pair<int,int> d[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        d[i].first=q1;
        d[i].second=q2;
        cin>>a[q1][q2];
        b[q2]++;
        c[q1]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    int minm,dp2[n];
    memset(dp2,-1,sizeof(dp2));
    for(int i=0;i<n;i++)
    {
        if(c[i]==0) 
        {
            s.push(i);
            dp2[i]=maxm;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[i][t]>=0)
            {   
                if(dp2[i]!=-1) dp2[i]=min(dp2[t]-a[i][t],dp2[i]);    
                else dp2[i]=dp2[t]-a[i][t];
                minm=min(dp2[i],minm);
                c[i]--;
                if(c[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    for(int i=0;i<m;i++)
    {
        //cout<<dp[d[i].first]<<endl;
        cout<<dp2[d[i].second]-a[d[i].first][d[i].second];
        //cout<<dp2[i];
        cout<<endl;
    }
    return 0;
}

J

把F-I四个题拼在一起就行。 

#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
int main()
{
    int a[100][100];
    int b[100],c[100];
    pair<int,int> d[100];
    int n,m;
    cin>>n>>m;
    memset(b,0,sizeof(b));
    memset(a,-1,sizeof(a));
    for(int i=0;i<m;i++)
    {
        int q1,q2;
        cin>>q1>>q2;
        d[i].first=q1;
        d[i].second=q2;
        cin>>a[q1][q2];
        b[q2]++;
        c[q1]++;
    }
    int count=0;
    stack<int> s;
    int maxm=0,dp[n];
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        if(b[i]==0) 
        {
            s.push(i);
            dp[i]=0;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[t][i]>=0)
            {   
                if(dp[i]!=-1) dp[i]=max(dp[t]+a[t][i],dp[i]);    
                else dp[i]=dp[t]+a[t][i];
                maxm=max(dp[i],maxm);
                b[i]--;
                if(b[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    int minm,dp2[n];
    memset(dp2,-1,sizeof(dp2));
    for(int i=0;i<n;i++)
    {
        if(c[i]==0) 
        {
            s.push(i);
            dp2[i]=maxm;
            count++;
        }
    }
    while(!s.empty())
    {
        int t=s.top();
        s.pop();
        for(int i=0;i<n;i++)
        {
            if(a[i][t]>=0)
            {   
                if(dp2[i]!=-1) dp2[i]=min(dp2[t]-a[i][t],dp2[i]);    
                else dp2[i]=dp2[t]-a[i][t];
                minm=min(dp2[i],minm);
                c[i]--;
                if(c[i]==0)
                {
                    count++;
                    s.push(i);
                }
            }
        }
    }
    for(int i=0;i<m;i++)
    {
        int g1=dp[d[i].first];
        int g2=dp2[d[i].second]-a[d[i].first][d[i].second];
        if(g1==g2)
        {
            cout<<d[i].first<<"-->"<<d[i].second<<":"<<g1<<endl;
        }
    }
    return 0;
}

year city city_id treat log_y y x8 x11 x15 x22 2007 北京市 1 0 9.539508 13898.11 1.264640 0.569942 0.845000 0.055012 2008 北京市 1 0 9.802288 18075.06 1.239413 0.639087 0.849000 0.057260 2009 北京市 1 0 9.615341 14993.03 1.264713 0.740540 0.850100 0.054458 2010 北京市 1 0 9.931640 20571.05 1.286552 0.860007 0.859600 0.065843 2011 北京市 1 0 10.128951 25058.06 1.300859 0.990307 0.862300 0.056413 2012 北京市 1 0 10.208309 27127.65 1.309597 1.089477 0.862000 0.054254 2013 北京市 1 0 10.226097 27614.51 1.320657 1.188262 0.863000 0.056227 2014 北京市 1 0 10.316599 30230.27 1.331363 1.299789 0.864000 0.062482 2015 北京市 1 0 10.308587 29989.02 1.333557 1.402388 0.865100 0.050159 2016 北京市 1 0 10.240028 28001.91 1.342149 1.564142 0.865000 0.044606 2017 北京市 1 0 10.525465 37252.16 1.354748 1.707603 0.864500 0.053042 2018 北京市 1 0 10.627913 41270.92 1.356565 1.848103 0.865000 0.057030 2019 北京市 1 0 10.562997 38676.87 1.362943 2.155454 0.866000 0.058505 2020 北京市 1 1 10.554462 38348.17 1.356403 2.199525 0.875500 0.057751 2021 北京市 1 1 10.877047 52947.02 1.359477 2.452796 0.875000 0.062379 2022 北京市 1 1 10.996456 59662.32 1.362090 2.735230 0.874500 0.067378 2007 天津市 2 0 9.209267 9989.27 0.980527 0.429456 0.763200 0.033127 2008 天津市 2 0 9.472047 12991.45 1.025510 0.540338 0.772100 0.033021 2009 天津市 2 0 9.285099 10776.24 1.217347 0.639613 0.780200 0.030237 2010 天津市 2 0 9.601398 14785.44 1.261224 0.784393 0.795700 0.031415 2011 天津市 2 0 9.798709 18010.48 1.289371 0.961503 0.805000 0.033497 2012 天津市 2 0 9.878067 19498.00 1.308759 1.096418 0.815600 0.035672 2013 天津市 2 0 10.002953 22091.61 1.318956 1.205854 0.820000 0.036407 2014 天津市 2 0 10.093455 24184.21 1.351850 1.319705 0.822700 0.037784 2015 天津市 2 1 10.085443 23991.22 1.388772 1.387781 0.826400 0.037378 2016 天津市 2 1 10.016884 22401.53 1.406730 1.500830 0.829100 0.033836 2017 天津市 2 1 9.660468 15685.12 1.387262 1.556532 0.829200 0.035344 2018 天津市 2 1 9.762916 17377.23 1.382398 1.599459 0.831500 0.034050 2019 天津市 2 1 9.698000 16285.00 1.348040 1.178574 0.834800 0.031338 2020 天津市 2 1 9.689465 16146.60 1.348037 1.156892 0.847000 0.037499 2021 天津市 2 1 10.012050 22293.48 1.236330 1.267668 0.848800 0.032979 2022 天津市 2 1 10.131458 25120.98 1.230111 1.389052 0.850604 0.029005 假设数据的一部分为这种格式,log_y为被解释变量,treat为虚拟解释变量,为1是表示实施了自贸区政策,x8 x22 x15 x11为控制变量,那么这个异质性多期DID的平行趋势检验如何进行
03-15
<think>嗯,用户给了一个关于异质性多期DID平行趋势检验的问题。首先,我需要回忆一下多期DID和传统的双向固定效应模型有什么不同。传统DID是处理组和对照组在政策实施前有平行趋势,而多期DID因为处理时间不同,可能需要不同的检验方法。 用户的数据结构显示,不同城市的处理时间可能不同,比如北京市的treat在2020年变为1,而天津市在2015年就变为1。这种情况下,平行趋势检验需要调整,不能再用传统的事件研究法,因为每个处理组的时间点不一致。 我记得最近关于异质性处理效应的DID文献,比如Callaway和Sant&#39;Anna的方法,或者Sun和Abraham的估计方法,可能涉及动态效应和分组检验。但用户的问题更偏向于如何执行平行趋势检验,所以可能需要先进行分组,然后对每个处理时间组进行事件窗口下的系数检验。 首先,可能需要生成相对时间虚拟变量,比如政策前k期和 policy后k期,然后检查政策前的系数是否不显著异于零。但如果有多个处理时间,每个处理组的政策前后时间不同,生成这些虚拟变量需要考虑不同处理时间的影响。 另外,用户提到的控制变量x8、x22等,可能在回归时需要加入这些变量,或者在平行趋势检验时是否需要控制?这时候可能需要用双向固定效应模型,加入时间和个体固定效应,同时控制变量,然后看处理变量前的系数是否联合显著。 不过,多期DID中,如果处理时间是错开的,直接使用传统的事件研究法可能会有偏,因为存在异质性处理效应。这时候可能需要用Sun and Abraham(2021)的方法,对每个处理时间组单独估计事件研究系数,然后汇总平均。 具体步骤可能包括: 1. 确定每个个体的处理时间,将样本分成不同的处理队列(cohorts)。例如,北京市在2020年处理,天津市在2015年处理,每个队列的处理时间不同。 2. 对每个队列生成相对时间虚拟变量,即相对于处理年份的时间差,比如-3,-2,-1,0+1等,排除-1期作为参照。 3. 将这些虚拟变量作为解释变量,进行回归,包括队列固定效应、时间固定效应,以及控制变量。此时,检验政策前各期的系数是否联合不显著,即满足平行趋势。 或者,使用Callaway & Sant&#39;Anna(2021)的估计方法,计算每个队列的处理效应,然后检验政策前的效应是否为零。 此外,可能需要用动态效应模型,将处理变量替换为不同时间窗口的虚拟变量,例如,政策前第3年、前2年、前1年,政策后第1年、第2年等,然后检验政策前的虚拟变量系数是否为零。 用户的数据中,处理变量treat在不同年份和城市变化,所以需要确保模型设定正确,避免因为处理时间差异导致的估计偏差。 另外,关于控制变量的处理,是否需要在平行趋势检验时加入它们?通常来说,平行趋势检验应基于控制变量后的模型,因此回归模型中应该包括这些控制变量。 总结可能的步骤: 1. 将数据按处理时间分组,生成各个处理队列。 2. 对于每个队列,创建相对时间变量(如event_time = year - treatment_year)。 3. 在回归模型中,引入相对时间的虚拟变量(如event_-3, event_-2, event_0, event_+1等),并排除政策前1期的虚拟变量(-1期作为基准)。 4. 使用双向固定效应模型(个体和时间固定效应),加入控制变量,进行回归。 5. 检验所有政策前的虚拟变量系数(如event_-3, event_-2等)是否联合不显著,通常用F检验或Wald检验。 6. 如果无法拒绝原假设,则平行趋势成立。 或者,如果处理队列较多,可以采用Sun and Abraham的方法,对各队列进行单独估计,再汇总平均的动态效应,并检查政策前的效应是否为零。 不过,对于应用者来说,可能更倾向于使用事件研究法,生成相对时间虚拟变量,然后进行联合检验。这时候需要注意排除处理后的时期,避免引入处理效应到检验中。 另外,如果样本量较小,或者处理时间分散,可能需要使用更灵活的方法,如堆叠回归(stacked regression),或者限制样本到处理前的时间窗口。 还有,用户可能需要使用动态效应图形来展示政策前后的系数变化,观察政策前的系数是否在零附近波动,这也是一种直观的平行趋势检验方法。 最后,需要提醒用户注意异方差和自相关的问题,使用稳健标准误,或者聚在个体层面,以确保推断的有效性。</think>针对多期DID(异质性处理时点)的平行趋势检验,需采用动态效应模型结合事件研究法。以下是逐步操作指南: --- ### **一、数据预处理** 1. **识别处理队列** - 将样本按处理时间分组(如北京市2020年处理,天津市2015年处理),形成多个处理队列(cohorts)。 2. **生成相对时间变量** - 对每个观测值计算相对时间: $$ \text{event\_time} = \text{year} - \text{treatment\_year} $$ - 例如,北京市2020年处理的样本中,2018年对应$\text{event\_time}=-2$,2021年对应$\text{event\_time}=+1$。 --- ### **二、构建动态效应模型** 1. **设定虚拟变量** - 创建相对时间虚拟变量$D^{k}$,表示距离处理时间的第$k$期(如$k=-3,-2,0,+1,+2$)。 - **注意**:需排除政策前最后一期(如$k=-1$)作为基准组,避免多重共线性。 2. **回归模型** 使用双向固定效应模型,加入控制变量: $$ \log\_y_{it} = \alpha_i + \gamma_t + \sum_{k \neq -1} \beta_k D_{it}^k + \theta X_{it} + \epsilon_{it} $$ - $\alpha_i$:城市固定效应 - $\gamma_t$:年份固定效应 - $X_{it}$:控制变量(x8, x11, x15, x22) - $\beta_k$:政策前/后的动态效应系数 --- ### **三、平行趋势检验** 1. **假设检验** - 原假设$H_0$:所有政策前系数$\beta_{k<0}$联合为0- 通过**Wald检验**或**F检验**判断政策前系数是否显著。若p值>0.1,则通过平行趋势检验。 2. **可视化验证** - 绘制$\beta_k$的估计值及置信区间,观察政策前系数($k<0$)是否围绕0波动(如下图示意): ![动态效应图示例](https://miro.medium.com/v2/resize:fit:1400/1*eZkq3QGZ3Q0WgM7vRrSJjw.png) --- ### **四、Stata代码示例** ```stata * 生成相对时间变量 gen treatment_year = year if treat == 1 bysort city_id: egen first_treat = min(treatment_year) gen event_time = year - first_treat * 创建相对时间虚拟变量(限制政策前后5年) forvalues k = -5(1)5 { if `k&#39; == -1 continue gen D_`k&#39; = (event_time == `k&#39;) if !missing(event_time) } * 动态效应回归 reghdfe log_y D_* x8 x11 x15 x22, absorb(city_id year) cluster(city_id) * 检验政策前系数(假设政策前5期到前2期) test D_-5 D_-4 D_-3 D_-2 ``` --- ### **五、注意事项** 1. **处理队列异质性** - 若处理时间分散,可参考Sun & Abraham(2021)方法,对每个队列单独估计后加权平均。 2. **控制变量选择** - 确保控制变量在政策前不受处理效应影响,避免“坏控制”问题。 3. **样本平衡性** - 限制样本为处理前后$T$期(如T=5),避免长面板中混杂其他政策。 4. **稳健性检验** - 更换时间窗口、剔除部分处理队列,验证结果是否稳健。 --- ### **六、参考文献** - Callaway, B., & Sant&#39;Anna, P. (2021). Difference-in-Differences with Multiple Time Periods. *Journal of Econometrics*. - Sun, L., & Abraham, S. (2021). Estimating Dynamic Treatment Effects in Event Studies with Heterogeneous Treatment Effects. *Journal of Econometrics*.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五百场cf灰名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值