2014-01-30 281 views
1

對不起,標題混淆。希望下面清楚。Stata - 根據變量中的值分配不同的變量

我正在使用Stata,我想將值1賦予一個取決於不同變量內的值的變量。我有20個命令變量和20個相應的變量。例如,如果order1 = 3,我想分配變量3 = 1.下面是最終數據集的樣子,如果我只有3個變量的話。

enter image description here
現在我有兩個迴路這樣做,但我必須解決這個另一個循環,通過這個9次進入加我已經這樣做了幾百個數據文件。我想讓它更有效率。

forvalues i = 1/20 { 
    forvalues j = 1/20 { 
    replace variable`j' = 1 if order`i'==`j' 
    } 
    } 

是否有可能使用order'i」的值直接分配變量[order`i'VALUE]?然後我可以擺脫上面的j循環。像這樣的東西。

forvalues i = 1/20 { 
    replace variable[`order`i'value] = 1 

    } 

感謝您的幫助!

***** CLARIFICATION ADD Feb Feb。** 我簡化了我的問題,並且數據集太多了,但解決方案建議爲我提供的工作提供了工作,但沒有得到我真正想要做的。儘管謝謝你的解決方案。我的帖子中我還不夠清楚。

爲了說明問題,我的數據沒有每個訂單的一一對應關係#分配變量#a 1(如果它沒有丟失)。例如,對於order1 = 3的第一個觀察,變量1不應該得到1,變量3應該得到1.我沒有在我的原始文章中包含的是,我實際上檢查其他條件來設置它等於1.

欲瞭解更多背景,我計算出生在不同年齡的母親的出生次序(第一個孩子,第二個孩子等)的婦女出生。所以在數據中,每一行都是女人,每個訂單#都是出生人數(order1 = 3,這是她的第三個孩子)。相應的變量#s是計數(變量#意味着女人有一個孩子的出生順序#)。我在帖子中提到,我這樣做了9次,我正在做5年齡組(15-19; 20-24等)。因此,當女性年齡在15-19歲時,第一組變量#將按順序排列;第二組變量#將是婦女20-24歲時的順序的出生次數。在此之後,我以不同的方式(按女性的教育,地理等)對這些數字進行了總結。

所以與其他迴路我做的是更多的東西像這樣

forvalues k = 1/9{ 
    forvalues i = 1/20 { 
    forvalues j = 1/20 { 
    replace variable`k'_`j' = 1 if order`i'==`j' & age`i'==`k' & birth_age`i'<36 
    } 
    } 
} 

不知道這是可能的,但我想簡化,所以我只能通過每個孩子一次需要週期,而無需通過循環出生命令並直接使用該值#以將正確的變量賦值1。因此,如果order1 = 3,並且該女人有特定年齡組的孩子,則分配變量[agegroup] [3] = 1;如果order1 = 2,則變量[agegroup] [2]應該得到1.

forvalues k=1/9{ 
    forvalues i = 1/20 { 
    replace variable`k'_[`order`i'value] = 1 if age`i'==`k' & birth_age`i'<36 
    } 
} 
+0

你只想要標記(與1的)非缺失觀察? –

+0

我想用1或0來標記所有的觀察值。所有缺少的順序#變量都會得到一個0(我已經將變量的初始值設置爲0,代碼未顯示在此處)。 – Michelle

+0

感謝您分享您的解決方案!我終於有機會密切關注這些帖子,並且過分簡化了我的問題。我已將編輯添加到我的原始帖子中以進行澄清。 – Michelle

回答

2

我會reshape兩次。首先reshapelong,然後條件variable!missing(order),然後reshape回到wide

* generate your data 
clear 
set obs 3 
forvalues i = 1/3 { 
    generate order`i' = . 
     local k = (3 - `i' + 1) 
     forvalues j = 1/`k' { 
      replace order`i' = (`k' - `j' + 1) if (_n == `j') 
     } 
} 
list 


*. list 
* 
*  +--------------------------+ 
*  | order1 order2 order3 | 
*  |--------------------------| 
* 1. |  3  2  1 | 
* 2. |  2  1  . | 
* 3. |  1  .  . | 
*  +--------------------------+ 

* I would rehsape to long, then back to wide 
generate id = _n 
reshape long order, i(id) 
generate variable = !missing(order) 
reshape wide order variable, i(id) j(_j) 
order order* variable* 
drop id 
list 


