[SC5] Studiennote standardisieren

Hallo Tobias!

Sorry für die späte Antwort, aber die Anfrage landete leider in der falschen Warteschlange und wurde daher übersehen.

Zu den Daten in der SC5 gilt leider generell, dass es für viele Probleme keine harmonisierten Informationen in den Target-Datensätzen gibt.

Eine konsistente, aber auch sehr komplexe Möglichkeit, bietet nur spVocTrain.

Die Daten von Spellform (mehrere Zeilen pro Person pro Welle) in Wellenform (eine Zeile je Welle pro Person) zu transferieren ist sehr herausfordernd und hängt auch von inhaltlichen Kriterien ab.

Ich habe eine Syntax geschrieben mit der das funktionieren kann, aber bitte beachte die Kommentare. Entscheidend dabei ist auch, welcher Welle man den Zeitraum zwischen zwei Erhebungen zurechnet, da die Ereignisse auch retrospektiv abgefragt werden. Gehört der Zeitraum zwischen Interview Welle 1 und Welle 2 zur Welle 1 oder zur Welle 2. Das kann ich so nicht entscheiden. Ich habe diesen Zeitraum in der Syntax der Welle 1 zugeordnet.

// Nepstools-Stata-ados installieren
capture: net install nepstools, from("http://nocrypt.neps-data.de/stata")


global origdatapath <Setze hier den Pfad zum Datenverzeichnis der Originaldaten>  (z.B.: C:/User/User1/Desktop/SC5_11-0-0/origdata)
global workingdatapath  <Setze hier den Pfad zum Datenverzeichnis der aufbereiteten Daten> (z.B.: C:/User/User1/Desktop/SC5_11-0-0/workingdata)

***********************************************************************************
*** spVocTrain-Datensatz aufbereiten ****

//spVocTrain öffnen
local usevars ID_t splink spell subspell tg24170* ts15201 tx20100 ts151??_* ts15211  // relevante Vars aus spVocTrain
use `usevars' using "${origdatapath}/SC5_spVocTrain_D_11-0-0.dta", clear

//Nur Uni-/FH-Episoden behalten, die harmonisiert sind und empfohlen werden
keep if inrange(ts15201,6,10) & subspell==0 & tx20100==1
drop *R

// NEPS-Missingwerte auf Daten schreiben
nepsmiss

//Monats-basiertes Start- und Enddatum eine Spells generieren
gen startdate=ym(ts1511y_g1,ts1511m_g1)
gen enddate=ym(ts1512y_g1,ts1512m_g1)

// Datum droppen falls missing
drop if missing(startdate) , missing(enddate)

// Datum so formatieren, dass es auch Menschen lesen können
format %tm startdate enddate

// **** Offensichtlich unplausible Episoden löschen ****
drop if startdate >= enddate // Ende des Spells liegt vor Beginn >> weg
gen ws1011=ym(2010,9) // Semester-Startdatum generieren
drop if startdate < ws1011 // alle Episoden vor WS10/11 löschen
drop ts1512y* ts1512m* ts1511?*  // Einzel-Variablen werden nicht mehr benötigt

*******************************
// Nun kommt die Datenaufbereitung für die Episoden:
// Es gibt leider einige Personen im Datensatz die angaben, 
// mehrere gleichzeitige Studien zu absolvieren
// Nun muss eigentlich jeder Nutzer individuell entscheiden, welche Episoden verwendet werden sollen

//Vorschlag für die Auswahl der Spells:
unab allvars: _all
egen nummiss=rowmiss(`allvars') // Anzahl der Missings in den Variablen als Kriterium
gen duration=enddate-startdate // Dauer von Episoden als Kriterium
duplicates tag ID_t startdate, gen(dup_start) // Fälle einer Person markieren, die parallele Beginndaten von Spells haben

// jeweils eine Zeile der Duplikate werden gelöscht, wenn das Studium "nebenher" absolviert wird
drop if dup_start==1 & ts15211==2 

// Spell mit maximaler Dauer ermitteln
bysort ID_t startdate: egen maxdur=max(duration) 
keep if duration==maxdur // Spellzeile mit der längsten Dauer behalten

