2016-03-27 6 views
1

Das Indexierungsproblem, das ich beschrieben habe here, wurde mit der devel data.table Version 1.9.7 behoben.Meine Funktion wird in data.table aufgerufen j gibt keine erwarteten Ergebnisse zurück

Meine Frage ist zu verstehen, was ich falsch beim Senden von Daten an und von meiner eigenen Funktion gemacht habe.

Wie in der anderen Frage beschrieben, möchte ich nur das längste kontinuierliche Segment für jede gvkey behalten und wenn es mehrere Segmente gleicher Länge gibt, nehmen Sie die neueste.

DT[, fyear.lag := shift(fyear, n=1L, type = "lag"), by = gvkey] 
DT[, gap := fyear - fyear.lag] 

Hier bekomme ich die erwarteten Ergebnisse (mit data.table v1.9.7):

DT[,   step.idx := 0] # initialize 
DT[gap >=2 , step.idx := 1] # 1's at each multi-year jump 
DT[, step.idx := cumsum(step.idx), by = gvkey] # indexes each sequence by firm 
DT[ , seq.lengths := .N, by=.(gvkey,step.idx)]  # length of each sequence 
DT[, keep.seq := 1*(seq.lengths == max(seq.lengths)), by = gvkey]  # each firm's longest sequence 
DT[keep.seq==1, keep.seq := c(rep(0, (.N-max(seq.lengths))), rep(1, max(seq.lengths))), by = gvkey] 

#' expected results: 
DT.out <- DT[keep.seq==1] # 23 
DT.out[keep.seq==0, .N] # 0 
nrow(DT.out)# [1] 149 

Wenn ich im Wesentlichen den gleichen Prozess mit meiner eigenen Funktion versuche ich zusätzliche keep.seq==0 Fälle bekommen. Meine Frage ist, warum nicht ich erhalte das gleiche Ergebnis wie oben daraus:

find.seq.keep <- function(g){ 
    step.idx = rep(0, length(g)) 
    step.idx[g>=2] = 1 
    step.idx = cumsum(step.idx) 
    N.seq = length(unique(step.idx)) 

    seq.lengths = as.vector(unlist(tapply(step.idx, step.idx, 
        function(x) rep(length(x), length(x))))) 
    keep.seq = 1*(seq.lengths == max(seq.lengths)) 
    if(length(keep.seq[keep.seq == 1]) > max(seq.lengths)){ 
     N.max = max(seq.lengths) 
     N.1s = length(keep.seq[keep.seq==1]) 
     keep.seq[keep.seq==1] = c(rep(0, (N.1s-N.max)), rep(1, N.max)) 
    } 
return(as.list(keep.seq)) 
} 
DT[,keep.seqF := find.seq.keep(gap), by = gvkey] 

Entfernen der Zeilen funktioniert, aber es gibt einige Fehlalarme von dem, was zu entfernen:

DT.outF <- DT[keep.seqF==1] 
    DT.outF[keep.seqF==0, .N] # 0 
    nrow(DT.outF) # 141 (<149 = nrow(DT.out) !!) 

Ich möchte meine persönliche Funktion so einrichten, dass ich immer noch die Version 1.9.6 verwenden kann (was es einfacher macht, sie mit Kollegen zu teilen), zumindest bis 1.9.7 auf CRAN ist. Jetzt, da Frank eine Lösung für mein Problem zur Verfügung gestellt hat, möchte ich einen besseren Überblick darüber bekommen, was mit dem Argument j passiert, wenn ich find.seq.keep anrufe.

=======

** Reproduzierbare Beispieldaten ***