*. list 
* 
*  +-----------------------------------------------------------+ 
*  | order1 order2 order3 variab~1 variab~2 variab~3 | 
*  |-----------------------------------------------------------| 
* 1. |  3  2  1   1   1   1 | 
* 2. |  2  1  .   1   1   0 | 
* 3. |  1  .  .   1   0   0 | 
*  +-----------------------------------------------------------+ 
+0

謝謝,我會試試看看它是否會加速我的程序。 – Michelle

2

使用一個簡單的循環forvaluesgeneratemissing()是數量級比其他提出的解決方案更快(直到現在)。對於這個問題,只需要一個循環遍歷變量的完整列表,而不是兩個,就像在原始文章中一樣。下面的代碼顯示了這兩點。

*----------------- generate some data ---------------------- 

clear all 
set more off 

local numobs 60 

set obs `numobs' 

quietly { 
forvalues i = 1/`numobs' { 
    generate order`i' = . 
     local k = (`numobs' - `i' + 1) 
     forvalues j = 1/`k' { 
      replace order`i' = (`k' - `j' + 1) if (_n == `j') 
     } 
} 
} 

timer clear 

*------------- method 1 (gen + missing()) ------------------ 

timer on 1 

quietly { 
    forvalues i = 1/`numobs' { 
     generate variable`i' = !missing(order`i') 
    } 
} 

timer off 1 

* ----------- method 2 (reshape + missing()) --------------- 

drop variable* 

timer on 2 

quietly { 
    generate id = _n 
    reshape long order, i(id) 
    generate variable = !missing(order) 
    reshape wide order variable, i(id) j(_j) 
} 

timer off 2 

*--------------- method 3 (egen, rowmax()) ----------------- 

drop variable* 

timer on 3 

quietly { 
// loop over the order variables creating dummies 
forvalues v=1/`numobs' { 
    tab order`v', gen(var`v'_) 
} 


// loop over the domain of the order variables 
// (may need to change) 
forvalues l=1/`numobs' { 
    egen variable`l' = rmax(var*_`l') 
    drop var*_`l' 
} 
} 

timer off 3 

*----------------- method 4 (original post) ---------------- 

drop variable* 

timer on 4 

quietly { 
forvalues i = 1/`numobs' { 
    gen variable`i' = 0 

    forvalues j = 1/`numobs' { 
     replace variable`i' = 1 if order`i'==`j' 
    } 
} 
} 

timer off 4 

*----------------------------------------------------------- 

timer list 

的定時程序給

. timer list 
    1:  0.00/  1 =  0.0010 
    2:  0.30/  1 =  0.3000 
    3:  0.34/  1 =  0.3390 
    4:  0.07/  1 =  0.0700 

其中timer 1是簡單gentimer 2reshapetimer 3egen, rowmax(),並timer 4原來的崗位。

你只需要一個循環的原因是Stata的方法是從頂部(第一個觀察)到底部(最後一個觀察)對數據庫中的所有觀測值執行命令。例如,生成variable1,但根據order1是否丟失;這是針對兩個變量的所有觀察而完成的,沒有明確的循環。

我不知道你是否真的需要這樣做。對於未來的問題,如果你有進一步的目標,我認爲一個好的策略是在你的文章中提到它。

注意:我已經從其他海報的答案中重用了代碼。

+0

哇。感謝您的基準測試。我需要重溫我的口頭禪,「不惜一切代價避免循環」。 –

+0

當然@RichardHerron。 'reshape'是一個似乎涉及這項任務太多工作的程序。運行'viewsource reshape.ado'並檢查你自己。我認爲類似的事情發生在'egen,rowmax()'。 –

1

這裏有一個簡單的方法來做到這一點(即仍然需要2個循環):

// loop over the order variables creating dummies 
forvalues v=1/20 { 
    tab order`v', gen(var`v'_) 
} 


// loop over the domain of the order variables (may need to change) 
forvalues l=1/3 { 
    egen variable`l' = rmax(var*_`l') 
    drop var*_`l' 
} 
+0

這有兩個問題。 1)根據觀察/變量(和Stata版本)的數量,它會很快達到允許變量數量的限制(例如Stata IC爲70 obs/vars)。 2)再次,根據obs/vars的數量,它可能比'reshape'解決方案慢(例如60 obs/vars)。 –