2013-03-21 8 views
8

posso ottenere un grafico a scatole di una colonna stipendio in un dataframe panda ...Come applicare l'ordine di colonne personalizzato a boxe panda?

train.boxplot(column='PredictionError',by='Category',sym='') 

... però io non riesco a capire come definire l'indice in ordine utilizzato su colonna 'Categoria' - I vuole fornire il mio ordine personalizzato, secondo un altro criterio:

category_order_by_mean_salary = train.groupby('Category')['Salary'].mean().order().keys() 

Come posso applicare il mio ordine colonna personalizzata alle colonne grafico a scatole? (diverso dal brutto che blocca i nomi delle colonne con un prefisso per forzare l'ordinamento)

'Category' è una colonna di stringhe che assume 27 valori distinti: ['Accounting & Finance Jobs','Admin Jobs',...,'Travel Jobs']. Così può essere facilmente fattorizzata con pd.Categorical.from_array()

Su controllo, la limitazione è all'interno pandas.tools.plotting.py:boxplot(), che converte l'oggetto colonna senza consentire ordinazione:

Suppongo che potrei o incidere una versione personalizzata di panda boxplot(), oppure raggiungere in interni dell'oggetto. E anche presentare una richiesta di miglioramento.

MODIFICA: questa domanda è sorta con panda ~ 0.13 ed è stata probabilmente obsoleta dalle recenti versioni (0.19+?) Come per la risposta in ritardo di @ Cireo.

risposta

6

Difficile dire come farlo senza un esempio funzionante. La mia prima ipotesi sarebbe semplicemente aggiungere una colonna intera con gli ordini che si desidera.

Un modo semplice, a forza bruta, consiste nell'aggiungere ogni schema box uno alla volta.

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 

df = pd.DataFrame(np.random.rand(37,4), columns=list('ABCD')) 
columns_my_order = ['C', 'A', 'D', 'B'] 
fig, ax = plt.subplots() 
for position, column in enumerate(columns_my_order): 
    ax.boxplot(df[column], positions=[position]) 

ax.set_xticks(range(position+1)) 
ax.set_xticklabels(columns_my_order) 
ax.set_xlim(xmin=-0.5) 
plt.show() 

enter image description here

+0

dettaglio aggiunto per te e idee su soluzioni alternative. L'aggiunta di una colonna intera autonoma separata non fornisce un grafico decente perché ora le etichette delle colonne sono numeri interi (illeggibili) e non di testo. (Kludging un prefisso di testo in nomi di categoria per forzare ordinamento personalizzato-ordine è forse l'hack più veloce. Ma ancora brutto) – smci

+0

[panda dataframe non può gestire una colonna categoriale] (http://stackoverflow.com/questions/15356433/how-to Generi i-panda-dataframe-colonna-di-categorica-da-string-colonna), a differenza di R. – smci

+0

non dove ero diretto. Di solito uso 'apply' con una tabella di ricerca hard-coded. vedere la mia risposta modificata per un approccio diverso, però. –

1

Nota che i panda possono ora creare colonne categoriali. Se non ti dispiace avere tutte le colonne presenti nel grafico, o rifilatura in modo appropriato, si può fare qualcosa di simile al seguito:

http://pandas.pydata.org/pandas-docs/stable/categorical.html

df['Category'] = df['Category'].astype('category', ordered=True) 

panda recenti sembra anche per permettere positions per passare tutti la strada da una cornice all'altra.

+0

Ooh, eccellente. Quale versione hanno aggiunto? 0.20? – smci

+1

Il link diceva 0.15, ma ero sospettoso di ciò. Non sono sicuro se la funzionalità fosse completamente integrata a quel punto. Sono stato in grado di fare tutto questo in '0.19.2' – Cireo

+0

Grazie per la verifica. – smci

1

Aggiunta una risposta separata, che forse potrebbe essere un'altra domanda - risposte apprezzato.

ho voluto aggiungere un ordine di colonna personalizzata all'interno di un groupby, che pone molti problemi per me. Alla fine, ho dovuto evitare di cercare di utilizzare boxplot da un oggetto groupby, e invece passare attraverso ogni sottotrama me stesso per fornire posizioni esplicite.

import matplotlib.pyplot as plt 
import pandas as pd 

df = pd.DataFrame() 
df['GroupBy'] = ['g1', 'g2', 'g3', 'g4'] * 6 
df['PlotBy'] = [chr(ord('A') + i) for i in xrange(24)] 
df['SortBy'] = list(reversed(range(24))) 
df['Data'] = [i * 10 for i in xrange(24)] 

# Note that this has no effect on the boxplot 
df = df.sort_values(['GroupBy', 'SortBy']) 
for group, info in df.groupby('GroupBy'): 
    print 'Group: %r\n%s\n' % (group, info) 

# With the below, cannot use 
# - sort data beforehand (not preserved, can't access in groupby) 
# - categorical (not all present in every chart) 
# - positional (different lengths and sort orders per group) 
# df.groupby('GroupBy').boxplot(layout=(1, 5), column=['Data'], by=['PlotBy']) 

fig, axes = plt.subplots(1, df.GroupBy.nunique(), sharey=True) 
for ax, (g, d) in zip(axes, df.groupby('GroupBy')): 
    d.boxplot(column=['Data'], by=['PlotBy'], ax=ax, positions=d.index.values) 
plt.show() 

Nel mio codice finale, era anche un po 'più coinvolti per determinare le posizioni perché ho avuto più punti dati per ogni valore sortby, e ho finito per dover fare il seguito:

to_plot = data.sort_values([sort_col]).groupby(group_col) 
for ax, (group, group_data) in zip(axes, to_plot): 
    # Use existing sorting 
    ordering = enumerate(group_data[sort_col].unique()) 
    positions = [ind for val, ind in sorted((v, i) for (i, v) in ordering)] 
    ax = group_data.boxplot(column=[col], by=[plot_by], ax=ax, positions=positions) 
+0

Bene, la domanda originale è stata chiusa per anni, perché non aggiungere una nuova domanda per questa risposta? Specificare panda 0.20+ – smci

+1

non era sicuro per l'etichetta di pubblicazione di una domanda allora rispondere da soli =/ – Cireo

+0

che è perfettamente ok. Anche in questo caso desiderabile - questa domanda è diventata obsoleta ad un certo punto dai panda 0.19 – smci