2017-12-04 3 views
2

Ich habe einige Schwierigkeiten mit erweiterten Operationen in dplyr mit gruppierten Daten. Ich bin mir nicht sicher wie angegeben wird, wenn ich auf einen Wert der Beobachtungsstufe verweisen möchte und wenn ich speziell auf den gesamten Vektor verweisen kann.bezieht sich auf Vektor vs Zeile mit gruppierten Daten in dplyr (R)

Beispieldatenrahmen:

df <- as.data.frame(
    rbind(
    c(11990, 2011, 1, 1, 2010), 
    c(11990, 2015, 1, 0, NA), 
    c(11990, 2017, 2, 1, NA), 
    c(11990, 2018, 2, 1, 2016), 
    c(11990, 2019, 2, 1, 2019), 
    c(11990, 2020, 1, 0, NA), 
    c(22880, 2013, 1, 1, NA), 
    c(22880, 2014, 1, 0, 2011), 
    c(22880, 2015, 1, 1, NA), 
    c(22880, 2018, 2, 0, 2014), 
    c(22880, 2020, 2, 0, 1979))) 
names(df) <- c("id", "year", "house_apt", "moved", "year_moved") 

# > df 
#  id year house_apt moved year_moved 
# 1 11990 2011   1  1  2010 
# 2 11990 2015   1  0   NA 
# 3 11990 2017   2  1   NA 
# 4 11990 2018   2  1  2016 
# 5 11990 2019   2  1  2019 
# 6 11990 2020   1  0   NA 
# 7 22880 2013   1  1   NA 
# 8 22880 2014   1  0  2011 
# 9 22880 2015   1  1   NA 
# 10 22880 2018   2  0  2014 
# 11 22880 2020   2  0  1979 

Wenn ich einfach mutieren Operationen ausführen:

library(dplyr) 
df %>% mutate(year+2) 
df %>% group_by(id) %>% mutate(year+2) 

Es ist ziemlich offensichtlich, dass „Jahr“ hier auf jeden einzelnen Zeilenwert bezieht. Dies ist auch dann der Fall, wenn ich es (aus irgendeinem Grund) mit einer Gruppierung machen würde. Aber wenn ich die folgenden zwei Operationen zu tun, die eine Vektoroperation beinhalten:

df %>% mutate(sum(year)) 
df %>% group_by(id) %>% mutate(sum(year)) 

dplyr versteht „Jahr“, wie der gesamte Vektor der Jahreswerte für die gesamte Gruppe.

Allerdings habe ich jetzt eine Menge Probleme mit einer Operation, wo es mehrdeutig ist, ob ich mutate den Zeilenwert oder den gesamten Vektor verwenden möchte. Mit meinem Datenrahmen möchte ich eine Variable erstellen, die ein bewegtes Jahr für Personen, die sich bewegt haben, aber nicht das Bewegungsdatum bis zu einer späteren Befragungsinstanz aufgezeichnet hat. Beachten Sie, dass die Daten extrem unordentlich sind, mit einigen unsinnigen Verschiebungsterminen, die wir ignorieren wollen.

Daher möchte ich einen "rate" -Wert für jede Zeile, wo eine Person bewegte, aber keine move_year aufgezeichnet wird. Ich möchte, dass der Vorgang den gesamten Vektor der Verschiebungstermine für jedes einzelne Element durchgeht, wobei die Teilmenge nur die Elemente enthält, die vor dem aktuellen Jahr liegen, und dasjenige auswählen, das dem Jahr für die aktuelle Zeile am nächsten kommt. Granulares Beispiel: Wenn wir uns Zeile 3 ansehen, bewegte sich die Person in diesem Jahr, aber es gibt kein Verschiebungsdatum. Daher wollen wir den gesamten year_moved-Vektor für diese Person betrachten (2010, NA, NA, 2016, 2019, NA) und wählen Sie diejenige, die am nächsten ist und vorzugsweise früher als der Zeile # 3 Wert des Jahres (2017). Der Schätzwert wäre daher 2016.

Abrufen der Wert, den wir mit einem bestimmten Jahr und Vektor von Werten wollen, ist einfach:

year <- 2017 
year_moved <- c(2010, 2016, 2017) 
year_moved[which.min(year-(year_moved[year_moved<year & !is.na(year_moved)]))] 
# [1] 2016 
rm(year, year_moved) 

Allerdings, wenn ich in einer mutieren Funktion versuchen, dies, ist es mir nicht das gleiche Ergebnis.

df %>% 
    group_by(id) %>% 
    mutate(
    year_guess = ifelse(moved==1 & is.na(year_moved), 
         year_moved[which.min(year-(year_moved[year_moved<year]))], 
         NA)) 
