Stata: Generarea sumei / totalului pe anumite intervale de date și salvarea lor ca o nouă variabilă (Programare, Sum, Interval, Serii De Timp, Stata, Subtotal)

În777 a intrebat.

Lucrez cu date panel care conțin mai multe companii (id) și acoperă perioada 1.1.2008 – 1.1.2013 (date, year). Doresc să generez o nouă variabilă (sum1) care conține o sumă a observațiilor zilnice pentru var1 pentru fiecare societate și interval de timp specific. Dacă intervalul ar fi egal cu fiecare an, aș folosi funcția total():

 bysort id year: egen sum1=total(var1)

În cazul meu însă, intervalul de timp este determinat ca interval între două evenimente. Am o variabilă specială numită event, care ia valoarea 1 dacă evenimentul a avut loc la o dată specială și lipsește în caz contrar. Există între 5 și 10 evenimente pentru fiecare companie. Intervalele dintre evenimente nu sunt egale; prin urmare, primul interval poate conține 60 de observații, iar următorul interval 360 de observații. De asemenea, intervalele nu sunt egale pentru diferite societăți. Data de începere a primului interval pentru fiecare societate este 1.1.2008. Data de început a celui de-al doilea interval este data primului eveniment + 1 zi. În plus, aș dori să iau în considerare valorile lipsă, astfel încât, dacă toate valorile din var1 pentru societatea x sunt variabile lipsă, sum1 pentru societatea x și intervalul specific trebuie să conțină valori lipsă și nu 0.

Panoul meu arată în felul următor:

   id   date        year    var1    event  sum1(to gen)  event_id(to gen)
   1    1.1.2008    2008    25        .     95 (25+30+40)     1
   1    2.1.2008    2008    30        .     95 (25+30+40)     1
   ...........................................................1      
   1    31.4.2008   2008    40        1     95 (25+30+40)     1
   1    1.5.2008    2008    50        .     160 (50+50+60)    2
   1    2.5.2008    2008    50        .     160 (50+50+60)    2
   .........................................  ................2
   1   31.4.2009    2009    60        1     160 (50+50+60)    2 
   2    1.1.2008    2008    26        .     96 (26+30+40)     1 
   2    2.1.2008    2008    30        .     96 (26+30+40)     1
   ...........................................................1      
   2    31.6.2008   2008    40        1     96 (26+30+40)     1
   2    1.5.2008    2008    51        .     161 (51+50+60)    2
   2    2.5.2008    2008    50        .     161 (51+50+60)    2
   ...........................................................2
   2   31.6.2009    2009    60        1     161 (51+50+60)    2  

Am încercat să scriu diferite bucle (while, if), dar nu am reușit să o fac corect. Nu pot utiliza rolling deoarece intervalele mele nu sunt aceleași.

Cealaltă idee a mea a fost să creez mai întâi identificatorul grupului (numit event_id), care conține event_id pentru fiecare interval și pentru fiecare companie. Apoi aș putea utiliza bysort id event_id: egen sum1=total(var1), dar, din păcate, nu am nicio idee despre cum să fac acest lucru. Așadar, variabilele event_id și sum1 din panoul meu nu există și servesc drept exemplu pentru rezultatul pe care doresc să îl obțin.

Comentarii

  • Am ceva probleme în a înțelege event. Pentru prima instanță, event = 1 pentru primul și ultima apariție, în timp ce toate celelalte evenimente sunt marcate doar cu event = 1 în ultima apariție. Îmi scapă ceva? –  > Por ander2ed.
  • Aveți dreptate, explicația mea este înșelătoare. Am editat-o puțin. Evenimentul din configurația mea este o dată de publicare a raportului anual. De aceea, zilele evenimentului sunt diferite pentru diferite companii sau chiar de câteva ori pentru aceeași companie. Suma1 este suma tuturor observațiilor pentru var1 între două date de publicare. Deoarece nu am date anterioare datei de 1.1.2008. Am luat ca punct de plecare pentru primul interval 1.1.2008. –  > Por În777.
3 răspunsuri
Nick Cox

Pot să înțeleg exemplul cu următoarele modificări:

  1. Datele 31 aprilie și 31 iunie sunt greșeli de scriere pentru 1 zi mai devreme.
  2. Data 31.6.2008 ar trebui să fie totuși 30.4.2008.

Acestea fiind spuse, un truc de inversare a timpului face ca subdiviziunea în vrăji să fie ușoară. Având în vedere reperele 1 pentru se încheie ale fiecărei perioade, putem apoi să cumulăm în sens invers folosind sum(). Micul detaliu crucial aici este că sum() ignoră valorile lipsă sau, mai exact, le tratează ca fiind zero. Aici, aceasta este în întregime o caracteristică, deși nu este chiar ceea ce dorește OP atunci când aplică egen, total().

Apoi, inversați numerotarea ortografică, inversați timpul în direcția normală și aplicați egen ca în alte răspunsuri. Inversarea și inversarea înapoi sunt amândouă doar o negație folosind -. Sortarea pe date în cadrul panoului este doar cosmetică, odată ce avem o diviziune în vrăji, dar este totuși ceea ce trebuie făcut.

Pentru mai multe informații despre perioadele în Stata, consultați aici

Pentru indicii de la Statalist despre cum să oferiți exemple de date folosind dataex (SSC), care se aplică și aici cu o modificare minoră, vezi aici

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 30.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 30.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 30.4.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 30.6.2009 2009 60 1 161    
end