DT <- data.table(
    gvkey = c(1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681, 
       1681, 1681, 1681, 1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914, 
       1914, 1914, 1914, 1914, 1914, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
       2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
       2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
       2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
       2011, 2011, 2011, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 
       2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 
       2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 
       2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 
       2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2085, 2164, 2164, 2164, 2164, 
       2164, 2164, 2164, 2164, 2164, 2164, 2164, 2164, 2185, 2185, 2185, 2185, 2185, 
       2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 2185, 
       2185, 2185, 2185), 
    fyear = c(1983, 1984, 1985, 1986, 1987, 1988, 1989, 1997, 1998, 2008, 2009, 2010, 2011, 
      2012, 2013, 2014, 1983, 1984, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 
      2001, 2002, 2003, 2004, 2005, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 
      1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 
      1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 
      1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2007, 2008, 
      2009, 2010, 2011, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 
      1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 
      1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 
      1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 
      2000, 2001, 2002, 2003, 2004, 2005, 2006, 2011, 2012, 1978, 1979, 1980, 1981, 
      1982, 1983, 1984, 1985, 1986, 1989, 1990, 1991, 1970, 1971, 1972, 1973, 1974, 
      1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 
      1988, 1994, 1995)) 

setkey(DT, gvkey, fyear) 
+1

Könnten Sie bitte die Post durch Verengen der Ausgabe verkürzen? Ich – Arun

+0

Ich habe es verkürzt . –

+2

In Ihrem Q geht es nun darum, eine Funktion zu debuggen, die Sie in Base R, IIUC geschrieben haben. Und es ist höchstwahrscheinlich an dem Ort, an dem Sie 'seq.lengths' erstellen, wo Sie' gvkey, step verwenden.idx' Gruppen und nur 'step.idx' in tapply. Verwenden Sie 'debugonce()' für Ihre Funktion und führen Sie sie Zeile für Zeile erneut aus, während Sie die Ausgabe überprüfen. – Arun

Antwort

3

Ich bin mir nicht sicher, warum Ihre Funktion nicht funktioniert, aber hier ist ein alternativer Ansatz:

DT[, g := cumsum(fyear - shift(fyear, fill=fyear[1L]-1L) != 1L), by=gvkey] 
keep = DT[, 
    .(len = .N), by=.(gvkey, g)][, 
    .(g = g[tail(which(len == max(len)), 1)]), by=gvkey] 

DT.out = DT[keep, on=names(keep)] 

DT.out[, .N] # 149, as expected 

Wie es funktioniert:

  • g ist eine ID für Läufe innerhalb jedes gvkey.
  • len ist die Länge jedes Laufs.
  • g[tail(which(len == max(len)), 1)] ist die längste, brechen Bindungen durch die neuesten.
  • DT[keep, on=names(keep) ist eine Zusammenführung, die DT zu (gvkey,g) enthält, die in behalten werden.

Wenn aus irgendeinem Grund Sie eine Basisfunktion wollte, dies zu tun ...

tag.long.seq = function(x){ 
    g = cumsum(c(1L, diff(x) > 1L)) 
    len = tapply(g, g, FUN = length) 
    w = tail(which(len == max(len)), 1L) 

    ave(g, g, FUN = function(z) z[1] == w)  
} 

DT[, keepem := tag.long.seq(fyear), by=gvkey] 

DT[(keepem==1L), .N] # 149 again 
+0

Vielen Dank! Scheint wie eine sehr elegante Lösung, aber ich bekomme einen Fehler in der zweiten Zeile für 'keep':' Die Elemente in der 'by' oder 'keyby' Liste sind Länge (172,16). Jeder muss dieselbe Länge wie Zeilen in x oder Anzahl der Zeilen haben, die von i zurückgegeben werden (172). "... Was macht' '1L'' auch in' cumsum'? –

+1

@TonyBeans Hm, nicht sicher, warum Sie diesen Fehler treffen. Das '! = 1 'ist ein logischer Test, WAHR, wenn die Lücke nicht eins ist, andernfalls FALSCH. Diese werden jeweils 1/0 zugeordnet, wenn "cumsum" auf das Ergebnis angewendet wird. – Frank

+1

Sorry, es gab einen Tippfehler, als ich es versuchte. Dies funktioniert perfekt für beide Versionen von 'data.table'. Ich hatte nicht einmal von "Schwanz" - sehr nett. Vielen Dank. (Und jetzt sehe ich, was in 'Cumsum', Thnx 'vor sich geht). Obwohl dies das ultimative Problem löst, denke ich, dass ich es als Antwort ablehnen sollte, da meine Frage ein allgemeineres Problem mit dem Verständnis von "j" war. Trotzdem sehr geschätzt! –

Verwandte Themen