bysort ID_t startdate: egen dauert_an=min(ts1512c_g1)
drop if dup_start==1 & dauert_an!=ts1512c_g1
bysort ID_t startdate: egen minmiss=min(nummiss)
keep if nummiss==minmiss
bysort ID_t startdate (spell): gen dup_nr=_n
drop if dup_nr > 1
drop ws1011 nummiss maxdur minmiss dup_start dup_nr dauert_an ts15211 subspell tx20100
isid ID_t startdate
save "${workingdatapath}/spVocTrain_work1.dta", replace


/*****************************************************
**** Wellenindikator aus dem Cohort Profile an Spell-Logik anspassen ****
	HAUPTANNAHME: DER ZEITRAUM INTERVIEWDATUM AKTUELLE WELLE bis DATUM < INTERVIEWDATENFOLGEWELLE IST AKTUELLE WELLE:
		>>> Beispiel: Interviewdatum Welle1: 201010 Interviewdatum Welle 2: 201105 Zeitraum 201010 bis einschließlich 201104 ist Welle 1.
		Wenn man das anders haben will, muss man die Syntax anpassen
	1. Monatsbasiertes Interviewdatum generieren
	2. Endgültige Ausfälle wegwerfen
	3. Mittelwert des Interviewmonats für temp. Ausfälle in intdate einsetzen
	4. Dublikate in den intdates auflösen: Wenn Interview von Welle 1 und Welle 2 im selben Monat stattfanden, Intmonat von Welle 1 um 1 Monat subtrahieren
	5. Monatssplits generieren: Für jeden Interviewmonat von Semesterbeginn WS10/11 bis zum letzten Interview wird eine Zeile im Datensatz angehängt:
	
original: 			aufgebläht mit Monatssplits:
ID	Welle	intdate		ID	Welle	intdate	month
1	1	201010		1	1	201010	201010
1	2	201105		1	1	201010	201011
1	3	201201		1	1	201010	201012
				1	1	201010	201101
				1	1	201010	201102
				1	1	201010	201103
				1	1	201010	201104
				1	2	201010	201105
				1	2	201010	201106
				1	2	201010	201107
				1	2	201010	201108
				1	2	201010	201109
				1	2	201010	201110
				1	2	201010	201111
				1	2	201010	201112
				1	3	201010	201201
				1	3	201010	201202
				1	3	201010	201203
				1	3	201010	201204

																					
	Es werden so für jeden Monat Zeilen generieren mit denen man die Wellen an Start- (startdate) u. Enddatum (enddate) der Episoden anspielen kann

*/ 
use ID_t wave intm inty intd tx80220 using "${origdatapath}/SC5_CohortProfile_D_11-0-0.dta" , clear   // relevante Daten aus CohortProfile laden
label drop `: value label wave' // wegen der Übersichtlichkeit: label des Wellenindikators droppen 
format %8.0g wave // Anzeigeformat für wave verringern

// *** 1. Monats-basiertes Interviewdatum generieren ***
generate intdate=ym(inty,intm) // Zählt die Monate seit Januar 1960/1970??? 
clonevar intdate_orig=intdate  // Original Interviewdatum behalten
gen ws1011=ym(2010,9)  // Semesterbeginn WS10/11 als Monatsdatum generieren
format %tm intdate ws1011 // von Menschen lesbares Anzeigeformat für Monatsdatum

// 2. *** endgültige Ausfälle droppen ***
drop if tx80220==3  
drop tx80220 // nicht mehr relevant

// 3. *** falls kein Interviewdatum, da nicht in Welle teilgenommen, Mittelwert des Interviewdatums einsetzen
// kann auch elaborierter erfolgen (z.B. Imputationen) ***
bysort wave: egen wavemean=mean(intdate)  
replace wavemean=round(wavemean)
replace intdate=wavemean if missing(intdate)
bysort ID_t (intdate): gen wave_chron=_n
bysort ID_t (intdate): replace intdate=ws1011 if intdate > ws1011 & _n==1

// 4. *** Duplikate aus ID_t und intdate werden aufgelöst:  ****
duplicates tag ID_t intdate, gen(dup_int)  
bysort ID_t intdate (intdate_orig): gen line=_n
replace intdate=intdate-1 if line==1 & dup_int==1
isid ID_t intdate


// **** 5. Monatssplits generieren ****
// Zeitraum zwischen zwei Interviews (dur) wird zum expandieren des Datensatzes verwenden
bysort ID_t (intdate): gen dur=intdate-intdate[_n-1] 
bysort ID_t (intdate): replace dur=0 if missing(dur) & _n==1 // Alle Welle 1-Dauern von Missing auf 0 setzen
assert !missing(dur) // gibts jetzt noch missings?

// Datensatz äufblähen für Monatssplits
expand=dur , generate(expandmarker) 
bysort ID_t wave (expandmarker) : gen monthnum=_n-1 // Laufindex für Monate
gen month=intdate-monthnum // Monatsvariable erzeugen: nun gibts für jeden Monat von erstem Interview bis zum Paneltod eine Zeile. So kann man die Spells an die Wavezeilen anspielen.
isid  ID_t month // doppelte Monate pro ID?
keep ID_t wave month
clonevar startdate=month
clonevar enddate=month
drop month
format %tm startdate enddate
save "${workingdatapath}/CohortProfile_work1.dta", replace

*****************************************************
*** aufbereiteten spVoctrain an CohortProfile über STARTDATE spielen und nur die Fälle behalten die in beiden Datensätzen vorhanden sind (keep 3 4 5)
merge 1:1 ID_t startdate using "${workingdatapath}/spVocTrain_work1.dta", assert(1 3 4 5) update replace keep(3 4 5) nogen
duplicates tag ID_t wave, gen(dup_wave) // nun gibt es wieder innerhalb von Wellen mehrere Duplikate (mehrere Studienbeginne pro Welle pro Person)


// **** Ab hier Dublikate pro Welle aufheben: ****
// 1. bei Duplikaten spells die nicht andauern löschen, wenn ein anderer gleichzeitig. Spell andauert
bysort ID_t wave: egen dauertan_min=min(ts1512c_g1)
drop if dup_wave==1 & ts1512c_g1==2 & dauertan_min==1  
drop dup_wave

// 2. bei Duplikaten die längsten Spells (längste Dauer) behalten und die kürzeren Spells löschen - sofern diese nicht andauern
duplicates tag ID_t wave, gen(dup_wave)
bysort ID_t wave (duration): egen maxdur=max(duration)
drop if duration!=maxdur & ts1512c_g1!=dauertan_min & dup_wave==1

// 3. längsten Spell behalten
distinct ID_t
local IDs_ante `r(ndistinct)'
keep if duration==maxdur
distinct ID_t
local IDs_post `r(ndistinct)'
assert `IDs_ante'==`IDs_post'
drop dup_wave
duplicates tag ID_t wave, gen(dup_wave)  // es bleiben immer noch Duplikate übrig

