2016-03-19 6 views
0

Ich übe meine ML-Klassifizierung Fähigkeiten auf The Billionaire Characteristics Database Datensatz.Zeichnen Sie ein Boxplot mit einem Sframe als Datenquelle

Ich verwende sframe zum Laden und Bearbeiten der Daten und seaborn für die Visualisierung.

Im Prozess der Datenanalyse, wollte ich durch eine kategorische Variable gruppiert, um eine Box-Plot zeichnen, wie dieses von seaborn Tutorial: box plot grouped by categorical value

im Datensatz gibt es eine networthusbillion numerische Variable und selfmade kategorische Variable das heißt, ob ein Milliardär ist self-made oder (s) er hat inherited die Bucks.

Wenn ich versuche, einen ähnlichen Box-Plot zu zeichnen sns.boxplot(x='selfmade', y='networthusbillion', data=data) verwenden, wirft es die folgenden Fehler:

--------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-17-f4bd651c2ae7> in <module>() 
----> 1 sns.boxplot(x='selfmade', y='networthusbillion', data=billionaires) 

/home/iulian/.virtualenvs/data-science-python2/lib/python2.7/site-packages/seaborn/categorical.pyc in boxplot(x, y, hue, data, order, hue_order, orient, color, palette, saturation, width, fliersize, linewidth, whis, notch, ax, **kwargs) 
    2127  plotter = _BoxPlotter(x, y, hue, data, order, hue_order, 
    2128       orient, color, palette, saturation, 
-> 2129       width, fliersize, linewidth) 
    2130 
    2131  if ax is None: 

/home/iulian/.virtualenvs/data-science-python2/lib/python2.7/site-packages/seaborn/categorical.pyc in __init__(self, x, y, hue, data, order, hue_order, orient, color, palette, saturation, width, fliersize, linewidth) 
    420     width, fliersize, linewidth): 
    421 
--> 422   self.establish_variables(x, y, hue, data, orient, order, hue_order) 
    423   self.establish_colors(color, palette, saturation) 
    424 

/home/iulian/.virtualenvs/data-science-python2/lib/python2.7/site-packages/seaborn/categorical.pyc in establish_variables(self, x, y, hue, data, orient, order, hue_order, units) 
    136    # See if we need to get variables from `data` 
    137    if data is not None: 
--> 138     x = data.get(x, x) 
    139     y = data.get(y, y) 
    140     hue = data.get(hue, hue) 

AttributeError: 'SFrame' object has no attribute 'get' 

ich die folgenden Formen versucht, den Box-Plot zu zeichnen - keiner von ihnen erreichte das Ergebnis:

sns.boxplot(x=billionaires['selfmade'], y=billionaires['networthusbillion']) 
sns.boxplot(x='selfmade', y='networthusbillion', data=billionaires['selfmade', 'networthusbillion']) 

aber ich konnte einen Box-Plot zeichnen sframe verwenden, aber ohne die Gruppierung von selfmade:

sns.boxplot(x=billionaires['networthusbillion']) 

Also, meine Frage ist: Gibt es eine Möglichkeit, einen Box-Plot durch eine kategoriale Variable mit einem sframe gruppiert zu ziehen? Vielleicht mache ich etwas falsch?

By the way, schaffte ich es zu zeichnen ein pandas.DataFrame mit der gleichen Syntax (sns.boxplot(x='selfmade', y='networthusbillion', data=data)) verwendet wird, so vielleicht ein sframe mit seaborn mit Gruppierung ist nur noch nicht implementiert.

Antwort

0

TL; DR

Gruppierung eine sframe mit seaborn verwendet, ist nur noch nicht implementiert.


in die Quellcode der Seaborn Nach dem Graben fand ich heraus, dass es speziell mit pandas.DataFrame arbeitet ausgelegt ist.Unter der Vorschlag der absolutelyNoWarranty in ihrer Antwort, ich folgende Fehlermeldung bekam:

TypeError: __getitem__() takes exactly 2 arguments (3 given) 

einen Blick auf den args in der get Funktion auf Anruf annimmt, gibt es diese Daten:

('gender', 'gender') 

Dies geschieht, weil dieser Code im Quelltext für BoxPlot:

# See if we need to get variables from `data` 
if data is not None: 
    x = data.get(x, x) 
    y = data.get(y, y) 
    hue = data.get(hue, hue) 
    units = data.get(units, units) 

Es wird versucht, den Wert zu erhalten, und verwendet den gleichen Wert wie ein fallb ack, falls es nicht existiert. Dies verursacht einen Fehler in der __getitem__(), weil es mit (self, 'gender', 'gender') Argumente aufgerufen wird.

Ich versuchte, die get() Funktion wie folgt zu umschreiben:

def get(self, *args): 
    return self.__getitem__(args[0]) if args[0] else None # The `None` is here because the `units` in the source code is `None` for boxplots. 

