這部分是對Stata編程的簡單介紹旭蠕。主要討論宏和循環(huán),并展示如何編寫簡單程序惨驶。編程是一個很大的主題,我在這里僅進(jìn)行一些提示敛助,希望能激發(fā)你進(jìn)一步學(xué)習(xí)的興趣粗卜。本文所涵蓋的材料將幫助你更有效地使用Stata。
Stata 9引入了一種新的非常強(qiáng)大的矩陣編程語言Mata纳击。這極大擴(kuò)展了程序員的工具续扔,遠(yuǎn)遠(yuǎn)超出了這里所討論的宏,但是Mata是一個值得單獨(dú)討論的主題焕数,所以本文不會對此進(jìn)行介紹纱昧。然而,您在這里的努力不會白費(fèi)堡赔,因?yàn)镸ata僅是Stata編程的補(bǔ)充识脆,而不是完全替代。
要了解關(guān)于Stata編程的更多信息,我建議您使用Kit Baum的Stata編程簡介,現(xiàn)在已發(fā)布到第二版。您也可以查閱用戶指南第18章昙衅,根據(jù)需要參考。Nick Cox在Stata Journal的專欄也是學(xué)習(xí)Stata的絕佳資源粘招。
3.1 宏
宏是一個與一些文本相關(guān)聯(lián)的名稱啥寇,依據(jù)范圍可分為全局宏與本地宏偎球。
3.1.1 在本地宏中存儲文本
本地宏名稱最多為31個字符,并且僅在當(dāng)前環(huán)境(語境)中被識別(console辑甜,do file或programe)衰絮。
本地宏定義語句為local name [=] text
,輸入 `name' (請注意使用反引號和左引號。)進(jìn)行調(diào)用磷醋。
第一種變體不帶等號猫牡,用于存儲任意文本,最多可達(dá)64k個字符(在Stata SE中最多可達(dá)100萬個字符)邓线。文本通常用引號引起來淌友,但不是必須。
示例:回歸方程中的控制變量
有時你需要運(yùn)行一堆回歸方程骇陈,其中包括一組標(biāo)準(zhǔn)的控制變量震庭,比如age,agesq你雌,education器联,和income
。當(dāng)然婿崭,你可以在每個等式中鍵入這些名稱拨拓,或者可以剪切和粘貼名稱,但這些方法很繁瑣且容易出錯氓栈。聰明的方法是定義一個宏
local controls age agesq education income
然后渣磷,輸入命令
regress outcome treatment `controls'
它與一下命令完全等價
regress outcome treatment age agesq education income
如果只運(yùn)行一次回歸,不需要保存信息授瘦,但是如果你必須運(yùn)行多個具有不同結(jié)果或處理方式的模型幸海,使用宏可以提高效率并確保一致性。
這種方法還有一個好處是奥务,如果以后你意識到你應(yīng)該對某個控制變量取對數(shù)物独,你只需改變宏的定義即可,比如將income
改為logimcome
,對宏所做的改變會在所有后續(xù)模型中應(yīng)用氯葬。
警告:輸入不存在的宏不是錯誤;,只是會返回一個空字符串挡篓。所以要小心拼寫正確的宏名稱。如果輸入regress outcome treatment `contrls',Stata將讀取regress outcome treatment官研,因?yàn)楹?strong>contrls不存在秽澳。如果你輸入control的話,也會發(fā)生同樣的情況戏羽,因?yàn)楹昝Q不能按變量名稱的方式縮寫担神。
示例:管理虛擬變量
假設(shè)你正在參與人口調(diào)查工作,受訪人按年齡以5年分為一組始花,從age15to19
到age45to49
共分為七組妄讯。其中有六組會作為虛擬變量在回歸中使用。定義一個宏
local age "age20to24 age25to29 age30to34 age35to39 age40to44 age45to49"
然后在你的回歸模型中使用
regress ceb `age' urban
這不僅更短酷宵,更具可讀性亥贸,而且更接近你的意圖。這也使得改變對年齡的表示更為容易浇垦,如果您以后決定使用線性和二次項表示年齡炕置,則只需定義宏local age "age agesq"
并重新運(yùn)行模型。請注意男韧,第一個age
是宏的名稱朴摊,第二個是變量的名稱。在此我用引號使代碼更清晰此虑。
請注意嵌套的宏甚纲。如果一個宏中包含了另一個宏(在此不妨稱為子宏),新宏的內(nèi)容是在創(chuàng)建那一刻就確定的(解析)寡壮,而不是在被評估時被解析贩疙。例如,如果你定義宏local controls `age' income education况既。在定義新宏control時Stata認(rèn)為其中包含子宏age并對子宏內(nèi)容展開解讀这溅,就算在未來你改變了子宏age的內(nèi)容,新宏中保留的依然是創(chuàng)建時點(diǎn)子宏的內(nèi)容與形式棒仍。
但是悲靴,有一種方法可以實(shí)現(xiàn)新宏隨子宏同步更新的效果。訣竅是在定義宏時輸入斜杠號避開宏評估字符local controls `age' income education∧洌現(xiàn)在Stata不評估宏癞尚,所以controls內(nèi)容變成了`age' income education。當(dāng)宏controls被評估時乱陡,Stata才會發(fā)現(xiàn)它包含宏age并對其展開解讀浇揩。
3.1.2 在本地宏中存儲結(jié)果
第二種類型的宏定義local name = text
(含等于號)用于存儲結(jié)果。它指示Stata將右側(cè)的文本視為表達(dá)式憨颠,對其進(jìn)行評估胳徽,并在指定名稱中存儲結(jié)果的文本表達(dá)积锅。
假設(shè)你只是運(yùn)行一個回歸,并想存儲R平方結(jié)果养盗,以便與后面的回歸進(jìn)行比較缚陷。你知道regress
命令將殘差平方和存儲在e(r2)
中,所以你認(rèn)為如下命令將會奏效:
local rsq e(r2)
但事實(shí)并非如此往核。您的宏所存儲是公式e(r2)
箫爷,如過你輸入
display "`rsq'"
你看到的是一條公式,而不是我們所要的數(shù)值聂儒。解決方法是使用等號連接local rsq = e(r2)
,這會t提示Stata計算表達(dá)式并存儲結(jié)果虎锚。
要看到差異,請嘗試一下代碼
. sysuse auto, clear
(1978 Automobile Data)
. quietly regress mpg weight
. local rsqf e(r2)
. local rsqv = e(r2)
. di `rsqf' // this has the current R-squared
.65153125
. di `rsqv' // as does this
.65153125
. quietly regress mpg weight foreign
. di `rsqf' // the formula has the new R-squared
.66270291
. di `rsqv' // this guy has the old one
.65153125
當(dāng)你僅僅是想存儲文本信息是也可以使用等號薄货,但我并不推薦翁都,尤其當(dāng)你使用的是舊版Stata時碍论,會帶來不必要的麻煩谅猾。以local controls = "age agesq education income"
為例,使用等號不影響正常工作鳍悠,但會使右引號左邊內(nèi)容被Stata計算税娜,并被標(biāo)記為字符串格式——最多輸入244個字符,而正常宏文本可輸入更多內(nèi)容藏研。
3.1.3 全局宏與鍵盤映射
全局宏名稱最多可包含32個字符敬矩,正如名稱所示,它具有全局范圍蠢挡。
你可以定義一個全局宏弧岳,global name [=] text
并使用$name
進(jìn)行計算。(你可能需要用${name}
限定名稱的結(jié)尾)
我建議你避免使用全局宏业踏,因?yàn)榇嬖诿Q沖突的可能性禽炬。一個有用的應(yīng)用是使用鍵盤上的功能鍵映射。如果你在一個名字很長的共享網(wǎng)絡(luò)文件夾上工作勤家,請嘗試
global F5 \\server\shared\research\project\subproject\
當(dāng)你打F5時腹尖,Stata會替換全名。而你的do files可以使用命令do${F5}dofile
(我們需要大括號來表明宏名稱是F5伐脖,而不是F5dofile
)
顯然你不想在每次使用Stata時輸入這個宏热幔,你可以將其輸入到你的profile.do
文件——每次運(yùn)行Stata時執(zhí)行的一組命令。通常情況下讼庇,你的個人配置文件最好存儲在Stata的啟動目錄C:\data
中绎巨。help profilew
了解更多信息。
3.1.4 關(guān)于宏的更多信息
宏也可用于使用擴(kuò)展宏函數(shù)獲取和存儲關(guān)于系統(tǒng)或數(shù)據(jù)集中變量的信息蠕啄。例如场勤,你可以檢索變量和值標(biāo)簽。還有一些命令可以管理你的宏集合,包括macro list
和macro drop
却嗡,help macro
了解更多信息舶沛。
3.2 循環(huán)
循環(huán)用于完成重復(fù)性任務(wù)。Stata的命令允許循環(huán)遍歷數(shù)字序列和包括變量列表在內(nèi)的各種類型列表窗价。在我們開始之前如庭,不要忘記Stata自己做了很多循環(huán)。如果你想計算收入的對數(shù)撼港,你可以在Stata中用一行代碼來實(shí)現(xiàn):
gen logincome = log(income)
這行代碼隱晦地在所有觀測值上循環(huán)坪它,計算每個收入的對數(shù),又稱為矢量化操作帝牡。你可以自己編寫循環(huán)往毡,但是沒有必要。第一靶溜,你不需要开瞭;第二,你的代碼會比Stata內(nèi)置循環(huán)慢很多
3.2.1 遍歷數(shù)字序列循環(huán)
基本的循環(huán)命令采用這種形式
forvalues number = sequence {
... body of loop using `number' ...
}
這forvalues
是一個關(guān)鍵字罩息,number
是一個本地宏的名稱嗤详,它將被設(shè)置為序列中的每個數(shù)字,sequence
是一個如下形式的數(shù)值范圍
-
min/max
:從min
到max
以1為步長的數(shù)字序列瓷炮,例如1/3
產(chǎn)生1,2和 3 -
first(step)last
:從first
到last
以step
為步長依次排列的數(shù)字序列例如15(5)50為15,20,25,30,35,40,45和50葱色。
(指定第二種序列的方法有兩種,這里列出的是最清晰的娘香,替代方案請參閱help forvalues
)
開頭的左大括號必須是第一行的最后一項(注釋除外)苍狰,并且循環(huán)必須以獨(dú)立成行的右大括號結(jié)束。循環(huán)會對序列中的每個值執(zhí)行一次并將結(jié)果保存在本地宏number
(本例中宏名為number
)中烘绽。
創(chuàng)建虛擬變量
這是我最喜歡的創(chuàng)建年齡組虛擬變量的方式淋昭。雖然Stata 11引入了因子變量,Stata 13改進(jìn)了估算表格的標(biāo)簽诀姚,大大減少了“滾動自己的”虛擬變量的需求响牛,但代碼仍然具有啟發(fā)性。
forvalues bot = 20(5)45 {
local top = `bot' + 4
gen age`bot'to`top' = age >= `bot' & age <= `top'
}
這將創(chuàng)建一組虛擬變量age20to24
到age45to49
赫段。循環(huán)時呀打,本地宏bot
將以5為步長在20和45范圍內(nèi)取值表示年齡組的下限(即20,25,30,35,40和45)。
在循環(huán)內(nèi)部糯笙,我們創(chuàng)建一個本地宏top
來表示年齡段的上限贬丛,它等于下限加4。第一次循環(huán)中bot
是20给涕,所以top
是24.我們使用等號來存儲bot
加4的結(jié)果豺憔。
下一行是一個簡單的生成語句额获。第一次循環(huán)時語句會顯示gen age20to24 = age >= 20 & age <= 24
(你可以建立自己的宏來查看),這將創(chuàng)建第一個虛擬變量恭应,然后Stata將返回頂部創(chuàng)建下一個抄邀。
3.2.2遍歷列表中的元素
第二個循環(huán)命令是foreach
,它有六種風(fēng)格昼榛,以處理不同類型的列表境肾。我將從通用列表開始:
foreach item in a-list-of-things {
... body of loop using `item' ...
}
foreach
是一個關(guān)鍵字,item
是自己選擇的本地宏名稱胆屿,in
是另一個關(guān)鍵字奥喻,緊跟著是空格分隔的單詞。試試這個例子
foreach animal in cats and dogs {
display "`animal'"
}
由于本地宏animal
被設(shè)置為列表中的每個單詞非迹,因此該循環(huán)將輸出“貓”环鲤,“和”和**“狗” **。Stata不知道“和”不是一種動物憎兽,但即使這樣做冷离,它也不會在意,因?yàn)檫@個列表是通用的唇兑。
如果你想循環(huán)一個不規(guī)則的數(shù)字序列 - 例如你需要用Coale-Demeny區(qū)域模型生命表對第2,6和12級做一些事情 - 你可以編寫
foreach level in 2 6 12 {
... do something with `level' ...
}
這可能是你需要了解循環(huán)的全部內(nèi)容酒朵。
3.2.3 循環(huán)專用列表
foreach
還有其他五種變體桦锄,它們在特定類型的列表上循環(huán)扎附,我現(xiàn)在簡要介紹它們。
變量列表
也許是最有用的變體
foreach varname of varlist list-of-variables {
... body of loop using `varname' ...
}
這里foreach
结耀,of
和varlist
是關(guān)鍵字留夜,它們必須準(zhǔn)確輸入。list-of-variables
是一個存儲變量名字的列表图甜。你可以進(jìn)行適當(dāng)縮寫碍粥,比如使用類型變量的名稱var*
來指代以“var”
開頭的所有變量,或var1-var3
對變量var1
到var3
進(jìn)行引用黑毅。
這種循環(huán)的有點(diǎn)是foreach varname in list-of-variables
命令中Stata會檢查列表中的每個名稱是否確實(shí)是現(xiàn)有的變量嚼摩,并且可以縮寫或使用擴(kuò)展名稱。
如果你需要對新生成變量進(jìn)行循環(huán)矿瘦,使用命令foreach varname of newlist list-of-new-variables
枕面。關(guān)鍵字newlist
替換原有的varlist
,告訴Stata檢查列表中此前不存在的變量名稱缚去。
遍歷宏中詞匯
其他兩個變體循環(huán)遍歷本地或全局宏中的單詞潮秘,格式是分別使用關(guān)鍵字global
或local
,后跟宏名稱(代替列表名)易结。例如枕荞,這里有一種方法可以從本地宏中列出控制變量名稱:
foreach control of local controls {
display "`control'"
}
在數(shù)據(jù)集中我們可以使用foreach
和varlist
來實(shí)現(xiàn)相同目的柜候。
數(shù)字列表
Stata中有一個foreach
變體專門用于處理forvalues
無法處理的數(shù)字列表。
假設(shè)一項調(diào)查在1980年開始進(jìn)行躏精,并在1985年和1995跟進(jìn)渣刷。(在1990年雖然他們同樣希望跟進(jìn),但并未得到資助)矗烛,要對間隔不規(guī)則數(shù)字列表進(jìn)行循環(huán)飞主,你可以使用
foreach year of numlist 1980 1985 1995 {
display "`year'"
}
你可以做一些比打印年份名更有趣的事情,比如將numlist
指定為1 2 3或1/5((意思是1 2 3 4 5))高诺,或是1(2)7(從1到7以2為步長計數(shù)以得到1 3 5 7); 更多信息help numlist
碌识。
這個命令優(yōu)于優(yōu)點(diǎn)通用命令的地方是Stata會檢查數(shù)字列表中的每個元素是否為一個數(shù)字。
3.2.4 while循環(huán)
與許多編程語言一樣虱而,Stata也有一個while循環(huán)筏餐,它具有以下結(jié)構(gòu)
while condition {
... do something ...
}
條件是表達(dá)式。只要條件為真(非零)牡拇,循環(huán)就會執(zhí)行魁瞪。通常情況下,內(nèi)部循環(huán)時會有條件不滿足惠呼,否則代碼將永遠(yuǎn)運(yùn)行导俘。
while
循環(huán)一種典型用途是迭代估計,當(dāng)連續(xù)估計的差值大于預(yù)設(shè)的容差循環(huán)繼續(xù)進(jìn)行剔蹋。迭代計數(shù)通常用于檢測對象是否缺乏收斂性旅薄。
continue [,break]
命令將會中斷包括while
,forvalues
,foreach
在內(nèi)的所有循環(huán)。該命令將停止當(dāng)前迭代并繼續(xù)下一個迭代泣崩,除非已經(jīng)指定了break
少梁,否則將退出循環(huán)。
3.2.5 條件執(zhí)行
Stata的也有一個if
編程命令矫付,為了不與限定子集的限定符if
混淆(如summarize mpg if foreign
),該if
命令具有以下結(jié)構(gòu)
if expression {
... commands to be executed if expression is true ...
}
else {
... optional block to be executed if expression is false ...
}
這里if
和可選的else
是關(guān)鍵字凯沪,help exp
了解表達(dá)式信息。{
必須是一行中最后一項(注釋除外)买优,}
必須單獨(dú)成行妨马。
如果if
或else
部分由單個命令組成,便不需要大括號并且可以單獨(dú)成行杀赢,如if expression command
烘跺。但不可以使用括號情況下同行成列如if expression { command }
。你可以將代碼分成三行來使用大括號葵陵,這通常會提高代碼的可讀性液荸。
在這里我們設(shè)置一個簡單的循環(huán),在十次迭代的五次之后停止脱篙,
forvalues iter=1/10 {
display "`iter'"
if `iter' >= 5 continue, break
}
3.3 編寫命令
我們接下來的任務(wù)是編寫自己的Stata命令娇钱,跟隨我們開發(fā)幾個簡單的程序伤柄,一個用于標(biāo)注你的輸出( sign your output),另一個來評估Coale-McNeil模型的婚禮安排文搂,我們可以創(chuàng)建如下所示圖表:
3.3.1 無參數(shù)程序
讓我們開發(fā)一個命令适刀,以你的名字標(biāo)注你的輸出。開發(fā)一個命令最簡單的方法是從一個do文件開始煤蹭。啟動Stata的do-file編輯器(Ctrl+9)并輸入:
capture program drop sign
program define sign
version 9.1
display as text "Germán Rodríguez "
display "{txt}{hline 62}"
end
如果你現(xiàn)在輸入sign
,Stata將使用文本樣式顯示簽名
的program drop
在需要改變do file
內(nèi)容或重新運(yùn)行該文件時使用笔喉,類似于數(shù)據(jù)集中的clear
命令。因?yàn)槟悴荒芏x一個已經(jīng)存在的程序硝皂。在一次使用時需要capture
常挚,此時沒有什么程序需要刪除。
version 9.1
表明該命令是為Stata版本9.1開發(fā)的稽物,可以幫助未來版本的Stata正確運(yùn)行它,即使語法在此期間發(fā)生了變化奄毡。
最后一行使用了一些SMCL
(Stata Markup Control Language),發(fā)音為“smickle”贝或,Stata標(biāo)記控制語言是Stata輸出處理器的名稱吼过。SMCL
使用純文本結(jié)合大括號中。例如咪奖,{txt}
將顯示模式設(shè)置為文本盗忱,{hline 62}
繪制一個寬度為62個字符的水平線。了解更多關(guān)于SMCL類型的信息help smcl
羊赵。
3.3.2 有參數(shù)的程序
為了制作有用的程序趟佃,你經(jīng)常需要在命令后面輸入?yún)?shù)以傳遞信息給它們。讓我們寫一個能夠回應(yīng)你所說的話的命令:
capture program drop echo
program define echo
version 9.1
display as text "`0'"
end
嘗試輸入echo Programming Stata Tutorial
看看會發(fā)生什么慷垮。
當(dāng)你調(diào)用echo
命令時揖闸,Stata將參數(shù)存儲在名為0
的本地宏中,并且用display
命令將宏結(jié)果以文本呈現(xiàn)料身,由于是文本,所以帶上雙引號衩茸。(假如你輸入echo Hi
芹血,本地宏0
由空白變?yōu)?code>Hi,命令會讀取display Hi
,此時stata會報錯無法找到Hi
命令楞慈,我們希望命令讀取`display “Hi”,因此為宏添加引號)
如果我們沒有指定任何內(nèi)容幔烛,則本地宏0
將是一個空字符串,該命令將讀取display ""
并且Stata將打印一個空行囊蓝。
3.3.3 復(fù)合引號
在慶祝之前饿悬,我們需要解決新命令的一個小問題。輸入echo The hopefully "final" run
,Stata會報錯聚霜。為什么呢狡恬?因?yàn)?"final"
中含有引號在讀取命令顯示為:
display "The hopefully "final" run"
Stata理解的則是 “The hopefully” final “run”
珠叔,兩個引號包圍的詞夾著沒有引號的final
,這在Stata看來是一句無效表達(dá)弟劲。顯然我們需要一些方法來區(qū)分內(nèi)部和外部引用祷安。
順便提一句,你可以通過set trace on
命令看到Stata執(zhí)行的整個過程(如下所示)兔乞。完成后別忘了輸入set trace off
汇鞭。help trace
以了解更多信息。
echo The hopefully "final" run
---------------------------------------------------------------- begin echo ---
- version 9.1
- display as text "`0'"
= display as text "The hopefully "final" run"
The hopefully final" run" invalid name
------------------------------------------------------------------ end echo ---
r(198);
那么問題該如何解決呢庸追?答案是使用Stata的復(fù)合引號:
`"
開始霍骄," '
結(jié)束,例如`"compound quotes"'
淡溯。由于打開和關(guān)閉符號不同腕巡,這些引號可以嵌套。復(fù)合引號可以在任何使用雙引號的地方使用血筑。如果引用的文本包含雙引號绘沉,則必須使用復(fù)合引號。
所以我們的最終版本是display "`0'"
豺总。
program define echo
version 9.1
if `"`0'"' != "" display as text `"`0'"'
end
你會注意到我刪去了capture drop line
這是因?yàn)槲覀儸F(xiàn)在準(zhǔn)備將程序保存為ado
文件车伞。輸入sysdir
以找出您的個人ado
目錄位置,然后將文件保存為echo.ado
∮髟現(xiàn)在你可以在任意時刻調(diào)用該命令另玖。
(ps,如果要確認(rèn)新建命令沒有和官方命令重名表伦,輸入which echo.Stata
,得到回復(fù)file echo.Stata not allowable filetype
即可)
3.3.4 位置參數(shù)
Stata除了將所有參數(shù)一起存儲在本地宏0
谦去,還會把參數(shù)的文本分別存儲在本地宏'1','2','3'等等之中(使用參數(shù)作為分隔符),并在這些宏中對解析參數(shù)蹦哼。
通常你會先解析宏`1'
然后轉(zhuǎn)向下一個鳄哭。這時mac shift
命令會派上用場,因?yàn)樗鼘⑺械暮甓枷蛳乱苿右粋€纲熏,所以現(xiàn)在2的內(nèi)容在1妆丘,3的內(nèi)容在2等等。這樣局劲,你只需一直對宏1
處理即可勺拣,直到列表耗盡時1
內(nèi)容為空,你的工作就完成了鱼填。
下是顯示參數(shù)內(nèi)容的規(guī)范程序:
capture program drop echo
program define echo
version 9.1
while "`1'" != "" {
display `"`1'"'
mac shift
}
end
不要忘記mac shift
药有,否則你的程序可能會永遠(yuǎn)運(yùn)行。(或者直到你按下break
)
嘗試echo one two three testing
和echo one "two and three" four
苹丸。體會如何通過使用引號將多個單詞分組為單個參數(shù)愤惰。
(ps:我們不僅可以將參數(shù)傳遞給命令苇经,還可以將其傳遞給do files,help do
以便了解更多信息羊苟。)
3.3.5 使用Stata語法
如果你使用標(biāo)準(zhǔn)的stata語句塑陵,你可以充分利用stata自己的解析器,它可以方便地將所有元素存儲在本地宏中供你使用蜡励,不過一個標(biāo)準(zhǔn)的stata語句意味你的參數(shù)必須是一個變量列表令花,或是權(quán)重,if
/in
子句凉倚,或是一堆選項中的一種或多種兼都。
一個命令原型
讓我們編寫一個命令,用一個給定的均值稽寒,標(biāo)準(zhǔn)差和結(jié)婚比例的Coale-McNeil模型計算一定年齡段的結(jié)婚概率扮碧。我們設(shè)計的使用語法是:
pnupt age, generate(married) [ mean(25) stdev(5) pem(1)]
對照語法,我們需要包含確切年齡數(shù)據(jù)的年齡變量杏糙,以及一個必須選項——在給定結(jié)婚比例時生成一個新變量慎王。還有一些可選選項指定平均值,標(biāo)準(zhǔn)差和結(jié)婚比例宏侍,當(dāng)然這些都預(yù)設(shè)有默認(rèn)值赖淤。
因此,我們需要一個具有確切年份的年齡的現(xiàn)有變量谅河,以及一個強(qiáng)制選項咱旱,指定一個以已婚比例生成的新變量。還有一些選項可以指定時間表中的平均值绷耍,標(biāo)準(zhǔn)偏差和結(jié)婚比例吐限,所有這些都有默認(rèn)值。這是命令的第一步
capture program drop pnupt
program define pnupt
version 9.1
syntax varname, Generate(name) ///
[ Mean(real 25) Stdev(real 5) Pem(real 1) ]
// ... we don't do anything yet ...
end
首先要注意的是褂始,該syntax
命令看起來非常像我們的原型诸典。
變量列表
在我們的語法中的第一個元素是一個變量列表varlist
。你可以指定最小值和最大值病袄,例如一個需要兩個變量的程序varlist(min=2 max=2)
搂赋。當(dāng)我們只有一個變量時,可以輸入varname
益缠,這是varlist(min=1 max=1)
的簡稱。
然后基公,Stata將確保您的程序調(diào)用時使用的是一個現(xiàn)有變量的名稱幅慌,該變量將被存儲在名為varlist
的本地宏中。(t即使你只有一個變量并在你的語法語句中使用varname
轰豆,宏名依然是varlis
)嘗試pnupt nonesuch
,Stata會抱錯胰伍,說“variable nonesuch not found”齿诞。
(如果你之前有過編程經(jīng)驗(yàn),并且花費(fèi)大部分時間用于檢查輸入錯誤骂租,僅少部分真正用于手頭任務(wù)祷杈,你將會非常喜歡syntax
,因?yàn)樗鼮槟銏?zhí)行了很多錯誤檢查)
選項和默認(rèn)值
可選語法元素包含在方括號[]中渗饮。在我們的命令中但汞,generate
選項是必需的,其他三個是可選的互站。嘗試使用這些命令生成一個范圍在15到50的年齡變量小測試數(shù)據(jù)集
drop _all
set obs 36
gen age = 14 + _n
現(xiàn)在嘗試pnupt age
私蕾。這次Stata并未對age
變量報錯,但提示 'option generate() required'胡桃。帶參數(shù)的選項需要指定參數(shù)類型(integer踩叭,real,string翠胰,name)和默認(rèn)(不強(qiáng)制)值容贝。generate
需要一個name
,沒有默認(rèn)值之景。嘗試pnupt age, gen(2)
斤富。Stata會抱怨說2不是一個變量名。
正常情況下闺兢,選項的內(nèi)容將存儲在與選項同名的本地宏中茂缚。
檢查參數(shù)
現(xiàn)在我們需要做一些工作來檢查名稱是否是一個有效的變量名稱,我們使用confirm
:
confirm new variable `generate'
然后Stata檢查你是否可以生成這個變量屋谭,如果不行脚囊,則發(fā)出錯誤110.嘗試pnupt age, gen(age)
,Stata會說 'age already defined'。
現(xiàn)在你應(yīng)該清楚桐磁,stata會檢查均值悔耘,標(biāo)準(zhǔn)差和結(jié)婚比例這三個選項是否有指定數(shù)值(縮寫為m()
,s()
和p()
)我擂,這些值必須是實(shí)數(shù)衬以,并將被存儲在名為mean
, stdev
, 和pem
的本地宏中。
你可以對輸入做更多的檢查校摩。讓我們快速檢查所有三個參數(shù)是負(fù)數(shù)看峻,其中比例不能大于1。
if (`mean' <= 0 | `stdev' <= 0 | `pem' <= 0 | `pem' > 1) {
di as error "invalid parameters"
exit 110
}
你可能希望對每個參數(shù)進(jìn)行單獨(dú)檢查衙吩,這正是接下來我們要做的互妓。
臨時變量
我們現(xiàn)在準(zhǔn)備利用Coale-McNeil模型和伽瑪分布之間的關(guān)系做一些計算,下面是該程序的工作版本
program define pnupt
*! Coale-McNeil cumulative nuptiality schedule v1 GR 24-Feb-06
version 9.1
syntax varname, Generate(name) [Mean(real 25) Stdev(real 5) Pem(real 1)]
confirm new var `generate'
if `mean' <= 0 | `stdev' <= 0 | `pem' <= 0 | `pem' > 1 {
display as error "invalid parameters"
exit 198
}
tempname z g
gen `z' = (`varlist' - `mean')/`stdev'
gen `g' = gammap(0.604, exp(-1.896 * (`z' + 0.805)))
gen `generate' = `pem' * (1 - `g')
end
我們可以將概率公式一行寫出,但這會犧牲可讀性冯勉。相反澈蚌,我們先對年齡變量進(jìn)行標(biāo)準(zhǔn)化,只是我們該如何稱呼這個新變量呢灼狰?你或許會叫它z
,這當(dāng)然可以宛瞄。只是如果你命令的用戶恰巧有一個變量叫z
該怎么辦呢?當(dāng)我們計算伽瑪函數(shù)后交胚,我們又應(yīng)該如何命令稱呼結(jié)果呢份汗?
上述問題的答案是tempname
命令,該命令使stata生成唯一的臨時變量名承绸,本例中兩個變量名會分別被存儲在本地宏z
和g
中裸影。由于這些宏是本地的,因此不存在名稱沖突的問題军熏。臨時變量的另一個特點(diǎn)是當(dāng)程序結(jié)束時它們會自動消失轩猩,所有工作stata會自動替你做好。
gen `z' = (`varlist' - `mean')/`stdev'
這行代碼乍一看會有些奇怪荡澎,但請記住我們所有感興趣的量現(xiàn)在都存儲在本地宏中均践,我們調(diào)用時必須先對宏解析:z'獲取我們臨時變量的名稱,
varlist'獲取用戶指定的年齡變量的名稱摩幔,mean'獲取平均值彤委,
stdev'得到標(biāo)準(zhǔn)差的值。在宏代換之后或衡,這行代碼會讀取類似的內(nèi)容gen _000001 = (age-22.44)/5.28
焦影,這可能會更有意義。
if/in
你可能在考慮允許用戶在命令中指定if
和in
條件封断,這需要添加到syntax
中斯辰,它們將被存儲在本地宏中,然后你可以在計算中使用它們坡疼,在這種情況下傳遞給生成彬呻。
有關(guān)此主題類型的更詳細(xì)的討論help syntax
3.3.6創(chuàng)建新變量
有時你編寫的命令會創(chuàng)建一個新的變量。事實(shí)上柄瑰,這就是我們的小命令所做的闸氮。如果我們可以使用egen
像這樣的一種命令輸入形式會非常方便:
egen married = pnupt(age), mean(22.48) stdev(5.29) pem(0.858)
答案是肯定的。因?yàn)?code>egen是用戶可擴(kuò)展的教沾。要實(shí)現(xiàn)一個名為pnupt
的函數(shù)蒲跨,你必須創(chuàng)建一個程序(do files )的_gpnupt,換句話說就是添加前綴_g
授翻。關(guān)于egen
擴(kuò)展的文檔有點(diǎn)稀少财骨,但一旦你知道了這個基本事實(shí)镐作,你只需要查看egen
命令的源文件并復(fù)制即可藏姐。
所以這里是我們的Coale-McNeil命令版本的egen
隆箩。
program define _gpnupt
*! Coale-McNeil cumulative nuptiality schedule v1 GR 24-Feb-06
version 9.1
syntax newvarname=/exp [, Mean(real 25) Stdev(real 5) Pem(real 1)]
if `mean' <= 0 | `stdev' <= 0 | `pem' <= 0 | `pem' > 1 {
display as error "invalid parameters"
exit 198
}
tempname z g
gen `z' = (`exp' - `mean')/`stdev'
gen `g' = gammap(0.604, exp(-1.896 * (`z' + 0.805)))
gen `typlist' `varlist' = `pem' * (1 - `g')
end
這個版本和上一個之間的差異很小,主要體現(xiàn)在egen
接受表達(dá)式輸入而不是單單變量輸入.輸入?yún)?shù)會被解析并存儲在一個名為exp
的臨時變量中羔杨。輸出變量被指定為varlist
捌臊,在本例中為newvarname
。這就是為什么z
現(xiàn)在與exp
和gen
產(chǎn)生varlist
兜材。typlist
的存在是因?yàn)?code>egen可以讓你指定輸出變量的類型(默認(rèn)情況下為float)并傳遞給我們的函數(shù)理澎,函數(shù)再將它傳遞給gen
。
3.3.7 Coale-McNeil 擬合
我們準(zhǔn)備揭示最初的圖形是如何制作的曙寡。這些數(shù)據(jù)可以在我網(wǎng)站的人口統(tǒng)計部分的Stata文件中找到糠爬,數(shù)據(jù)包括已婚和單身女性的年齡。我們將計算觀察到的已婚比例举庶,根據(jù)Rodríguez和Trussell(1980)的估計值計算擬合值执隧,并繪制結(jié)果圖。這一切只需幾行代碼即可完成户侥。
use http://data.princeton.edu/eco572/datasets/cohhnupt
gen obs = ever/total
egen fit = pnupt(age+0.5), mean(22.44) stdev(5.28) pem(.858)
gen agem = age + 0.5
twoway (scatter obs agem) (line fit agem), ///
title(Proportions Married by Age) subtitle(Colombia 1976) ///
ytitle(Proportion married) xtitle(age)
3.4其他主題
由于缺乏時間和篇幅镀琉,我還沒有討論程序返回值,help return
了解更多信息蕊唐。對于可以發(fā)布估計結(jié)果的估計命令的相關(guān)主題屋摔,請參閱help ereturn
和help _estimates
。關(guān)于估計的重要參考是Maximum Likelihood Estimation with Stata, Fourth Edition, by Gould, Pitblado and Poi (2010).替梨。
其他有趣的主題還有矩陣(help matrix
)钓试,對于輸出更深入的討論需要了解更多SMCL的信息(help smcl
)。對于圖形工作副瀑,你可能想要學(xué)習(xí)類的編程(help class
)并學(xué)習(xí)sersets(help serset
)弓熏。為你的命令提供一個圖形用戶界面help dialog programming
。
[參考]: RodríguezG.和Trussell TJ(1980);測量數(shù)據(jù)對Coale模型婚姻調(diào)度參數(shù)的最大似然估計;世界生育率調(diào)查技術(shù)公告