# # A tibble: 11 x 6 
# # Groups: id [2] 
#  id year house_apt moved year_moved guess 
# <dbl> <dbl>  <dbl> <dbl>  <dbl> <dbl> 
# 1 11990 2011   1  1  2010 NA 
# 2 11990 2015   1  0   NA NA 
# 3 11990 2017   2  1   NA NA 
# 4 11990 2018   2  1  2016 NA 
# 5 11990 2019   2  1  2019 NA 
# 6 11990 2020   1  0   NA NA 
# 7 22880 2013   1  1   NA 2011 
# 8 22880 2014   1  0  2011 NA 
# 9 22880 2015   1  1   NA 2011 
# 10 22880 2018   2  0  2014 NA 
# 11 22880 2020   2  0  1979 NA 
# Warning message: 
# In year - (year_moved[year_moved < year & !is.na(year_moved)]) : 
# longer object length is not a multiple of shorter object length 

(Zeile 3 sollte 2016 sein und Zeile 9 sollte 2014 sein) Ich denke, ein Teil davon meine Unfähigkeit, ob ich Interesse an einer Reihe-Wert oder einen Vektor angeben ist. Beachten Sie, dass ich mich beim ersten Mal auf "year_moved" (is.na(year_moved)) auf den Wert in dieser Zeile beziehe. Wenn ich innerhalb der which.min darauf Bezug nehme, versuche ich auf den groupwise Vektor zu verweisen. Wenn ich mich auf "Jahr" beziehe, versuche ich, auf den Wert der einzelnen Zeile, in der ich arbeite, zu verweisen. Offensichtlich sind die Dinge ein wenig durcheinander, und es ist ein breiteres Problem, mit dem ich viele verschiedene Anwendungen konfrontiert habe. Kann jemand Anleitung geben?

Ich habe mein ganzes Projekt mit Hilfe von Tidyverse geschrieben und möchte so fortfahren, wenn möglich.

+0

Re‘Es ist ziemlich offensichtlich, dass“ Jahr ... nicht so offensichtlich. 'Jahr + 2' ist eine vektorisierte Operation (mit Wiederverwendung von' 2'). 'dplyr'" versteht "immer eine Variable als den ganzen Vektor (möglicherweise in einer Gruppe) und nicht als einen einzigen Wert auf der Beobachtungsebene. –

+0

Oh interessant. Also ist die ganze Prämisse meiner Frage falsch. Sie beziehen sich im Grunde niemals auf einen Zeilenwert innerhalb von mutate, Sie rufen immer den gesamten Vektor auf. Jetzt, wo Sie darauf hinweisen, ist es sehr intuitiv. – MrMr

+0

Verwenden Sie also eine Anwendungsfunktion, wie @Marius unten zeigt, ist die einzige Möglichkeit, eine Operation auszuführen, die nur den Wert für diese Zeile und nicht den gesamten Vektor enthält? Oder gibt es einen etwas allgemeineren Weg, dies zu tun? Ich versuche mehr von der Intuition hinter vektorisierten/nicht-vektorisierten Funktionen zu verstehen, also wäre jede Hilfe großartig. – MrMr

Antwort

1

ich denke, die einfachste Art und Weise Ihren aktuellen Versuch zu ändern, die richtigen Ergebnisse zu erhalten, ist das Erraten Betrieb in sapply so wickeln, dass eine Vermutung separat für jedes Jahr berechnet:

df %>% 
    group_by(id) %>% 
    mutate(
     year_guess = ifelse(
      moved==1 & is.na(year_moved), 
      sapply(year, function(x) year_moved[which.min(x-(year_moved[year_moved < x]))]), 
      NA) 
     ) 

Ich habe nicht Ich war in der Lage, die Logik, wie das funktioniert, vollständig zu entschlüsseln, aber ich denke, wie beschrieben ist Ihr Schätzverfahren ein wenig komplex, um leicht vektorisiert zu werden (obwohl es wahrscheinlich sein kann, wenn Sie es auf eine etwas andere Weise angehen).

Ausgang: „hier auf jede einzelne Zeile Wert bezieht sich‚

# A tibble: 11 x 6 
# Groups: id [2] 
     id year house_apt moved year_moved year_guess 
    <dbl> <dbl>  <dbl> <dbl>  <dbl>  <dbl> 
1 11990 2011   1  1  2010   NA 
2 11990 2015   1  0   NA   NA 
3 11990 2017   2  1   NA  2016 
4 11990 2018   2  1  2016   NA 
5 11990 2019   2  1  2019   NA 
6 11990 2020   1  0   NA   NA 
7 22880 2013   1  1   NA  2011 
8 22880 2014   1  0  2011   NA 
9 22880 2015   1  1   NA  2014 
10 22880 2018   2  0  2014   NA 
11 22880 2020   2  0  1979   NA 
+0

Danke für diese @Marius.Dies ist eine große Hilfe für das spezifische Problem zur Hand : "Ich bin nicht in der Lage gewesen, die Logik der Funktionsweise vollständig auszupacken, aber ich denke, dass Ihr Schätzverfahren wie beschrieben ein wenig komplex ist, um leicht vektorisiert zu werden (obwohl es wahrscheinlich sein kann, wenn Sie es etwas anders angehen) "Interessiert an allgemeinen Lösungen? – MrMr

+0

Außerdem scheint (für die Referenz von anderen), dass die Sapply-Funktion am besten in einen unlist() -Aufruf eingeschlossen ist, um einen schön formatierten Vektor in das df zu übergeben, im Gegensatz zu eine Liste. – MrMr