【Stata 18新功能】從數(shù)據(jù)集到框架集和別名變量:Stata的數(shù)據(jù)管理進(jìn)展
作者:Kreshna Gopal, Principal Computer Scientist and Software Developer

導(dǎo)讀
本文的目的是描述Stata 18(2023年發(fā)布)中引入的兩個(gè)新功能:1. framesets(框架集) 和 2. 別名變量 across frames。這些功能使Stata能夠高效、方便地處理大量潛在的非常大的數(shù)據(jù)集。framesets允許您捆綁、保存文件并在內(nèi)存中加載一組包含數(shù)據(jù)集的相關(guān)框架。Alias變量只需很少的內(nèi)存就能允許您訪問其他幀中的變量,就好像它們是當(dāng)前幀的一部分一樣。
Stata中的數(shù)據(jù)管理
1985年Stata 1.0發(fā)布時(shí),數(shù)據(jù)以表格形式組織為觀測(cè)值(行)和變量(列),稱為數(shù)據(jù)集。數(shù)據(jù)集完全保存在內(nèi)存中(然后以KB為單位),并作為.dta文件保存在磁盤上。數(shù)據(jù)類型,如整數(shù)、實(shí)數(shù),尤其是字符串,都是經(jīng)過節(jié)儉管理的。最初的44個(gè)命令大多用于數(shù)據(jù)管理,包括仍然不可避免的生成、替換和列表。這個(gè)底層框架仍然是隨后的17個(gè)版本Stata的基石:數(shù)據(jù)集仍然作為表完全保存在內(nèi)存中,使用強(qiáng)類型語言來處理數(shù)據(jù)。這使得Stata速度很快,并允許在幾毫秒內(nèi)處理數(shù)十億次觀測(cè)。然而,對(duì)于非常大的數(shù)據(jù)集,將整個(gè)數(shù)據(jù)集保存在內(nèi)存中是有限制的。盡管如此,利用經(jīng)濟(jì)實(shí)惠的內(nèi)存的驚人增長(zhǎng),Stata的數(shù)據(jù)管理功能不斷變得更大、更強(qiáng)、更快。
在本文中,作者討論了處理大型數(shù)據(jù)集的新功能,即幀、幀集和別名變量。作者將在接下來的三節(jié)中詳細(xì)介紹這些功能。在本文末尾的附錄中,作者概述了Stata的數(shù)據(jù)管理能力是如何隨著時(shí)間的推移而增長(zhǎng)的。
Frames:用于多個(gè)數(shù)據(jù)集的框架
對(duì)于龐大而復(fù)雜的數(shù)據(jù),通常需要同時(shí)處理多個(gè)可能巨大的數(shù)據(jù)集。您可能想要多任務(wù)處理,并使用各種項(xiàng)目的各種數(shù)據(jù)集?;蛘撸赡苷谑褂靡唤M相關(guān)的數(shù)據(jù)集,并希望整合它們之間的統(tǒng)計(jì)數(shù)據(jù)。有一些Stata命令,如?preserve?和?restore,使您能夠從一個(gè)數(shù)據(jù)集切換到另一個(gè)數(shù)據(jù)集中。但這些都需要一些謹(jǐn)慎的編碼,并且在將數(shù)據(jù)集保存到磁盤和從磁盤恢復(fù)數(shù)據(jù)集時(shí)會(huì)帶來時(shí)間損失。
在Stata 16(2019)中,引入了一種用于處理多個(gè)數(shù)據(jù)集的新框架:frames。多個(gè)數(shù)據(jù)集可以在多個(gè)幀中保存在內(nèi)存中。例如,以下是如何創(chuàng)建具有幀創(chuàng)建的幀,使該幀成為具有幀更改的當(dāng)前(工作)幀,并將數(shù)據(jù)集加載到其中:
. frame create auto
. frame change auto
. sysuse auto
(1978 automobile data)
可以復(fù)制框架并重命名框架:
. frame copy auto auto1
. frame rename auto1 cars
數(shù)據(jù)集和包含它們的幀的名稱可能不同。此外,即使內(nèi)存中有多個(gè)幀,也可以一次交互處理一個(gè)幀(當(dāng)前幀)。您可以使用pwf(打印工作框架)識(shí)別當(dāng)前框架:
. pwf
?(current frame is auto)
默認(rèn)情況下,始終使用當(dāng)前幀。也就是說,幀前綴功能允許您在當(dāng)前幀之外的幀上運(yùn)行命令。例如,您可以在 frame?cars?中生成一個(gè)新變量,例如?newvar(此處為隨機(jī)值):
. frame cars: generate newvar = runiform()
也可以使用?frlink?在當(dāng)前幀和另一幀之間創(chuàng)建鏈接。例如,可以通過匹配變量?make(保持汽車品牌)上的觀察結(jié)果,在當(dāng)前車架汽車和車架汽車之間創(chuàng)建一對(duì)一鏈接(通過指定1:1):
. frlink 1:1 make, frame(cars)
(all observations in frame auto matched)
您可以通過?frame drop?來刪除幀(如果不是當(dāng)前幀):
. frame drop cars
您可以使用 reset frames:
. frames reset
這會(huì)將Stata重置為內(nèi)存中只有一個(gè)空幀的狀態(tài)。
你可以用框架做更多的事情:用 frame put 復(fù)制數(shù)據(jù)變量和觀測(cè),用frame post添加新的觀測(cè),等等。
請(qǐng)注意,與 frame 和 frames 相關(guān)的命令的工作方式與鍵入框架或框架完全相同;它們是同義詞。
Stata最多支持100幀。就像單個(gè)數(shù)據(jù)集一樣,所有幀都完全保存在內(nèi)存中。這使得使用框架的速度也非常快。但它假設(shè)您可以在內(nèi)存中擬合所有幀數(shù)據(jù),這是Stata 18中兩個(gè)新功能的驅(qū)動(dòng)因素。
Stata 18新增功能:Framesets
Stata 18 添加了 frame 概念的自然演變:用戶現(xiàn)在可以以高效內(nèi)存的方式在磁盤上保存一組 frame 。為 framesets 引入了一種新的數(shù)據(jù)文件格式:.dtas,.dta的復(fù)數(shù)。
例如,讓我們創(chuàng)建三個(gè) frame ,并將三個(gè)不同的數(shù)據(jù)集(與預(yù)期壽命有關(guān))加載到其中:
. frame create life0
. frame create life1
. frame create life2
. frame life0: sysuse lifeexp
(Life expectancy, 1998)
. frame life1: sysuse uslifeexp
(U.S. life expectancy, 1900-1999)
. frame life2: sysuse uslifeexp2
(U.S. life expectancy, 1900-1940)
您可以使用將這三個(gè) frame 保存在一個(gè)幀集文件中,例如?life.dtas
. frames save life, frames(life0 life1 life2)
file life.dtas saved
您可以稍后重置或清除所有 frame ,并使用加載?life.dtas?中保存的 frame
. frames reset
. frames use life
?life0 ?68 x 6; Life expectancy, 1998
?life1 ?100 x 10; U.S. life expectancy, 1900-1999
?life2 ?41 x 2; U.S. life expectancy, 1900-1940
使用一組 frame 時(shí),必須考慮許多因素。例如,如果要從磁盤加載的 frame 與內(nèi)存中的 frame 名稱相同,該怎么辦?加載 frameset 時(shí),哪個(gè) frame 成為當(dāng)前 frame ?如果您嘗試加載一個(gè)以前鏈接的 frame ,但該 frame 已不存在,該怎么辦?
作者提供了?frames-describe,它對(duì)內(nèi)存和磁盤中的 frame 及其所包含的變量進(jìn)行了評(píng)估。例如,下面給出了 frameset?life.dtas?中 frame 的(簡(jiǎn)短)描述:
. frames describe using life, short
-------------------------------------------------------------------------------
Frame: life0
Contains data ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Life expectancy, 1998
Observations: ? ? ? ? ? ?68 ? ? ? ? ? ? ? ? ?26 Aug 2023 20:06
? ?Variables: ? ? ? ? ? ? 6
Sorted by:
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Frame: life1
Contains data ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? U.S. life expectancy, 1900-1999
Observations: ? ? ? ? ? 100 ? ? ? ? ? ? ? ? ?26 Aug 2023 20:06
? ?Variables: ? ? ? ? ? ?10
Sorted by: year
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Frame: life2
Contains data ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? U.S. life expectancy, 1900-1940
Observations: ? ? ? ? ? ?41 ? ? ? ? ? ? ? ? ?26 Aug 2023 20:06
? ?Variables: ? ? ? ? ? ? 2
Sorted by: year
-------------------------------------------------------------------------------
Frameset 命令還存儲(chǔ)大量 r 結(jié)果,以跟蹤正在發(fā)生的事情,例如,正在保存或加載的 frame 的子集,每個(gè) frame 中的數(shù)據(jù)在內(nèi)存中是否發(fā)生了變化,等等。
與?.dta?文件一樣,Stata 提供?.dtas?文件的低級(jí)描述。help-dtas?提供了讀取和寫入其他軟件 .dtas 文件所需的所有詳細(xì)信息。
Frameset 命令的語法和選項(xiàng)很自然地遵循數(shù)據(jù)集命令的句法和選項(xiàng),如?save?(保存),?use?(使用), 和?describe?(描述)。例如,dataset 和 frameset 命令以相同的方式處理標(biāo)簽、空數(shù)據(jù)集、描述數(shù)據(jù)集的詳細(xì)程度等。
Stata 使用其原生的?zipfile?在?frames save?中壓縮幀集文件,并在?frames use?(幀使用)中?unzipfile?(解壓縮文件)。用戶可以指定幀保存的壓縮級(jí)別。這可以通過兩種方式完成:通過?complevel(#)選項(xiàng)或通過?set dtascomplevel#。# 是介于0和9之間的整數(shù)——0表示無壓縮,9表示最大壓縮。默認(rèn)值為1。例如,可以通過鍵入以下命令在具有最大壓縮的磁盤上保存和替換?life.dtas。
. frames save life, frames(life0 life1 life2) complevel(9) replace
file life.dtas saved
請(qǐng)注意,frames 和 framesets 是建立在數(shù)據(jù)集之上的。這意味著,如果 frames 和 framesets 對(duì)您沒有實(shí)際使用意義,您可以以與以前完全相同的方式繼續(xù)使用數(shù)據(jù)集。你可能需要知道的唯一一件事是,當(dāng)你使用一個(gè)數(shù)據(jù)集時(shí),它默認(rèn)會(huì)進(jìn)入一個(gè) frame——而這個(gè) frame 被命名為 default,這并不奇怪。在一天結(jié)束時(shí),即使使用 frame,也可以在任何給定時(shí)間交互式地使用一個(gè)數(shù)據(jù)集或一個(gè) frame。
Stata 18新增功能:Alias variables across frames(跨幀的別名變量)
在本節(jié)中,作者將描述如何使用別名變量以高效內(nèi)存的方式跨幀訪問變量。
不同 frame 中的兩個(gè)數(shù)據(jù)集可以通過具有匹配變量來關(guān)聯(lián)。如前所述,可以通過基于公共變量將當(dāng)前 frame 中的觀測(cè)值與相關(guān) frame 中的觀察值進(jìn)行匹配,將 frame 與?frlink?鏈接起來。
使用?frlink?創(chuàng)建鏈接后,可以使用?fralias-add?定義變量別名——引用 linked frames 中變量的名稱。
下面是添加別名變量的示例。首先,讓我們像上面那樣在內(nèi)存中設(shè)置 auto 和 cars frames。
. clear all
. frame create auto
. frame change auto
. sysuse auto
(1978 automobile data)
. frame copy auto cars
. frame cars: generate newvar = runiform()
. pwf
(current frame is auto)
這兩個(gè) frame 是相同的,除了添加到 cars 的變量?newvar。從當(dāng)前的框架?auto,您可以根據(jù)公共變量?make?創(chuàng)建與?car?的一對(duì)一鏈接:
. frlink 1:1 make, frame(cars)
(all observations in frame auto matched)
現(xiàn)在,可以在當(dāng)前 frame auto中創(chuàng)建一個(gè)別名變量,比如?newvar,以訪問汽車中的變量?newvar:
. fralias add newvar, from(cars)
(1 variable aliased from linked frame)
這里的別名變量與它所指向的變量同名,但可以不同。作者將在下一個(gè)示例中演示如何操作。
本質(zhì)上,fralias-add?定義了從 current frame 到 linked frames 中變量的引用。通過引用,您可以使用鏈接的變量,而無需在當(dāng)前框架中復(fù)制它們。這些引用占用的內(nèi)存很少;變量實(shí)際上只存儲(chǔ)在一個(gè) frame 或數(shù)據(jù)集中,但可以在不同的 frame 中使用。
以下是關(guān)于?frlink?的更多評(píng)論,fralias 是基于?frlink?的。使用 frlink 時(shí),會(huì)在當(dāng)前 frame 中創(chuàng)建一個(gè)新變量。它引用鏈接的 frame 。默認(rèn)情況下,新變量以鏈接的 frame 命名。但是使用?generate()選項(xiàng)可以生成不同的變量名。
此外,frlink?完成的觀測(cè)值與常見變量的匹配可以是一對(duì)一或多對(duì)一。更有用的是,frlink?還將處理不同 frame 中常見但名稱不同的變量。此外,frlink?可以在變量名中使用通配符*來匹配變量組。如果數(shù)據(jù)發(fā)生更改或幀被重命名,則可以使用?frlink rebuild?或通過刪除鏈接變量來刪除鏈接。
Fralias-add?創(chuàng)建的別名變量與數(shù)據(jù)集中的任何其他變量一樣處理,但需要注意的是,不允許更改其值。對(duì)于給定的別名變量,如果在其所在的 linked frames 中更改相應(yīng)變量的值,則在下次使用別名變量時(shí),更改后的值將自動(dòng)可用。因此,在一個(gè) frame 中改變變量就足夠了,并且這種變化反映在所有引用它們的框架中。
別名變量允許許多 frame 具有相同的變量,就好像它屬于所有 frame 一樣,但變量?jī)H存儲(chǔ)在一個(gè) frame 中。這樣可以避免創(chuàng)建重復(fù)的變量或使用諸如?merge?或?frget?之類的昂貴命令。例如,后者從具有大內(nèi)存占用的 linked frames 幀中復(fù)制變量,尤其是對(duì)于 double 和 string 等的數(shù)據(jù)類型。相比之下,別名變量只是內(nèi)存中的引用,具有較小的固定內(nèi)存占用。因此,使用別名變量可以節(jié)省內(nèi)存,并有助于將所有 frame 保存在內(nèi)存中,從而使 Stata 保持快速靈活。
Frameset 和別名變量示例
在本節(jié)中,作者將提供一個(gè)更完整的示例,并深入研究 framesets 和別名變量命令的其他功能。
假設(shè)你正在進(jìn)行一個(gè)關(guān)于美國(guó)得克薩斯州收入水平的項(xiàng)目,并希望分析個(gè)人和縣一級(jí)的數(shù)據(jù)(美國(guó)每個(gè)州都包括縣)。
您使用的是兩個(gè) Stata 數(shù)據(jù)集:persons.dta?和?txcounty.dta?。您可以在兩個(gè)幀中加載這兩個(gè)數(shù)據(jù)集,例如,persons?和?country,如下所示:
. clear all
. frame create persons
. frame change persons
. webuse persons
. frame create counties
. frame change counties
. webuse txcounty
(Median income in Texas counties)
您可以使用 frame 前綴來描述這兩個(gè) frame:
. frame persons: describe
Contains data from https://www.stata-press.com/data/r18/persons.dta
Observations: ? ? ? ? ? ?20
? ?Variables: ? ? ? ? ? ? 3 ? ? ? ? ? ? ? ? ?16 Apr 2022 13:36
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(_dta has notes)
----------------------------------------------------------------------
Variable ? ? ?Storage ? Display ? ?Value
? ?name ? ? ? ? type ? ?format ? ?label ? ? ?Variable label
----------------------------------------------------------------------
personid ? ? ? ?byte ? ?%9.0g ? ? ? ? ? ? ? ? Person ID
countyid ? ? ? ?byte ? ?%9.0g ? ? ? ? ? ? ? ? County ID
income ? ? ? ? ?float ? %9.0g ? ? ? ? ? ? ? ? Household income
----------------------------------------------------------------------
Sorted by:
. frame counties: describe
Contains data from https://www.stata-press.com/data/r18/txcounty.dta
Observations: ? ? ? ? ? ? 8 ? ? ? ? ? ? ? ? ?Median income in Texas counties
? ?Variables: ? ? ? ? ? ? 2 ? ? ? ? ? ? ? ? ?30 Dec 2022 06:13
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(_dta has notes)
-------------------------------------------------------------------------------
Variable ? ? ?Storage ? Display ? ?Value
? ?name ? ? ? ? type ? ?format ? ?label ? ? ?Variable label
-------------------------------------------------------------------------------
countyid ? ? ? ?byte ? ?%9.0g ? ? ?cty ? ? ? ?County ID
median_income ? float ? %9.0g ? ? ? ? ? ? ? ? Household median income
-------------------------------------------------------------------------------
Sorted by:
通過?clear all?以上內(nèi)容,我們自動(dòng)從一個(gè)名為?default?的空工作 frame 開始。然后,我們?cè)?default?的基礎(chǔ)上添加了兩個(gè) frame 。我們可以列出內(nèi)存中的 frame ,并用
. frames dir
?counties ?8 x 2; Median income in Texas counties
?default ? 0 x 0
?persons ? 20 x 3; persons.dta
. pwf
?(current frame is counties)
Counties?是當(dāng)前的 frame,因?yàn)檫@是我們更改為的最后一個(gè) frame。如果我們想與?persons?合作,我們必須更改為該 frame:
. frame change persons
由于?frames persons?和?counties?有共同的變量?countyid,我們可以使用 frlink 將當(dāng)前?frame person?鏈接到?frame county,基于?countyid。因?yàn)樵S多 person 屬于同一個(gè) county,所以這里的匹配是多對(duì)一(m:1):
. frlink m:1 countyid, frame(counties)
(all observations in frame persons matched)
匹配的變量不必具有相同的名稱。在這種情況下進(jìn)行鏈接是相當(dāng)直接的。
請(qǐng)注意,上面的?frlink?命令在?persons?中創(chuàng)建了一個(gè)新變量,并命名為?countries?。它以 frame linked 命名。選項(xiàng)?generate( )?本可以在 frlink 中用于創(chuàng)建不同的變量名。新變量的值與各縣的觀測(cè)值相匹配。
現(xiàn)在,您可以使用 frames save 來在磁盤上保存 frame persons 和所有其他鏈接到它的 frame ,方法是指定 linked 選項(xiàng);所有 frame 都保存在文件?myproject.dtas?中:
. frames save myproject, frames(persons) linked
file myproject.dtas saved
請(qǐng)注意,在這種情況下,只有 frame?counties?鏈接到當(dāng)前 frame,給定上面的?frlink?命令。因此,除了?persons?之外,counties?也保存在?myproject.dtas?中。
接下來,您可以重置內(nèi)存中的所有 frame,稍后提醒自己?myproject.dtas?中有什么?frames describe(我們使用選項(xiàng)?simple?進(jìn)行緊湊描述):
. frames reset
. frames describe using myproject, simple
--------------------------------------------
Frame: persons
personid ?countyid ?income ? ?counties
--------------------------------------------
--------------------------------------------
Frame: counties
countyid ? ? ? median_income
--------------------------------------------
您可以將保存在?myproject.dtas?中的所有 frames 一起加載到內(nèi)存中使用:
. frames use myproject, frames(_all)
?counties ?8 x 2; Median income in Texas counties
?persons ? 20 x 4
請(qǐng)注意,在這一點(diǎn)上,當(dāng)前 frame 是?default?的,正如?pwf?所揭示的:
. pwf
(current frame is default)
即使已經(jīng)在內(nèi)存中加載了兩個(gè) frames ,當(dāng)前 frame(本例中為 default frame)也不會(huì)隨著?frames use?而更改。要使用其中一個(gè)加載的 frame,例如?persons?,您必須明確將其指定為 working frame:
. frame change persons
接下來,您想將?persons?收入與該?counties?的收入中位數(shù)進(jìn)行比較。中等收入可用于框架?counties?。我們知道,根據(jù)上述?frlink?命令,?persons?與各?counties?有關(guān)聯(lián)。我們可以從當(dāng)前 frame(?persons?)中驗(yàn)證現(xiàn)有的聯(lián)系
. frlink dir
?(1 frlink variable found)
?-----------------------------------------------------------------------------
?counties created by frlink m:1 countyid, frame(counties)
?-----------------------------------------------------------------------------
?Note: Type "frlink describe varname" to find out more, including whether the
?variable is still valid.
要訪問?frame counties?中的變量median_income,可以添加一個(gè)別名變量,例如中位數(shù),以引用變量,如下所示:
. fralias add median = median_income, from(counties)
(1 variable aliased from linked frame)
可以使用描述別名變量
. fralias describe median
----------------------------------------------------
Alias ? ?Type ? ?Target ? ? ? ? ?Link ? ? ? Frame
----------------------------------------------------
median ? float ? median_income ? counties ? counties
----------------------------------------------------
現(xiàn)在,您可以在包含可變中位數(shù)的 frame?persons?中運(yùn)行分析。簡(jiǎn)單地說,在這里,你可以找到個(gè)人收入與相應(yīng)縣收入中值的比率:
. generate ratio = income/median
請(qǐng)注意,別名變量的?median?僅引用 counties 中的?median_income,這幾乎不消耗內(nèi)存。因此,您可以像處理 frame 的一部分一樣處理變量,只需很少的內(nèi)存開銷。但是你不能改變變量;它只能在 frame?countries中更改。變量中的任何更改都將在引用它的所有 frame 中可用。