2016-07-05 11 views
1

Frage:In einem Datenrahmen, für jedes Element einer Spalte mit dem Index des nächstkleineren Wert finden

In einem Datenrahmen, habe ich eine neue Spalte als die Indizes der nächst kleineren Wert eines zu erstellenden vorhandene Spalte.

Zum Beispiel sehen die Daten so aus. Es ist bereits in item, day angeordnet.

item day val 
1 1 2 3 
2 1 4 2 
3 1 5 1 
4 2 1 1 
5 2 3 2 
6 2 5 3 

Zuerst möchte ich group_by(item) in dplyr verwenden, um die Unterdatenrahmen jedes Element auszuwählen.

Dann für Zeile 1, ich Blick nach unten die Zeilen und finden Sie, dass Zeile 2 hat eine kleinere val. Dies ist, was ich will, also notiere ich die day entsprechend dieser Reihe. Ähnliche für die Zeile 2.

anzumerken, dass für die Zeile 3 und 6, sie sind die letzten Reihen der entsprechenden Teildatenrahmen sind, so gibt es keinen nächsten kleineren Wert. Für Zeile 4 und 5 gibt es keinen kleineren val, wenn ich die Zeilen nach unten schaue.

Der Datenrahmen mit der neuen Spalte sollte so aussehen.

item day val next.smaller.day 
1 1 2 3    4 
2 1 4 2    5 
3 1 5 1    -1 
4 2 1 1    -1 
5 2 3 2    -1 
6 2 5 3    -1 

Ich frage mich, ob es eine Möglichkeit ist dplyr der Verwendung dieses zu implementieren, oder irgendwelche Codes in r andere als eine for-Schleife.

fand ich einen Thread den Algorithmus dieser Frage zu stellen. Given an array, find out the next smaller element for each element. Es ist wichtig, und der vorgeschlagene Algorithmus schlägt Mine in Bezug auf die Zeit Komplexität, aber ich finde immer noch schwer, es in meinem Szenario zu implementieren.

Vielen Dank!

Update:

Hier ist ein weiteres Beispiel neu zu illustrieren, was ich suche.

item day val next.smaller.day 
1 1 2 2    5 
2 1 4 3    5 
3 1 5 1    -1 
4 2 1 3    3 
5 2 3 1    -1 
6 2 5 2    -1 

Antwort

0

können Sie gruppieren Sie Ihre Daten durch die Artikel, die Berechnung der verschiedenen zwischen den Reihen mit der diff Funktion und überprüfen, ob es kleiner als Null ist, die dann einen logischen Vektor erzeugen wird und Sie die Logik Vektor abholen können am nächsten Tag. Und da Sie Kommissionierung am nächsten Tag, müssen Sie die lead Funktion des Tages Säule nach vorne verschieben, so dass sie die Zeilen entsprechen können, wo Sie wollen, dass sie platzieren.

Exkurs: Da diff Funktion einen Vektor ein Element kürzer als das Original und Sie werden die letzte Zeile aus je Gruppe, wir können Pad das diff Ergebnis durch einen FALSE Zustand immer verlassen.

library(dplyr); 
df %>% group_by(item) %>% mutate(smaller = c(diff(val) < 0, F), 
           next.smaller.day = ifelse(smaller, lead(day), -1)) %>% 
     select(-smaller) 

# Source: local data frame [6 x 4] 
# Groups: item [2] 

# item day val next.smaller.day 
# <int> <int> <int>   <dbl> 
# 1  1  2  3    4 
# 2  1  4  2    5 
# 3  1  5  1    -1 
# 4  2  1  1    -1 
# 5  2  3  2    -1 
# 6  2  5  3    -1 

aktualisieren:

find.next.smaller <- function(ini = 1, vec) { 
    if(length(vec) == 1) NA 
    else c(ini + min(which(vec[1] > vec[-1])), 
      find.next.smaller(ini + 1, vec[-1])) 
}  # the recursive function will go element by element through the vector and find out 
     # the index of the next smaller value. 

df %>% group_by(item) %>% mutate(next.smaller.day = day[find.next.smaller(1, val)], 
           next.smaller.day = replace(next.smaller.day, is.na(next.smaller.day), -1)) 

# Source: local data frame [6 x 4] 
# Groups: item [2] 
# 
# item day val next.smaller.day 
# <int> <int> <dbl>   <dbl> 
# 1  1  2  2    5 
# 2  1  4  3    5 
# 3  1  5  1    -1 
# 4  2  1  1    -1 
# 5  2  3  2    -1 
# 6  2  5  3    -1 
+0

Vielen Dank für Ihre Antwort. Was Sie getan haben, funktioniert in dem gegebenen Beispiel. Es ist jedoch möglich, dass der nächstkleinere Wert nicht in der nächsten Zeile ist.Zum Beispiel, wenn "val" ist "2,3,1" und "Tag" ist "2,4,5", erwarte ich, dass die Ausgabe "5,5, -1". Haben Sie eine Idee, wie Sie das umsetzen können? –

+0

Siehe das Update. Sie können eine rekursive Funktion schreiben, um den Index des nächstkleineren Wertes zu finden, und dann mit der Funktion 'dplyr' anwenden. – Psidom

+0

Vielen Dank! Ich habe versucht, eine Funktion zu schreiben, um mein Ziel zu erreichen, aber ich konnte es nicht herausfinden. Ihre Lösung funktioniert sehr gut. Lassen Sie mich den Geist der rekursiven Natur Ihrer Funktion lernen und versuchen Sie es beim nächsten Mal anzuwenden. Vielen Dank nochmal! –