4 Label- und Variablenfunktionen
Inspiriert von der UCLA einige Beispielstrings:
clear all
input str60 add"4905 Lakeway Drive, College Station, Texas 77845 USA"
"673 Jasmine Street, Los Angeles, CA 90024"
"2376 First street, San Diego, CA 90126"
"6 West Central St, Tempe AZ 80068"
"1234 Main St. Cambridge, MA 01238-1234"
"Robert-Schuman-Platz 3, 53175 Bonn GERMANY"
"Regensburger Straße 100, 90478 Nürnberg Germany"
" Ammerländer Heerstraße 114-118, 26129 Oldenburg GERMANY "
end
4.1 Stringfunktionen
help string functions
gen x1 = substr(add,5,10) // substring von add -> Zeichen 5-10
gen x2 = wordcount(add) // Worte zählen
gen x3 = word(add,5) // 5. Wort
gen x4 = upper(add) // alles groß
gen x5 = lower(add) // alles klein
gen x6 = proper(add) // jeweiles erster Buchstabe eines Wortes groß
gen x7 = trim(add) // Leerzeichen am Ende und Beginn raus
gen x8 = strlen(add) // Anzahl der Zeichen in add
Allerdings sind diese Funktionen auf ASCII-Zeichen ausgelegt - einfach gesagt: Umlaute, ß usw. bereiten Probleme. Daher gibt es eine Erweiterung mit usubstr
, ustrupper()
, ustrlower()
usw. - mehr dazu jeweils in der Hilfe.
Der Weg zur passenden regex
string-Funktion ist leider oft von vielen Versuchen begleitet, am einfachsten testet man mit display
. So zeigt sich hier bspw., dass proper()
hier “ß” und “ü” als Wortende/-beginn (mis-)versteht:
display proper("Regensburger Straße 100, 90478 nüRnberg germany")
Regensburger StraßE 100, 90478 NüRnberg Germany
…in der Hilfe finden wir ustrtitle
:
display ustrtitle("Regensburger Straße 100, 90478 nüRnberg germany")
Regensburger Straße 100, 90478 Nürnberg Germany
Hier wenig hilfreich, aber häufig eine gute Abkürzung: split
Mit parse()
können wir einen Trenner angeben.
split add, parse(" ") gen(t)
real()
ist deutlich schneller und unkomplizierter als destring
clear all
input str1 x1"2"
"3"
"5"
"23"
"21"
"2"
"--"
"2"
end
gen num = real(x1)
list
destring(x1), gen(num2)
x1
1. "2"
2. "3"
3. "5"
4. "23"
5. "21"
6. "2"
7. "--"
8. "2"
9. end
(1 missing value generated)
+----------+
| x1 num |
|----------|
1. | 2 2 |
2. | 3 3 |
3. | 5 5 |
4. | 2 2 |
5. | 2 2 |
|----------|
6. | 2 2 |
7. | - . |
8. | 2 2 |
+----------+
x1: contains nonnumeric characters; no generate
4.2 Arbeiten mit “Regular Expressions”
“regular expressions” oder “regex” sind eine flexible Methode, strings (also Textinhalte) zu durchsuchen. Dabei suchen wir nach Mustern anstelle eines exakten matchings.
In Stata können wir regex für Variablen, aber auch für macros und Labels verwenden. regex sind aber nicht immer die (einfachste) Lösung und oft werden die Befehle sehr unübersichtlich. Daher hier nur ein kurzer Überblick.
Die drei Hauptfunktionen in Stata finden wir unter help regex
:
regexm(s,re)
allows you to search for the string described in your regular expressions. It evaluates to 1 if the string matches the expression.
regexs(n)
returns the nth substring within an expression matched by regexm (hence,regexm
must always be run before regexs).
regexr(s1,re,s2)
searches for re within the string (s1) and replaces the matching portion with a new string (s2).
Allerdings sind diese Funktionen auf ASCII-Zeichen ausgelegt - einfach gesagt: Umlaute, ß usw. bereiten Probleme. Daher gibt es eine Erweiterung mit ustrregexm
, ustrregexs
, ustrregexrf
und ustrregexra
. Auf die konzentrieren wir uns hier.
4.2.1 regex (Grund-)Regeln
regex basieren auf einer Reihe an Zeichen, mit Hilfe derer wir strings durchsuchen können:
\d
matcht eine Zahl\w
matcht “alphanumeric characters” (Buchstaben & Zahlen)\s
matcht ein Leerzeichen^
“matche Ausdruck am Anfang des strings”$
“matche Ausdruck am Ende des strings”-
lässt eine range zu:a-z
,0-9
,5-8
,F-M
etc..
bedeutet “matche irgendein Zeichen”\
ist ein “escape character” für Zeichen, die ansonsten als regex-Operator verstanden würden|
oder-Operator[]
use in matching, such as[a-zA-Z0-9]
for all alphanumeric characters()
darin angegebene Werte können wir mitustrregexs
extrahieren*
“matche 0 oder öfter” für den vorhergehenden Ausdruck+
“matche 1 oder öfter” für den vorhergehenden Ausdruck
4.2.2 Beispiele
Inspiriert von der UCLA einige Beispielstrings:
clear all
input str60 add"4905 Lakeway Drive, College Station, Texas 77845 USA"
"673 Jasmine Street, Los Angeles, CA 90024"
"2376 First street, San Diego, CA 90126"
"6 West Central St, Tempe AZ 80068"
"1234 Main St. Cambridge, MA 01238-1234"
"Robert-Schuman-Platz 3, 53175 Bonn GERMANY"
"Regensburger Straße 100, 90478 Nürnberg Germany"
"Ammerländer Heerstraße 114-118, 26129 Oldenburg GERMANY"
end
gen d = ustrregexm(add, "GERMANY|Germany")
Das m
in ustrregexm
steht für match. Mit ustrregexm
können wir nach Zeichenketten suchen. Wenn sie gefunden wird, wird eine 1 zurückzugeben, andernfalls 0. Hier suchen wir nach “entweder GERMANY oder Germany”.
Wir können aber auch den gefundenen Inhalt extrahieren. Bei Übereinstimmungen werden die matches gespeichert, darauf können wir mit ustrregexs
zurückgreifen:
gen d2 = ustrregexs(0) if ustrregexm(add, "GERMANY|Germany")
s
steht für subexpressions (oder “tokens”). Token 0 enthält alle übereinstimmenden Muster. Wird eine Zeichenkette mehrfach gefunden, dann enthält Token 0 alle Übereinstimmungen, Token 1 die erste, Token 2 die zweite und so weiter.
ustrregexrf
und ustrregexra
helfen uns schließlich, Inhalte zu ersetzen. rf
bzw. ra
stehen dabei für “replace first” bzw. “replace all”. ustrregexrf
ersetzt also nur den ersten match, ustrregexra
hingegen alle.
Basierend auf den Regeln von oben ergeben diese beiden Befehle unterschiedliche Ergebnisse:
gen s1 = ustrregexra(add, "street", "!")
gen s2 = ustrregexra(add, "[street]", "!")
In s1
wurden alle matches “street” gelöscht und durch ! ersetzt. In s2
wurden alle matches von “s”,“t”,“r”,“e” und “t” gelöscht und durch ! ersetzt.
Weitere Beispiele für ersetzen mit regex-Regelausdrücken - siehe DoFile:
gen z1 = ustrregexra(add, "\w", "") // alle alphanumeric ersetzen
gen z2 = ustrregexra(add, "\W", "") // alle nicht-alphanumeric ersetzen
gen z3 = ustrregexra(add, "\d", "") // alle Zahlen ersetzen
gen z4 = ustrregexra(add, "\D", "") // alle nicht-Zahlen ersetzen
gen z5 = ustrregexra(add, ".+,", "") // alles vor dem Komma ersetzen
gen z6 = ustrregexra(add, ",.+", "") // alles nach dem Komma ersetzen
Nach Zahlen suchen:
gen r1 = ustrregexs(0) if ustrregexm(add, "\d") // Zahl
gen r2 = ustrregexs(0) if ustrregexm(add, "\d+") // Zahlenfolge
gen r3 = ustrregexs(0) if ustrregexm(add, "(\d{5})") // 5-stellige Zahl
gen r4 = ustrregexs(0) if ustrregexm(add, "^(\d+)") // Zahlenfolge am Anfang
gen r5 = ustrregexs(0) if ustrregexm(add, "(\d+).*(\d+)") // Zahlenfolgen und alles was dazwischen kommt
gen r6 = ustrregexs(0) if ustrregexm(r5, "(\d+)$") // Zahlenfolge am Ende -> aus r5!
4.2.3 Weiterführende Links
Hier findet sich ein sehr gutes “Cheatsheet” zu den gebräuchlichsten regex. Das zugehörige Tutorial ist ebenfalls sehr lesenswert. Die Übersicht der UCLA bietet auch nochmal einige Hinweise - allerdings auf Basis der ASCII-basierten Befehle. Stata Hilfe Hier findet sich ein weiteres hilfreiches Tutorial
4.3 Label bearbeiten
Um Informationen zu Variablen & Labels abzurufen, stehen eine ganze Reihe an extended macro functions zur Verfügung:
loc v m1202
local vartype: type `v' // Variablen "storage type" (byte etc)
local varlab: variable label `v' // variable label
local vallabname: value label `v' // Name des value label
local vallab1 : label (`v') 1 // Value label für Wert = 1
Die so erstellten local
s können wir dann in der bekannten Methode wieder darstellen:
di "`vartype'" // display local "vartype"
di "`varlab'" // display local "varlabel"
di "`vallabname'" // display local "valuelabname"
di "`vallab1'" // display local "valuelab1"
Wir können die Labels und Eigenschaften von `v’ auch in einem Schritt anzeigen lassen, die Syntax sieht aber etwas eigenwillig aus:
loc v m1202di "`: type `v''" // "storage type" (byte etc) der Variable
di "`: variable label `v''" // variable label
di "`: value label `v''" // Name des value label
di "`: label (`v') 1'" // Value label für Wert = 1
Damit können wir bspw. ein Variable Label kürzen:
local longlabel: var label m1202 // variable label für variable m1202 suchen
local shortlabel = substr("`longlabel'",1,10) // verändern mit string Funktion
label var m1202 "`shortlabel'" // anwenden
Um an die Value Labels zu kommen, braucht es etwas mehr:
local lblname: value label m1202 // value labels für variable m1202 suchen
label drop `lblname'_n //neuen namen droppen zur Sicherheit
cap label copy `lblname' `lblname'_n // value labelbook kopieren
local lab1: label (m1202) 2 // value label für Wert = 2 aufrufen
upper("`lab1'") // dieses value labels verändern
loc lab2 = label define `lblname'_n `lvl' "`lab2'", modify // in neues value labelbook einfügen
labelbook `lblname' `lblname'_n // vergleich alt vs neu
Mit label copy oldname newname
, local lblname: value label var
und local lab1: label (var) level
können wir auch value-Labels bearbeiten:
loc v m1202
local lblname: value label `v' // value label aufrufen
label drop `lblname'_n // neuen Namen zur Sicherheit droppen
cap label copy `lblname' `lblname'_n // kopieren
levelsof `v', loc(x) // Werte für die Variable aufrufen
foreach lvl of local x {
local lab1: label (`v') `lvl' // Value label Variable v bei Level lvl
substr("`lab1'",1,8) // kürzen
loc lab2 =
label define `lblname'_n `lvl' "`lab2'", modify // im neuen value label ändern
}
`v' `lblname'_n // anwenden lab val
4.4 Abgleiche
Existiert eine Variable?
capture confirm variable lm02
if !_rc dis "ja"
if _rc dis "nein"
Ist variable numerisch?
capture confirm numeric variable az
if !_rc dis "ja"
if _rc dis "nein"
ja
help data_types
4.5 wo kommt überall -4 vor?
quietly ds
local varlist1 `r(varlist)'
display "`varlist1'"
*foreach v of varlist1 {
qui count if `v' == -4
if r(N) > 0 display "`v'"
}
* oder direkt:foreach v of varlist * {
qui count if `v' == -4
if r(N) > 0 display "`v'"
}
4.6 Übungen
4.6.1 Übung
- Verwenden Sie mit
input
die Adressdaten von oben - Wie kommen Sie jeweils an das vorletzte Wort aus der Adressliste?
- Extrahieren Sie die zehn letzten Zeichen aus
add
, aber lassen die drei letzten Zeichen weg. (“Zeichen 10 bis 4 von hinten her gezählt”).
4.6.2 Übung
- Laden Sie den
regex.dta
:
use "https://github.com/filius23/StataProgBIBB/raw/main/docs/regex1.dta", clear
und teilen Sie die Informationen ausaddress
in 4 Variablen auf: Hausnummer (erste Zahl), Straße, PLZ, Region- Wandeln Sie alle Einträge in Großbuchstaben um
- Verwenden Sie
split
mit geeignetemparse()
-Argument, um zwischen Hausnummer & Straße und PLZ & Region zu trennen. - Wie können Sie jetzt die Zahlen vom Text trennen? (Tipp: Suchen Sie erst nach den Zahlen. Tipp2: Was wollen wir dann in den Textvariablen nicht mehr?)
- Löschen Sie ggf. Leerzeichen zu Beginn und am Ende der Variablen
4.6.3 Übung
Laden Sie der Erwerbstätigenbefragung
Kürzen die die
variable labels
für alle Variablen mit “wissensintensiver Beruf” im Label (d *wib*
)- Ersetzen Sie “wissensintensiver Beruf” in den
variable labels
mit “wib”. - Spielen Sie die Routine erst für eine Variable durch: welche Label-Befehle brauchen Sie?
- Denken Sie an
foreach ... of varlist
und die Möglichkeit, wildcards zu verwenden. Alternativ hilft evtl. auchds
mit Wildcards
- Ersetzen Sie “wissensintensiver Beruf” in den
So können Sie überpürfen, ob das geklappt hat:
d *wib*
- Bearbeiten Sie das value label für
nuts2
- nutzen Sie dafür dieregex
undstring
-Funktionen von oben- Löschen Sie “Statistische” aus den den value labels und ersetzen Sie “Direktionsbezirk” durch “Bezirk”:
tab nuts2
- Kehren Sie die Codierung vom
m1202
um:gen m1202_n = 10 - m1202
und passen Sie die value labels entsprechend an die neue Codierung an.- Tipp: auch die value labels müssen dann jeweils
10 - x
genommen werden.
- Tipp: auch die value labels müssen dann jeweils
Für alle, die schon fertig sind:
- Wie könnten Sie automatisiert den Variable label für die Muttersprachenvariablen (
F1606_*
) kürzen, sodass statt “Muttersprache:” nur noch “MSpr” im label steht?
4.6.4 Übung
- In welchen Variablen aus der Erwerbstätigenbefragung kommt der der Wert
-9
vor? - Füttern Sie diese Information in
mvdecode
, um die Missings zu überschreiben.- Sammeln Sie die Information, welche Variablen
-9
enthalten (Stichwort rekursive macro-Definition) - Erstellen Sie einen
mvdecode
-Befehle, welcher die Information aufnimmt und in allen gefundenen Variablen-9
durch.
ersetzt.
- Sammeln Sie die Information, welche Variablen
4.7 Anhang
Variablen mit bestimmten Eigenschaften identifizieren in ein macro
ds, has(type byte)
`r(varlist)'
loc bytevars
foreach v of local bytevars {
rename `v' b_`v'
}