2016-03-19 22 views
0

我在The Billionaire Characteristics Database數據集上練習了我的ML分類技能。使用sframe作爲數據源繪製boxplot

我使用sframe來加載和操作數據,seaborn用於可視化。

在數據分析的過程中,我想從seaborn教程畫一個框陰謀分類變量分組,像這樣的: box plot grouped by categorical value

在數據集中,有一個networthusbillion數值變量和selfmade分類變量這表明億萬富翁是self-made或(s)他有inherited雄鹿。

當我嘗試繪製使用sns.boxplot(x='selfmade', y='networthusbillion', data=data)類似盒子的情節,它引發以下錯誤:

--------------------------------------------------------------------- 
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' 

我嘗試以下幾種形式繪製箱線圖 - 他們沒有取得結果:

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

不過,我可以畫使用sframe箱線圖,但沒有通過selfmade分組:

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

所以,我的問題是:有沒有一種方法來繪製通過使用sframe分類變量分組箱線圖?也許我做錯了什麼?

順便說一句,我設法用pandas.DataFrame使用相同的語法(sns.boxplot(x='selfmade', y='networthusbillion', data=data))來繪製它,使用與seabornsframe只是還沒有實現,所以也許分組。

回答

0

TL; DR

使用與seabornsframe分組只是尚未實現。


挖到seaborn的源代碼後,我發現它是專門設計與pandas.DataFrame工作。服用absolutelyNoWarranty的建議在他們的答案,我得到了以下錯誤:

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

考慮看看在調用get功能args,有這樣的數據:

('gender', 'gender') 

這是因爲這代碼的源代碼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) 

它試圖獲得的價值和使用相同的值作爲fallb以防萬一它不存在。這在__getitem__()中導致錯誤,因爲它被調用(self, 'gender', 'gender')參數。

我試圖重寫get()功能如下:

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. 

在這裏,我得到了結束了我嘗試的錯誤:

TypeError: 'SArray' object is not callable 

考慮看看源代碼,它檢查是否y數據是pd.Series,如果不是,則它將y值轉換成一個:

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

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

當執行vals.groupby(grouper)(石斑仍然是SArray實例)時,它會進入熊貓核心工作,其中調用SArray並引發錯誤。故事結局。

+0

我編輯了我的答案。看看它是否有幫助(雖然在這一點上它可能太hacky。) – absolutelyNoWarranty

0

問題是sns.boxplot預計數據有一個get方法就像一個熊貓的數據框。在Pandas中,get方法返回單列,因此它與括號索引相同,即your_df['your_column_name']

解決此問題的最簡單方法是調用您的sframe上的to_dataframe方法將其轉換爲數據框。

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

或者,你可以寫身邊類包裝或使用monkey-patchingget到SFrame類解決該問題破解。

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

謝謝你的回答。您提供的解決方法是有效的,但我需要調查'to_dataframe()'轉換的成本。然而,猴子補丁不起作用。我深入了'seaborn'源代碼,它的方法被設計爲專門用於數據框。 – iulian

+0

以下是''sframe'文檔(https://dato.com/products/create/docs/generated/graphlab.SFrame.to_dataframe.html#graphlab.SFrame.to_dataframe)'to_dataframe()的快速答案。 ':「這個操作將在內存中構建一個pandas.DataFrame,當返回的對象的大小很大時,必須小心。」所以,不幸的是,這也不是一個有效的選擇。 – iulian