gen ddate = -daily(date, "DMY") 
bysort id (ddate): gen EVENT = sum(event) 
replace ddate = -ddate 
by id: replace EVENT = EVENT[_N] - EVENT + 1 
bysort id EVENT (ddate): egen Sum = total(var1), missing
assert Sum == DesiredSum 
list, sepby(id EVENT) 

     +-----------------------------------------------------------------------+
     | id        date   year   var1   event   Desire~m   ddate   EVENT   Sum |
     |-----------------------------------------------------------------------|
  1. |  1    1.1.2008   2008     25       .         95   17532       1    95 |
  2. |  1    2.1.2008   2008     30       .         95   17533       1    95 |
  3. |  1   30.4.2008   2008     40       1         95   17652       1    95 |
     |-----------------------------------------------------------------------|
  4. |  1    1.5.2008   2008     50       .        160   17653       2   160 |
  5. |  1    2.5.2008   2008     50       .        160   17654       2   160 |
  6. |  1   30.4.2009   2009     60       1        160   18017       2   160 |
     |-----------------------------------------------------------------------|
  7. |  2    1.1.2008   2008     26       .         96   17532       1    96 |
  8. |  2    2.1.2008   2008     30       .         96   17533       1    96 |
  9. |  2   30.4.2008   2008     40       1         96   17652       1    96 |
     |-----------------------------------------------------------------------|
 10. |  2    1.5.2008   2008     51       .        161   17653       2   161 |
 11. |  2    2.5.2008   2008     50       .        161   17654       2   161 |
 12. |  2   30.6.2009   2009     60       1        161   18078       2   161 |
     +-----------------------------------------------------------------------+

Comentarii

  • Vă mulțumim pentru că ați sugerat un articol foarte util despre vrăji. Explicația și codul dvs. mi s-au părut foarte detaliate și am învățat o sintaxă interesantă de la dvs. –  > Por In777.
ander2ed

Dacă nu vă opuneți la recodificarea event în ceva un pic mai ușor de lucrat, următoarele ar trebui să fie suficiente. De asemenea, presupun aici că event este utilizat pentru a marca end intervalului de timp pentru care a avut loc evenimentul (fac această presupunere pe baza datelor dvs. de probă și a comentariului meu la întrebare).

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 31.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 31.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 31.6.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 31.6.2009 2009 60 1 161    
 end

 bysort id : gen i = _n  // to maintain sort order

 /* This section of code changes event so that 1 indicates the start of the 
    interval. This data structure makes more sense to me */
 replace event = 0 if mi(event)
 replace event = 2 if event[_n-1] == 1 & _n != 1
 replace event = event - 1 if event > 0
 replace event = 1 in 1

 gen event_id = event
 replace event_id = event_id+event_id[_n-1] if i != 1

 bysort id event_id : egen Sum = total(var1), missing

li id date event_id DesiredSum Sum, sepby(event_id)

În mod natural, dacă nu ați dorit să modificați event, ați putea generate event2 = event să îl utilizați în locul lui event.

Comentarii

  • Deși am făcut ceva diferit în detaliu, dar vag asemănător în principiu, acest lucru mi-a ușurat pregătirea propriului răspuns. –  > Por Nick Cox.
  • Întotdeauna bucuros să vă ajut. Întrucât configurarea introducerii datelor este, de obicei, cea mai mare sarcină pentru mine în pregătirea unui răspuns, presupun că, având-o la dispoziție, ați economisit destul de mult timp. –  > Por ander2ed.
  • Vă mulțumesc pentru codul detaliat. Mi-a fost ușor să înțeleg toți pașii (unul câte unul). Deoarece sunt începător în STATA, este foarte important pentru mine. Funcționează foarte bine. –  > Por In777.
Brendan

Se pare că, în esență, încercați să creați totaluri pentru combinații unice de id și eventidși nu id și year. Pe baza exemplului dvs., data evenimentului și indicatorul „dată specială” (event) nu par să conteze în calcularea sumei dorite. Prin urmare,

bysort id eventid: egen _sum = total(var1)

sau mai simplu

egen _sum = total(var1) , by(id eventid)

ar trebui ca ambele să vă dea totalul dorit. În ceea ce privește

În plus, aș dori să iau în considerare valorile lipsă, astfel încât, dacă toate valorile din var1 pentru compania x sunt variabile lipsă, suma1 pentru compania x și intervalul specific trebuie să conțină valori lipsă și nu 0.

Site-ul missing opțiune de pe egen total() ar trebui să ajute să se ocupe de această condiție.


Actualizare

Nu este neapărat un îmbunătățire față de celelalte răspunsuri, ci o altă metodă (care se bazează pe faptul că evenimentele sunt în ordinea corectă în datele brute):

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 30.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 30.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 30.4.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 30.6.2009 2009 60 1 161    
end

gen _obs = _n
gen date2 = daily(date, "DMY")
format date2 %td

bys id (_obs): gen eventid = sum(date2 == td(01jan2008)) + sum(event[_n-1] == 1)
egen sum = total(var1) , by(id eventid)  missing

li , sepby(id eventid)

Comentarii

  • Vă mulțumim pentru răspuns și pentru editare. Cred că nu a fost clar în întrebarea mea că variabila event_id nu există și că aș dori să o creez mai întâi pe baza variabilei event. Numai după aceea pot folosi codul pe care l-ați sugerat. Opțiunea missing este, într-adevăr, foarte utilă. –  > Por In777.
  • Într-adevăr, am înțeles greșit. Vă mulțumim pentru clarificare. Mi-am editat răspunsul. –  > Por Brendan.
  • Vă mulțumesc încă o dată pentru ajutor. Mi-a plăcut că abordarea dvs. alternativă este foarte scurtă și eficientă. –  > Por In777.