2  Schleifen aus Macros

2.1 local erstellen und für Schleifen verwenden

Schleifen aus globals / locals mit Hilfe von levelsof:

tab m1202
levelsof m1202

levelsof m1202, loc(ausb)
foreach lvl  of local ausb {
    dis "m1202: " `lvl'
}


levelsof m1202, loc(ausb)
glo ausb `ausb'
mac l ausb

foreach lvl  of global ausb {
    dis "m1202: " `lvl'
}


foreach lvl  of global ausb {
    dis "m1202: " `lvl'
    tab S1 if m1202 == `lvl'
}

2.2 Schleifen über strings

2.2.1 Wörter indizieren

local phrase `" "2 guys" "1 girl" "1 pizza place" "'
di "`:word 2 of `phrase' '"
1 girl

2.2.2 Wörter zählen

local sentence "here is a sentence 7"
local len: word count `sentence'
mac list _len
_len:           5

2.2.3 Wörter in Schleife

local phrase1 "here is a sentence of 7 words"
local len1: word count `phrase1'

forvalues i = 1(1)`len1' {
    loc word: word `i' of `phrase1'
    dis "this is word number " `i' ": `word'"
}
this is word number 1: here
this is word number 2: is
this is word number 3: a
this is word number 4: sentence
this is word number 5: of
this is word number 6: 7
this is word number 7: words

… dabei macht es einen Unterschied, wo die "" stehen:

local phrase2 `" "here is" "a sentence" "of 7 words" "'
local len2: word count `phrase2'

forvalues i = 1(1)`len2' {
    loc word: word `i' of `phrase2'
    dis "this is word number " `i' ": `word'"
}
this is word number 1: here is
this is word number 2: a sentence
this is word number 3: of 7 words

Übung


2.3 Informationen aus Schleifen behalten

2.3.1 Gespeicherte Ergebnisse

Um auf Ergebnisse zuzugreifen, können wir etwas hinter die Kulissen der Stata-Befehle sehen:

Befehl zeigt alle
c-class system parameters & settings finden wir als `c()`
r-class die meisten deskriptiven Befehle speichern die Ergebnisse in in `r()`
e-class ...außer estimation commands, wie bspw. `reg` - hier wird in `e()` gespeichert (Postestimates)
s-class parsing commands store results in `s()` used by programmers
n-class commands that do not store in `r()`, `e()`, oder `s()`

Jeweils alle Werte anzeigen mit:

Befehl zeigt alle
return list r()
ereturn list e()
sreturn list s()
creturn list c()

Es gibt dabei vier Typen an Ergebnissen:

  • macro: strings mit mehreren Wörtern (Text)
  • matrix: bspw. e(b) sind die Koeffizienten nach einem reg-Befehl oder e(V) ist die Varianz–Kovarianz Matrix der estimates (VCE)
  • scalar: einzelne Zahlen/Strings (1x1 Matrizen)
  • functions: bspw. e(sample) \(\Rightarrow\) 1 (true) wenn die Beobachtung im vorheringen “estimation command” verwendet wurde und 0 (false) wenn nicht
tab S1
return list
 Geschlecht |      Freq.     Percent        Cum.
------------+-----------------------------------
   männlich |     10,074       50.34       50.34
   weiblich |      9,938       49.66      100.00
------------+-----------------------------------
      Total |     20,012      100.00


scalars:
                  r(N) =  20012
                  r(r) =  2
su S1
return list
    Variable |        Obs        Mean    Std. Dev.       Min        Max
-------------+---------------------------------------------------------
          S1 |     20,012    1.496602    .5000009          1          2


scalars:
                  r(N) =  20012
              r(sum_w) =  20012
               r(mean) =  1.496602038776734
                r(Var) =  .2500009464113147
                 r(sd) =  .500000946410419
                r(min) =  1
                r(max) =  2
                r(sum) =  29950
