普林斯頓stata教程之stata編程


這部分是對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年分為一組始花,從age15to19age45to49共分為七組妄讯。其中有六組會作為虛擬變量在回歸中使用。定義一個宏

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 listmacro 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:從minmax以1為步長的數(shù)字序列瓷炮,例如1/3產(chǎn)生1,2和 3
  • first(step)last:從firstlaststep為步長依次排列的數(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)建一組虛擬變量age20to24age45to49赫段。循環(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结耀,ofvarlist是關(guān)鍵字留夜,它們必須準(zhǔn)確輸入。list-of-variables是一個存儲變量名字的列表图甜。你可以進(jìn)行適當(dāng)縮寫碍粥,比如使用類型變量的名稱var*來指代以“var”開頭的所有變量,或var1-var3對變量var1var3進(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)鍵字globallocal,后跟宏名稱(代替列表名)易结。例如枕荞,這里有一種方法可以從本地宏中列出控制變量名稱

foreach control of local controls {
    display "`control'"
}

在數(shù)據(jù)集中我們可以使用foreachvarlist來實(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ú)成行妨马。

如果ifelse部分由單個命令組成,便不需要大括號并且可以單獨(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”,因此為宏添加引號)

echo程序

如果我們沒有指定任何內(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 testingecho 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生成唯一的臨時變量名承绸,本例中兩個變量名會分別被存儲在本地宏zg中裸影。由于這些宏是本地的,因此不存在名稱沖突的問題军熏。臨時變量的另一個特點(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

你可能在考慮允許用戶在命令中指定ifin條件封断,這需要添加到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)在與expgen產(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 ereturnhelp _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ù)公告

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俗扇,一起剝皮案震驚了整個濱河市硝烂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铜幽,老刑警劉巖滞谢,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異除抛,居然都是意外死亡狮杨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門到忽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來橄教,“玉大人清寇,你說我怎么就攤上這事』さ” “怎么了华烟?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長持灰。 經(jīng)常有香客問我盔夜,道長,這世上最難降的妖魔是什么堤魁? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任喂链,我火速辦了婚禮,結(jié)果婚禮上妥泉,老公的妹妹穿的比我還像新娘椭微。我一直安慰自己,他們只是感情好盲链,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布蝇率。 她就那樣靜靜地躺著,像睡著了一般匈仗。 火紅的嫁衣襯著肌膚如雪瓢剿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天悠轩,我揣著相機(jī)與錄音间狂,去河邊找鬼。 笑死火架,一個胖子當(dāng)著我的面吹牛鉴象,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播何鸡,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纺弊,長吁一口氣:“原來是場噩夢啊……” “哼科雳!你這毒婦竟也來了欠雌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤棺牧,失蹤者是張志新(化名)和其女友劉穎隔盛,沒想到半個月后犹菱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吮炕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年腊脱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片龙亲。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡陕凹,死狀恐怖悍抑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杜耙,我是刑警寧澤搜骡,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站泥技,受9級特大地震影響浆兰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜珊豹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望榕订。 院中可真熱鬧店茶,春花似錦、人聲如沸劫恒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽两嘴。三九已至丛楚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間憔辫,已是汗流浹背趣些。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贰您,地道東北人坏平。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像锦亦,于是被迫代替她去往敵國和親舶替。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理杠园,服務(wù)發(fā)現(xiàn)顾瞪,斷路器,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 作者:謝作翰 | 連玉君 | (知乎 | 簡書 | 碼云) 1.1 數(shù)據(jù)讀取1.1.1 自由格式數(shù)據(jù)1.1.2 固...
    謝作翰閱讀 765評論 0 0
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,381評論 0 5
  • 我好喜歡我的姑娘!!她所有可愛的一面只展示給我!!我覺得我是最幸福的人!!
    孤獨(dú)工廠閱讀 82評論 0 1
  • 端午紀(jì)念屈原賦 作者:老鄒 序文: 屈原抛蚁,戰(zhàn)國晚期楚國人陈醒,官至大夫。因主張抵御秦國侵略篮绿,不合君意孵延,兩...
    古槳閱讀 464評論 0 1