2016-07-26 11 views
5

Ich habe einen großen Datensatz (> 200k) und ich versuche Nullsequenzen durch einen Wert zu ersetzen. Eine Nullsequenz mit mehr als 2 Nullen ist ein Artefakt und sollte entfernt werden, indem man sie auf np.NAN setzt.Ersetzen Sie eine Null-Sequenz durch einen anderen Wert

Ich habe Searching a sequence in a NumPy array gelesen, aber es hat meine Anforderung nicht vollständig erfüllt, da ich kein statisches Muster habe.

np.array([0, 1.0, 0, 0, -6.0, 13.0, 0, 0, 0, 1.0, 16.0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 1.0]) 
# should be converted to this 
np.array([0, 1.0, 0, 0, -6.0, 13.0, NaN, NaN, NaN, 1.0, 16.0, NaN, NaN, NaN, NaN, 1.0, 1.0, 1.0, 1.0])  

Wenn Sie weitere Informationen benötigen, lassen Sie es mich wissen. Vielen Dank im Voraus!


Ergebnisse:

divakar took 0.016000ms to replace 87912 points 
desiato took 0.076000ms to replace 87912 points 
polarise took 0.102000ms to replace 87912 points 

Als @ Divakar Lösung

Danke für die Antworten, hier sind auf 288.240 Punkte my (unprofessionell) Testergebnisse läuft die kürzeste und schnellste ich seine einzige akzeptieren.

Antwort

3

Nun, das ist im Grunde ein binary closing operation mit einer Schwelle Anforderung an die Schließung Lücke. Hier ist eine Implementierung basierend auf sie -

# Pad with ones so as to make binary closing work around the boundaries too 
a_extm = np.hstack((True,a!=0,True)) 

# Perform binary closing and look for the ones that have not changed indiicating 
# the gaps in those cases were above the threshold requirement for closing 
mask = a_extm == binary_closing(a_extm,structure=np.ones(3)) 

# Out of those avoid the 1s from the original array and set rest as NaNs 
out = np.where(~a_extm[1:-1] & mask[1:-1],np.nan,a) 

Ein Weg, um zu vermeiden, dass je nach Bedarf in dem früheren Verfahren Anhänge mit Begrenzungselementen zu arbeiten, die es ein bisschen teuer machen könnten, wenn sie mit großer Datenmenge zu tun, wäre wie so -

# Create binary closed mask 
mask = ~binary_closing(a!=0,structure=np.ones(3)) 
idx = np.where(a)[0] 
mask[:idx[0]] = idx[0]>=3 
mask[idx[-1]+1:] = a.size - idx[-1] -1 >=3 

# Use the mask to set NaNs in a 
out = np.where(mask,np.nan,a) 
+0

Funktioniert wie ein Charme - danke! – ppasler

+0

@ppasler Wären Sie so freundlich, uns mitzuteilen, wie die aufgeführten Ansätze in Bezug auf die Laufzeit auf Ihrem großen Dataset (> 200 KB) funktionieren? – Divakar

+0

Sicher, siehe die Ergebnisse nach der Frage – ppasler

1

Hier ist eine Funktion, die Sie für Ihre Listen verwenden können:

import numpy as np 

def replace(a_list): 
    for i in xrange(len(a_list) - 2): 
     print a_list[i:i+3] 
     if (a_list[i] == 0 and a_list[i+1] == 0 and a_list[i+2] == 0) or (a_list[i] is np.NaN and a_list[i+1] is np.NaN and a_list[i+2] == 0): 
      a_list[i] = np.NaN 
      a_list[i+1] = np.NaN 
      a_list[i+2] = np.NaN 
    return a_list 

Da die Liste in eine Richtung durchlaufen wird, gibt es nur zwei Vergleiche: (0, 0, 0) oder (NaN, NaN, 0), weil Sie durch NaN ersetzen, wie Sie gehen.

+0

Danke für diese Lösung. Ich erhalte einen 'ValueError: kann Float NaN nicht in Integer umwandeln' in Zeile 'data [i] = np.NaN' – ppasler

+0

Wenden Sie dies auf eine Liste oder auf ein' np.array' an? Ich denke du solltest es so benutzen: 'np.array (replace (the_list))' ... – polarise

+0

Yap, du hast recht mit einer Liste hab den Trick - danke – ppasler

1

Sie groupby des itertools Paket verwenden könnte

import numpy as np 
from itertools import groupby 

l = np.array([0, 1, 0, 0, -6, 13, 0, 0, 0, 1, 16, 0, 0, 0, 0]) 

def _ret_list(k, it): 
    # number of elements in iterator, i.e., length of list of similar items 
    l = sum(1 for i in it) 

    if k==0 and l>2: 
     # sublist has more than two zeros. replace each zero by np.nan 
     return [ np.nan ]*l 
    else: 
     # return sublist of simliar items 
     return [ k ]*l 

# group items and apply _ret_list on each group 
procesed_l = [_ret_list(k,g) for k,g in groupby(l)] 
# flatten the list and convert to a numpy array 
procesed_l = np.array([ item for l in procesed_l for item in l ]) 

print procesed_l 

, die Sie gibt

[ 0. 1. 0. 0. -6. 13. nan nan nan 1. 16. nan nan nan nan] 

beachten Sie, dass jede int zu einem float umgewandelt werden. siehe hier: NumPy or Pandas: Keeping array type as integer while having a NaN value

+0

Funktioniert gut - danke! Ich bevorzuge @Divakar Lösung, da es ein bisschen kürzer ist. – ppasler

+0

Nur herausgefunden, dass jede Sequenz mit den gleichen Zahlen ersetzt wird: '[1.0, 1.0, 1.0, 1.0, 0]' führt zu [NaN, Nan, NaN, NaN, 0] ' – ppasler

+0

ah, ja.Ich habe meine Antwort korrigiert, indem ich eine weitere Bedingung zu if-Anweisung hinzufüge: – desiato

Verwandte Themen