Und hier habe ich den Fehler bekam, dass meine Versuche beendet:

TypeError: 'SArray' object is not callable 

einen Blick auf den Quellcode nehmen, überprüft er, ob Die y Daten sind ein pd.Series und wenn nicht, konvertiert es y Wert in eins:

if not isinstance(vals, pd.Series): 
    vals = pd.Series(vals) 

# Group the val data 
grouped_vals = vals.groupby(grouper) 

Bei der Ausführung der vals.groupby(grouper) (Grouper ist immer noch eine SArray Instanz), geht es in Pandas Kernarbeiten wo der SArray aufgerufen wird und der Fehler ausgelöst wird. Ende der Geschichte.

+0

Ich habe meine Antwort bearbeitet. Sehen Sie, ob es hilft (obwohl es zu diesem Zeitpunkt vielleicht zu hackig ist.) – absolutelyNoWarranty

0

Das Problem ist, dass sns.boxplot Daten erwartet, eine get Methode wie ein Pandas Dataframe zu haben. In Pandas gibt die get-Methode eine einzelne Spalte zurück, so dass sie mit der Indexierung der Klammer übereinstimmt, d. H. your_df['your_column_name'].

Der einfachste Weg, um dies zu umgehen, ist die to_dataframe Methode auf Ihrem Sframe aufrufen, um es in einen Datenrahmen zu konvertieren.

sns.boxplot(x='selfmade', y='networthusbillion', data=data.to_dataframe()) 

Alternativ können Sie, um das Problem hacken nach Klasse Wrapper um zu schreiben oder monkey-patchingget auf die SFrame-Klasse.

import numpy as np 
import sframe 
import pandas as pd 
import seaborn as sns 
import matplotlib.pyplot as plt 

# For demostration purposes 
def to_sframe(df): 
    import sframe 
    d = {} 
    for key in df.keys(): 
     d[key] = list(df[key]) 
    return sframe.SFrame(d) 
pd.DataFrame.to_sframe = to_sframe 

tips = sns.load_dataset('tips') 

# Monkey patch sframe's get and _CategoricalPlotter's _group_longform 
def get(self, *args): 
    key = args[0] 
    return self.__getitem__(key) if key else None 
sframe.SFrame.get = get 


def _group_longform(self, vals, grouper, order): 
    """Group a long-form variable by another with correct order.""" 
    #import pdb;pdb.set_trace() 

    if type(vals) == sframe.SArray: 
     _sf = sframe.SFrame({'vals':vals, 'grouper':grouper}) 
     grouped_vals = _sf.groupby('grouper', sframe.aggregate.CONCAT('vals')) 
     out_data = [] 
     for g in order: 
      try: 
       g_vals = np.asarray(grouped_vals.filter_by(g, 'grouper')["List of vals"][0]) 
      except KeyError: 
       g_vals = np.array([]) 
      out_data.append(g_vals) 
     label = "" 
     return out_data, label 

    ## Code copied from original _group_longform 
    # Ensure that the groupby will work 
    if not isinstance(vals, pd.Series): 
     vals = pd.Series(vals) 

    # Group the val data 
    grouped_vals = vals.groupby(grouper) 
    out_data = [] 
    for g in order: 
     try: 
      g_vals = np.asarray(grouped_vals.get_group(g)) 
     except KeyError: 
      g_vals = np.array([]) 
     out_data.append(g_vals) 

    # Get the vals axis label 
    label = vals.name 

    return out_data, label 

sns.categorical._CategoricalPlotter._group_longform = _group_longform 


# Plots should be equivalent 
#1. 
plt.figure() 
sns.boxplot(x="day", y="total_bill", data=tips) 
#2. 
plt.figure() 
sns.boxplot(x="day", y="total_bill", data=tips.to_sframe(), 
      order=["Thur", "Fri", "Sat", "Sun"]) 
plt.xlabel("day") 
plt.ylabel("total_bill") 

plt.show() 
+0

Vielen Dank für Ihre Antwort. Die von Ihnen bereitgestellte Problemumgehung ist gültig, obwohl ich untersuchen muss, wie kostspielig die 'to_dataframe()' - Konvertierung ist. Das Affepatching funktioniert jedoch nicht. Ich bin in den Quellcode "seaborn" getaucht und seine Methoden sind speziell für die Arbeit mit Datenrahmen entwickelt. – iulian

+0

und hier ist die schnelle Antwort aus der ['sframe' Dokumentation] (https://dato.com/products/create/docs/generated/graphlab.SFrame.to_dataframe.html#graphlab.SFrame.to_dataframe) für' to_dataframe() ':" Diese Operation erstellt einen Pandas.DataFrame im Speicher. Vorsicht ist geboten, wenn die Größe des zurückgegebenen Objekts groß ist. " Also, leider, das ist auch keine gültige Option. – iulian

Verwandte Themen