2013-03-21 7 views
8

kann ich eine boxplot einer Gehaltsspalte in einer Pandas Dataframe bekommen ...Wie man benutzerdefinierte Spaltenreihenfolge auf Pandas Boxplot anwendet?

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

... aber ich kann nicht herausfinden, wie die Index-Ordnung auf Spalte ‚Kategorie‘ verwendet, um zu definieren - I möchte meinen eigenen kundenspezifischen Auftrag liefern, nach einem anderen Kriterium:

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

Wie kann ich meine benutzerdefinierte Spalte, um die boxplot Spalten anwenden? (außer hässlich Klonierung der Spaltennamen mit einem Präfix, um die Reihenfolge zu erzwingen)

'Kategorie' ist eine Zeichenkettenspalte mit 27 verschiedenen Werten: ['Accounting & Finance Jobs','Admin Jobs',...,'Travel Jobs']. So kann es leicht mit pd.Categorical.from_array()

Bei der Inspektion Faktoren zerlegt werden, ist die Begrenzung innerhalb pandas.tools.plotting.py:boxplot(), die, ohne dass die Bestellung der Spalte Objekt konvertiert:

Ich glaube, ich könnte entweder eine benutzerdefinierte Version von Pandas boxplot() zerhacken, oder in die Interna des Objekts erreichen. Und auch eine Erweiterungsanforderung einreichen.

BEARBEITEN: diese Frage entstand mit Pandas ~ 0.13 und ist wahrscheinlich von den letzten (0.19+?) Versionen gemäß @ Cireos späte Antwort veraltet worden.

Antwort

6

Schwer zu sagen, wie das ohne ein Arbeitsbeispiel zu tun ist. Meine erste Schätzung wäre, nur eine ganzzahlige Spalte mit den gewünschten Aufträgen hinzuzufügen.

Ein einfacher, brutaler Weg wäre, jeden Boxplot einzeln hinzuzufügen.

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

Added Details für Sie und Ideen zu Workarounds. Das Hinzufügen einer separaten Standalone-Integer-Spalte ergibt kein anständiges Diagramm, da Ihre Spaltenbeschriftungen jetzt (unlesbare) Ganzzahlen sind und kein Text. (Das Einfügen eines Textpräfixes in Kategorienamen, um eine benutzerdefinierte Sortierreihenfolge zu erzwingen, ist vielleicht der schnellste Hack. Aber immer noch hässlich) – smci

+0

[Pandas DataFrame kann keine kategorische Spalte verarbeiten] (http://stackoverflow.com/questions/15356433/how-to -generate-pandas-dataframe-Spalte-of-categorical-from-string-column), im Gegensatz zu R. – smci

+0

nicht dort, wo ich hinging. Normalerweise verwende ich 'apply' nur mit einer fest codierten Nachschlagetabelle. Siehe meine bearbeitete Antwort für einen anderen Ansatz. –

1

Beachten Sie, dass Pandas jetzt kategorisch Spalten erstellen können. Wenn Sie nichts dagegen haben alle Spalten in Ihrem Diagramm vorhanden ist, oder sie entsprechend Trimmen, können Sie so etwas wie die unten tun:

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

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

Letzte Pandas scheint auch zu ermöglichen positions alle passieren der Weg vom Rahmen zu den Achsen.

+0

Ooh, ausgezeichnet. Welche Version haben sie hinzugefügt? 0.20? – smci

+1

Der Link sagte 0.15, aber ich war misstrauisch. Ich bin mir nicht sicher, ob das Feature zu diesem Zeitpunkt vollständig integriert war. Ich konnte das alles in '0.19.2' machen. – Cireo

+0

Danke für die Überprüfung. – smci

1

eine separate Antwort hinzufügen, die vielleicht eine andere Frage sein könnte - Feedback zu schätzen.

Ich wollte eine benutzerdefinierte Spaltenreihenfolge innerhalb einer groupby hinzufügen, die für mich viele Probleme aufwarf. Am Ende musste ich vermeiden, boxplot von einem groupby Objekt zu verwenden, und stattdessen jeden Teilplot selbst durchsuchen, um explizite Positionen zu liefern.

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() 

In meinem letzten Code, es war sogar noch etwas aufwendigeren Positionen zu bestimmen, weil ich die folgenden tun mehrere Datenpunkte für jeden sortby Wert, und ich landete mit hatte:

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

Nun, die ursprüngliche Frage wurde seit Jahren geschlossen, warum nicht eine neue Frage für diese Antwort hinzufügen? Angeben von Pandas 0,20+ – smci

+1

War nicht sicher über die Etikette, eine Frage zu stellen und dann selbst zu antworten =/ – Cireo

+0

das ist vollkommen in Ordnung. Auch in diesem Fall wünschenswert - diese Frage ist irgendwann durch Pandas 0.19 obsolet geworden – smci