// 4. hier letzten aktiven Spell pro Welle aufheben
bysort ID_t wave: egen end_max=max(enddate) 
keep if enddate==end_max 
isid ID_t wave
rename wave wave_start  // wave in wave_start umbenennen
drop dauertan_min maxdur dup_wave end_max
save "${workingdatapath}/spVocTrain_wave_startdate.dta", replace

*****************************************************
// Diese Wellen-deduplizieren spVocTrain-Datensatz mit ENDDATE an aufgeblähten CohortProfile anspielen um die letzte Welle eines Spells zu erhalten.
use "${workingdatapath}/spVocTrain_wave_startdate.dta", clear
merge m:1 ID_t enddate using  "${workingdatapath}/CohortProfile_work1.dta", keep(match) assert(using match) nogen
rename wave wave_end  // Spell endet in Welle X

// Indikator erzeugen, der angibt über wieviele Wellen ein Spell von Beginn (wave_start) bis Ende (wave_end) läuft
gen wave_diff=wave_end-wave_start  
merge m:1 ID_t wave_start using "${workingdatapath}/spVocTrain_wave_startdate.dta", ///
	keepusing(splink enddate) update replace keep(3 4 5) assert(1 3 4 5) nogen

count if wave_diff < 0	// Fälle die zuerst in Welle 2 teilnahmen und dann erst in Welle 1..
bysort ID_t: egen wave_diff_min=min(wave_diff) 
bysort ID_t (wave_start wave_end): drop if _n > 1 & wave_diff < 0 // aber diese Personen haben noch andere Spells, die in Welle 1 starten
assert wave_diff >=0
drop wave_diff_min