reg F518_SUF zpalter 
ereturn list
      Source |       SS           df       MS      Number of obs   =    16,543
-------------+----------------------------------   F(1, 16541)     =    105.36
       Model |  1.3092e+09         1  1.3092e+09   Prob > F        =    0.0000
    Residual |  2.0555e+11    16,541    12426773   R-squared       =    0.0063
-------------+----------------------------------   Adj R-squared   =    0.0063
       Total |  2.0686e+11    16,542    12505168   Root MSE        =    3525.2

------------------------------------------------------------------------------
    F518_SUF |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
     zpalter |   24.62253   2.398848    10.26   0.000     19.92053    29.32453
       _cons |    2381.28    115.577    20.60   0.000     2154.736    2607.823
------------------------------------------------------------------------------


scalars:
                  e(N) =  16543
               e(df_m) =  1
               e(df_r) =  16541
                  e(F) =  105.3561454498825
                 e(r2) =  .0063290815436915
               e(rmse) =  3525.162828161657
                e(mss) =  1309236899.97876
                e(rss) =  205551251614.9366
               e(r2_a) =  .0062690083366028
                 e(ll) =  -158590.4618746699
               e(ll_0) =  -158642.9792418738
               e(rank) =  2

macros:
            e(cmdline) : "regress F518_SUF zpalter"
              e(title) : "Linear regression"
          e(marginsok) : "XB default"
                e(vce) : "ols"
             e(depvar) : "F518_SUF"
                e(cmd) : "regress"
         e(properties) : "b V"
            e(predict) : "regres_p"
              e(model) : "ols"
          e(estat_cmd) : "regress_estat"

matrices:
                  e(b) :  1 x 2
                  e(V) :  2 x 2

functions:
             e(sample)   

Anstatt zu versuchen, den Überblick darüber zu behalten, was wo gespeichert wird, finden wir ganz unten in jeder Hilfedatei einen Hinweis wie “summarize stores the following in r():” or “mean stores the following in e()” - entsprechend sehen wir die Ergebnisse in return bzw. ereturn.

2.3.2 e() und r() sind getrennte Welten

Neben dem Prinzip “One Data” folgt Stata auch dem Prinzip “One _-class”. Das bedeutet, dass wir nur den return oder ereturn für den letzten Befehl dieser Klasse sehen können. Wenn wir also reg ausführen und dann eine Reihe von r-Klassen-Aufrufen machen (z.B. su), wird uns der Aufruf von ereturn immer noch die Werte für reg anzeigen. Sobald wir jedoch einen weiteren r-class-Befehl ausführen, verlieren wir den Zugriff auf die Ergebnisse des ersten Befehls.

reg az F200
su az
ereturn list
      Source |       SS           df       MS      Number of obs   =    17,376
-------------+----------------------------------   F(1, 17374)     =  33637.44
       Model |  1269310.92         1  1269310.92   Prob > F        =    0.0000
    Residual |  655608.985    17,374   37.735063   R-squared       =    0.6594
-------------+----------------------------------   Adj R-squared   =    0.6594
       Total |   1924919.9    17,375  110.786757   Root MSE        =    6.1429

------------------------------------------------------------------------------
          az |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
        F200 |   .9897533   .0053965   183.41   0.000     .9791755    1.000331
       _cons |   3.937849   .1903973    20.68   0.000     3.564651    4.311047
------------------------------------------------------------------------------

    Variable |        Obs        Mean    Std. Dev.       Min        Max
-------------+---------------------------------------------------------
          az |     20,012    38.30557    11.75297         10        120


scalars:
                  e(N) =  17376
               e(df_m) =  1
               e(df_r) =  17374
                  e(F) =  33637.43995203968
                 e(r2) =  .6594097320849045
               e(rmse) =  6.142887188019294
                e(mss) =  1269310.915908093
                e(rss) =  655608.9846442067
               e(r2_a) =  .6593901286390708
                 e(ll) =  -56197.03934279057
               e(ll_0) =  -65554.6676770772
               e(rank) =  2

