2017-12-20 7 views
0

Was ich tun möchte:

ich zur Zeit eine Unterklasse der pandasDataFrame Python mit am Aufbau 3. Ein Merkmal der Klasse wird der Benutzer ihre data-Eingänge sowie die Namen der Spalten zum Erstellen einer MultiIndex für die Klasse zum Zeitpunkt der Konstruktion zu verwenden. Ich kämpfe jedoch dafür, einen sauberen Weg zu finden.Einstellung Indizes in Pandas Datenrahmen Unterklasse

Fehlgeschlagen Strategie # 1

Mein erster Versuch sah so etwas wie die folgenden, wo ich versuchen, die Daten und die Indexwerte zu konstruieren, bevor Sie den DataFrame Konstruktor aufrufen:

class DFSubClass(pd.DataFrame): 
    @property 
    def _constructor(self): 
     return DFSubClass 

    def __init__(self, data=None, #other DataFrame parameters#, 
       col_for_multi_index = None): 

     multi_index = CreateMultiIndex(data, col_for_multi_index) 
     data_subset = RemoveIndexColumnsFromData(data, col_for_multi_index) 

     super(DFSubClass,self).__init__(data = data_subset, 
               index = multi_index, 
               #other DataFrame parameters#) 

     multi_index = ComputeMultiIndexFromColumns(data, col_for_multi_index) 

     self = self.set_index(multi_index) 

Während ich Fabrikate der Lage war, etwas, das ich Werke für ComputeMultiIndexFromColumns() denken:

def ComputeMultiIndexFromColumns(data = None, cols = None): 
    index_values = [np.array(data[i]) for i in cols] 
    index = pd.MultiIndex.from_arrays(index_values, names=cols) 
    return index 

ich herausfinden konnte nichts für RemoveIndexColumnsFromData(), das alle unterschiedlichen Datentypen sauber verarbeitet, die ein pandas-Konstruktor akzeptieren kann (d. H. numpy arrays, dicts, andere DataFrame s). Auch wenn die Eingabe eine DataFrame war, lief ich in this problem, wo der Konstruktor alle NaN s zurückgibt, da die vorherigen Indizes nicht mit den neuen index Werten übereinstimmen.

Fehlgeschlagen Strategie # 2

An dieser Stelle habe ich beschlossen, nicht das Rad neu erfinden und lassen Sie die pandas Paket diese Probleme umgehen, indem zuerst die DataFrame Konstruktor aufrufen und dann die set_index() Funktionalität mit meiner Daten neu Index:

class DFSubClass(pd.DataFrame): 
    @property 
    def _constructor(self): 
     return DFSubClass 

    def __init__(self, data=None, #other DataFrame parameters#, 
       col_for_multi_index = None): 

     super(DFSubClass,self).__init__(data = data, 
               #other DataFrame parameters#) 

     multi_index = ComputeMultiIndexFromColumns(data, col_for_multi_index) 

     self = self.set_index(multi_index) 

Heilige unendliche Rekursion Batman! Es stellt sich heraus, dass die Funktion set_index() den Konstruktor aufruft, um die DataFrame neu zu indizieren, was bedeutet, dass diese Funktion sich selbst für immer aufruft.

Wo bin ich jetzt

Ich fühle mich ein bisschen stecken. Zurück zur ersten Strategie scheint das zu sein, was ich tun muss, aber ich zögere ein wenig, mit allen Datentypen umzugehen, besonders wenn pandas dieses Problem bereits gelöst hat. Wenn jemand weiß, wie ich entweder 1) Funktionen bereits in pandas wirksam zu machen, um dies sauber zu machen oder 2) eine alternative Strategie zur Lösung dieses Problems, wäre ich sehr dankbar.

Antwort

0

Der Schlüssel dazu endete mit inplace=True, also sah meine endgültige Klassendefinition so aus.

class DFSubClass(pd.DataFrame): 

    @property 
    def _constructor(self): 
     return DFSubClass 

    def __init__(self, data=None, #other DataFrame parameters#, 
       col_for_multi_index = None): 

     super(DFSubClass,self).__init__(data = data 
             #, other DataFrame parameters# 
             ) 

     self = self.set_index(col_for_multi_index, inplace = True) 

Die inplace=True verhindert, dass der Konstruktor aus aufgerufen wird und verhindert, dass das unendliche Rekursion Problem.

Wenn das Objekt data bereits einen Index festgelegt hat, werden diese Spalten aus den Daten entfernt. Wenn diese Spalten stattdessen in DFSubClass zurückgesetzt werden sollen, müssen Sie zuerst reset_index(inplace=True) aufrufen. Das hat jedoch den Nachteil, dass reset_index() Ihnen eine neue Spalte in DFSubClass gibt, die nur die Werte von 0 bis DFSubClass.size[0] enthält, wenn der Index nur der Standardindex war.Der folgende Code kann dies verhindern:

if not isinstance(self.index, pd.Int64Index): 
    self.reset_index(inplace=True) 

dies jedoch auch um den Anruf zu reset_index() verhindern, wenn der Index eine der Klassen, die von Int64Index wie DateTimeIndex erbt. Ich habe noch keine saubere Lösung gefunden, daher habe ich gerade eine Funktion, die prüft, ob self.index eine pd.Int64Index ist, aber keine der anderen Klassen, die ich kenne, die von pd.Int64Index anders als pd.RangeIndex erben.

Verwandte Themen