// Datensatz äufblähen, damit aus wave_start und wave_end wave generiert werden kann:
/* aus 				   	>>    wird  >>			
ID 	wave_start	wave_end	ID	wave	wave_start	wave_end  
1	2		8		1	2	2		8	
					1	3	2		8
					1	4	2		8
					1	5	2		8
					1	6	2		8
					1	7	2		8
					1	8	2		8
*/

// Das expandieren funktioniert analog zur Expansion von CohortProfile
expand=wave_diff+1, generate(expandmarker)
bysort ID_t wave_start (expandmarker) : gen wavenum=_n // Laufindex für Monate
// wave-Variable erzeugen: Es gibt nun eine wave-Variable von Anfang-Ende eines Spells.
gen wave=wave_start+wavenum-1 
keep ID_t wave splink startdate enddate tg24170_g2 tg24170_g5 ts1512c_g1 ts15265  // hier die Variablen behalten, die man braucht

// Nun gibt es aber wieder Spells, die sich zeitlich überlappen
duplicates report ID_t wave

// Alle Spells die sich zeitlich überlappen in eine Zeile von long nach wideformat transformieren
bysort ID_t wave (startdate enddate): gen line=_n  // Indikator für Zeilennummer
quietly: sum line
local maxspell=`r(max)'

// Varnames für Transformation anpassen wg. besserer Lesbarkeit
local vars startdate enddate tg24170_g2 tg24170_g5 ts1512c_g1 splink
foreach widevar of local vars {
	rename `widevar' `widevar'_
	local widevar `widevar'_
	local widevars : list widevars , widevar
}
// Wide-Transformation
reshape wide `widevars', i(ID_t wave) j(line)

// Variablenlabels erzeugen/reparieren
forvalues spell=1/`maxspell' {
	foreach var of varlist *_`spell'{ 
		if regexm("`var'","start") label variable `var' "Datum Beginn Spell `spell'"
		if regexm("`var'","end") label variable `var' "Datum Ende Spell `spell'"
		if regexm("`var'","splink") label variable `var' "Spell-Link-Nr des Spells `spell'"
		if regexm("`var'","tg24170_g2") label variable `var' "Fächergruppe Fach 1 (destatis 2010/11), generiert, Spell `spell'"
		if regexm("`var'","tg24170_g5") label variable `var' "ISCED-97 Fach 1 (1-Steller), generiert, Spell `spell'"
		if regexm("`var'","ts1512c_g1") label variable `var' "Prüfmodul: Episode dauert an (ediert), Spell `spell'"
		if regexm("`var'","ts15265") label variable `var' "Note Ausbildungsabschluss, Spell `spell'"
	}
}

// Check ob Datensatz richtig  befüllt wurde
forvalues spell=1/`maxspell' {
	local nextspell=`spell'+1
	if `spell' <= `maxspell'-1 assert missing(splink_`nextspell') if missing(splink_`spell')
}

// seichern
save "${workingdatapath}/SC5_Faecher_from_spells.dta", replace

***************************************************************************
// nun kann der Datensatz z.B. an pTagetCAWI angespielt werden:
merge 1:1 ID_t wave using "${origdatapath}/SC5_pTargetCAWI_D_11-0-0.dta"

// um nur die Falle zu behälten, die in beiden Datensätzen vorkommen:
keep if _merge==3
distinct ID_t  // Daten zu 12108 Personen in 32696 Beobachtungen verfügbar

Ich hoffe, ich konnte etwas weiterhelfen.

Viele Grüße.

Dietmar.