macros:
            e(cmdline) : "regress az F200"
              e(title) : "Linear regression"
          e(marginsok) : "XB default"
                e(vce) : "ols"
             e(depvar) : "az"
                e(cmd) : "regress"
         e(properties) : "b V"
            e(predict) : "regres_p"
              e(model) : "ols"
          e(estat_cmd) : "regress_estat"

matrices:
                  e(b) :  1 x 2
                  e(V) :  2 x 2

functions:
             e(sample)   

2.4 Ergebnisse weiter verwenden

Alle diese Informationen können wir mit einem Makro speichern bzw. weiter verarbeiten.

su S1
dis "Der Mittelwert beträgt: " r(mean)
Der Mittelwert beträgt: 1.496602
su S1
dis "Der Mittelwert beträgt: " round(r(mean),.01)
Der Mittelwert beträgt: 1.5
foreach lvl  of global ausb {
    dis "m1202: " `lvl'
    su S01 if m1202 == `lvl'
    dis r(mean)
}

foreach lvl  of global ausb {
    qui su S01 if m1202 == `lvl'
    dis "Der Frauenanteil in m1202=" `lvl' " beträgt: " round(r(mean)*100,.1) "%"
}


foreach lvl  of global ausb {
    qui su S01 if m1202 == `lvl'
    glo gend`lvl': display "Der Frauenanteil in m1202=" `lvl' " beträgt: " round(r(mean)*100,.1) "%"
}

2.4.1 Rekursivität

Macros können auch “recursively” erstellt werden:

global x ""
forvalues i = 1/20 {
    global x $x `i'
}
mac list x
x:              1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

…somit können wir einen global auch zusammenbauen:

glo gend ""
foreach lvl  of global ausb {
    qui su S01 if m1202 == `lvl'
    glo gend: display "${gend}m1202=" `lvl' " " round(r(mean)*100,.1) "% "
}
mac l gend
  4. }

gend:           m1202=1 45.6% m1202=2 53% m1202=3 37.8% m1202=4 48.9%

Übung


2.5 Kennzahlen in einer matrix ablegen

Matrizen helfen uns, die ergebnisse in handhabarer Form zu speichern (help matrix). Um eine Tabelle zu bauen benötigen wir einige Matrix-Befehle, weiteres unter help matrix operators

  • eine matrix ausgeben: matrix list matname

  • eine matrix umbenennen: matrix umbenennen altername neuername

  • eine matrix oder alle löschen: matrix drop [matlist]

Operator Symbol
column join ,
row join \\
transpose '
negation -
matrix Y1 = 1, 3 
mat l Y1
Y1[1,2]
    c1  c2
r1   1   3
matrix Y2 = 4\ 0
mat l Y2
Y2[2,1]
    c1
r1   4
r2   0
matrix Y = (2, 1.5 \ 2.5, 3)
mat l Y
Y[2,2]
     c1   c2
r1    2  1.5
r2  2.5    3

Transponieren:

matrix X2 = (1, 2, 3 \ 5 , 8 , 9)
mat l X2 
mat X3 = X2'
mat l X3
X2[2,3]
    c1  c2  c3
r1   1   2   3
r2   5   8   9



X3[3,2]
    r1  r2
c1   1   5
c2   2   8
c3   3   9

Mit J(Zeilen,Spalten,Inhalt) können wir eine Matrix mit gleichen Werten besetzen:

mat G0 = J(4,2,0)
mat l G0
G0[4,2]
    c1  c2
r1   0   0
r2   0   0
r3   0   0
r4   0   0

2.5.1 Namen für Spalten und Zeilen einer matrix

Aber wir können die Zeilennamen einer matrix verändern:

mat colname G0 = var1 var2
mat list G0
G0[4,2]
    var1  var2
r1     0     0
r2     0     0
r3     0     2
r4     0     0

Wenn zu wenige Namen angegeben werden, wird der letzte Wert einfach wiederholt:

mat rowname G0 = year result
mat list X1
G0[4,2]
        c1  c2
  year   0   0
result   0   0
result   0   2
result   0   0

2.5.2 matrix erstellen

Das nutzen wir jetzt um unsere Ergebnisse zu speichern:

levelsof m1202, loc(ausb)
foreach lvl  of local ausb {
    qui su S01 if m1202 == `lvl'
    
    // 1. Spalte level von m1202
    //2.Spalte: Frauenanteil
    mat G`lvl' = `lvl' ,r(mean)*100 
}
mat G = GX1\GX2\GX3\GX4
mat colname G = m1202 share_w
mat l G

