2017-11-02 1 views
2

Ich kodiere einen Hash-Table-Ish-Indexierungsmechanismus, der eine Intervallzahl (0 bis n) einer Ganzzahl gemäß einer Menge von Teilungspunkten zurückgibt.Pythonische Methode zum Indexieren von Intervallen von Ganzzahlen von Teilungspunkten

Wenn beispielsweise ganze Zahlen im Wert 3 (ein Teilungspunkt, so dass zwei Intervalle) aufgeteilt sind, können wir die Intervallnummer für jedes Array-Element finden einen einfachen Vergleich verwendet:

>>> import numpy as np 
>>> x = np.array(range(7)) 
>>> [int(i>3) for i in x] 
[0, 0, 0, 0, 1, 1, 1] 

Wenn es viele Intervalle können wir eine Funktion wie folgt definieren:

>>> def get_interval_id(input_value, splits):                                        
...  for i,split_point in enumerate(splits): 
...   if input_value < split_point: 
...    return i 
...  return len(splits) 
... 
>>> [get_interval_id(i, [2,4]) for i in x] 
[0, 0, 1, 1, 2, 2, 2] 

Aber diese Lösung sieht nicht elegant aus. Gibt es einen Python (besser) Weg, diesen Job zu machen?

Antwort

2

aussehen Seit verwenden Sie es schon, würde ich vorschlagen, dass Sie die digitize Methode von numpy verwenden:

>>> import numpy as np 
>>> np.digitize(np.array([0, 1, 2, 3, 4, 5, 6]), [2, 4]) 
array([0, 0, 1, 1, 2, 2, 2]) 

Vom documentation:

Geben Sie die Indizes der Klassen zurück, zu denen jeder Wert im Eingabe-Array gehört.

+0

Nein, sie beginnen bei 0. Wenn Sie möchten, dass sie anders beginnen, fügen Sie die Bins entsprechend ein. –

+0

Danke. Genau das habe ich gesucht. Ich bin relativ wohl mit numpy, aber erkannte die Existenz dieser Funktion nicht. Der Name dieser Funktion ist nicht sehr intuitiv, zumindest für mich. Hast du irgendwelche Vorschläge, um mich besser mit numpy vertraut zu machen? –

+0

Wenn Sie Ihre 'pandas' /' numpy' Fähigkeiten üben möchten, beginnen Sie Data Science. (zum Beispiel kaggle Wettbewerbe). Wenn meine Antwort Ihre Frage gelöst hat, akzeptieren Sie sie bitte. –

2

Python, per se, hat für diesen Prozess keine ausführbare Funktion, Binning genannt. Wenn Sie wollten, könnten Sie Ihre Funktion in einen einzeiligen Befehl einfügen, aber auf diese Weise ist sie besser lesbar.

Allerdings haben Datenrahmenpakete normalerweise voll ausgestattete Binning-Methoden; Das bekannteste in Python ist PANDAS. Auf diese Weise können Sie Werte nach gleichen Intervallen, gleichen Unterteilungen (gleiche Anzahl an Einträgen in jedem Fach) oder benutzerdefinierten Teilungswerten (Ihr Fall) sammeln oder klassifizieren. Eine gute Diskussion und Beispiele finden Sie unter this question.

Das bedeutet natürlich, dass Sie pandas installieren und importieren und Ihre Liste in einen Datenrahmen konvertieren müssen. Wenn das zu viel Mühe ist, behalte einfach deine aktuelle Implementierung bei; es ist lesbar, geradlinig und relativ kurz.

1

Wie wäre es, den gesamten Prozess innerhalb einer Funktion statt nur der Hälfte des Prozesses zu verpacken?

>>> get_interval_ids([0 ,1, 2, 3, 4, 5 ,6], [2, 4]) 
[0, 0, 1, 1, 2, 2, 2] 

und Ihre Funktion wie

def get_interval_ids(values, splits): 

    def get_interval_id(input_value): 
     for i,split_point in enumerate(splits): 
      if input_value < split_point: 
       return i 
     return len(splits) 

    return [get_interval_id(val) for val in values] 
+0

Warum ist es besser, es einzupacken? bitte ausführlicher! –

+0

@JiangXiang - Ob es besser ist, hängt davon ab, wie Sie es verwenden möchten. Im Allgemeinen sollte eine Funktion eine vollständige Aufgabe ausführen. Wenn Sie eine Liste von interval_ids mit einer Liste von Zahlen erhalten möchten, sollte Ihre Funktion genau das tun. Nicht mehr, nicht weniger. – noslenkwah

+0

Vielen Dank für Ihre Erklärung! –

Verwandte Themen