Damit können wir auch zeilenweise eine matrix befüllen, indem wir mit , mehrere Werte verbinden (row join):

qui levelsof m1202, loc(ausb)
foreach lvl  of local ausb {
    qui su zpalter if m1202 == `lvl', det
    mat A`lvl' = `lvl', r(p25), r(mean), r(p50), r(p75)
}
mat A = A1\A2\A3\A4
mat colname A = m1202 p25 mean median p75
mat l A
A[4,5]
        m1202        p25       mean     median        p75
r1          1         29  42.627213         46         55
r1          2         39  47.076531         49         56
r1          3         41  48.092344         50         56
r1          4         39  47.760744         49         57

Übung


2.6 Labels behalten

2.6.1 extended macro function für Labels

Idealerweise würden wir aber gerne nicht nur 1-4 in m1202 behalten, sondern die Labels (Ohne Berufsabschluss) usw. Um Informationen zu Variablen & Labels abzurufen, lernen wir später eine ganze Reihe an extended macro functions kennen, für den Moment reicht uns label (varname) varvalue:

loc v m1202
local vallab1 :    label (`v') 1            // Value label für Wert = 1
dis "`vallab1'"     // display local "valuelab1"
Ohne Berufsabschluss

In der Schleife können wir dann lvl entsprechen für label (var) lvl nutzen:

loc lvl = 1
qui su zpalter if m1202 == `lvl', det
mat GX = `lvl', r(p25), r(mean), r(p50), r(p75) 
local vallab1 :    label (m1202) `lvl' // label aufrufen

2.6.2 Labels als rowname

Leider können wir nicht einfach die Labels der Variable in die matrix schreiben. In einer Matrix sind nur Zahlenwerte erlaubt:

mat M = c(2\"label")
r(133);

end of do-file
r(133);

Aber wir können das Label als rowname ablegen:

loc lvl = 1
qui su zpalter if m1202 == `lvl', det
mat GX = `lvl', r(p25), r(mean), r(p50), r(p75) 
local vallab1 :    label (m1202) `lvl' // label aufrufen
mat rowname GX =  "`vallab1'" // in Zeilenname ablegen
mat l GX

…damit erweitern wir die Schleife von oben:

levelsof m1202, loc(ausb)
foreach lvl  of local ausb {
    qui su zpalter if m1202 == `lvl', det
    mat GX`lvl' = `lvl', r(p25), r(mean), r(p50), r(p75)
    
    local vallab1 :    label (m1202) `lvl'
    mat rowname GX`lvl' =  "`vallab1'"
}
mat G = GX1\GX2\GX3\GX4
mat colname G = m1202 p25 mean median p75
mat l G
1 2 3 4





G[4,5]
                  m1202        p25       mean     median        p75
Ohne Beruf~s          1         29  42.627213         46         55
duale o. s~l          2         39  47.076531         49         56
Aufstiegsf~T          3         41  48.092344         50         56
Fachhochsc~h          4         39  47.760744         49         57

2.7 Von der matrix zum Datensatz

Mit xsvmat bzw. dem ado xsvmat können wir eine matrix in einen Datensatz umwandeln. Mit rownames(lab) können wir Zeilennamen in die Variable lab ablegen. Außerdem nutzt xsvmat die neue frame- Funktion, um einen neuen Datensatz zu erstellen.

ssc install  xsvmat
xsvmat G, names(col) frame(res1) rownames(lab)
frame change res1
list, noobs clean
                                                         lab   m1202   p25       mean   median   p75  
                                        Ohne Berufsabschluss       1    29   42.62721       46    55  
    duale o. schulische Berufsausbildung/einf.,mittl. Beamte       2    39   47.07653       49    56  
    Aufstiegsfortbildung (Meister, Techniker, kfm. AFB u.ä.)       3    41   48.09234       50    56  
            Fachhochschule, Universität/ geh., höhere Beamte       4    39   47.76074       49    57  

2.8 frame: mehrere Datensätze in Stata

Die frame-Option basiert auf einer relativ neuen Funktion in Stata. Seit Version 16 bietet Stata mit den frame-Befehlen auch die Möglichkeit, mehrere Datensätze parallel zu bearbeiten.

  • mit frame create nameX können wir einen neuen Datensatz mit dem Namen nameX erstellen (der bisherige wird als default bezeichnet)
  • mit frame dir bekommen wir eine Übersicht zu den verschiedenen frames der aktuellen Stata-Session
  • mit frame change name können wir zwischen den verschiedenen frames hin- und herspringen
frame change res1
frame change default
  • mit frame drop name können wir einen frame wieder löschen:
frame drop res1

Übung


2.9 Übungen

2.9.1 Übung

  • Zählen Sie die Wörter in den folgenden beiden String-locals
loc x1 "ein sehr langer satz mit vielen wörtern"

ds *wib*
loc x2 =  r(varlist)
  • Wie würde eine Schleife aussehen, die jeweils ein Wort aus den locals nacheinander mit display ausgibt?

2.9.2 Übung

  • Laden Sie die Erwerbstätigenbefragung - am besten in der Version ohne Missings in den relevanten Variablen ( "${data}/BIBBBAuA_2018_suf1.0_clean.dta", siehe 01_init.do)
  • Erstellen Sie eine Schleife, welche jeweils das Maximaleinkommen (basierend auf F518_SUF) für die Gemeindegrößenklassen (gkpol) anzeigt.
    • Wie kommen Sie an den Maximalwert für F518_SUF? Verwenden Sie bspw. su oder tabstat zusammen mit return list.
    • Erstellen Sie mit display eine aussagekräftige Ausgabe
    • Testen Sie Ihre Schleifenlogik mit einem local, um anschließend die Schleife “außen herumzubauen”
    • Welche Ausprägungen hat gkpol - wie können Sie diese automatisch in eine Schleife überführen?
  • Optional Passen Sie Ihre Schleife an, sodass für jeden Durchlauf ein global gkX erstellt wird, wobei X für die Ausprägung von gkpol steht und den entsprechenden Maximalwert von F518_SUF für die entsprechende Größenklasse enthält.

2.9.3 Übung

  • Kopieren Sie die in Übung 2 erstellte Schleife und passen Sie diese so an, dass jeweils die Werte für Min, Mean, Median, Max und N in matrix gesammelt werden.
    • Verwenden Sie den row join für matrix mit , um jeweils eine Ergebniszeile zu erstellen

2.9.4 Übung

  • Passen Ihre Schleife von eben mit gkpol so mit Hilfe der Schleife von oben so an, dass die Labels für gkpol als rownames werden legen Sie die Ergebnismatrix in einen frame ab.
    • Nutzen Sie die label (v') 1 extended macro function um das jeweilige Label anzuzeigen
    • Setzen Sie das entsprechende Label als rowname
    • Fügen Sie die einzelnen Ergebnis in eine matrix zusammen
    • Nutzen Sie xsvmat, um einen frame zu erstellen
    • Nutzen Sie frame change, um in die Ergebnis-frame zu wechseln (und wieder zurück)