Как применить пользовательский порядок столбцов (по категориям) к коробочному графику панд?
РЕДАКТИРОВАТЬ: этот вопрос возник с пандами ~ 0,13 и был устарел прямой поддержкой где-то между версиями 0,15-0,18 (в соответствии с поздним ответом @Cireo)
Я могу получить boxplot
из столбца зарплаты в панде DataFrame...
train.boxplot(column='Salary', by='Category', sym='')
... однако я не могу понять, как определить порядок индекса, используемый в столбце "Категория" - я хочу указать свой собственный заказ в соответствии с другим критерием:
category_order_by_mean_salary = train.groupby('Category')['Salary'].mean().order().keys()
Как я могу применить свой собственный порядок столбцов к столбцам коробчатого графика? (кроме уродливой путаницы имен столбцов с префиксом для принудительного упорядочения)
"Категория" - это строка (на самом деле, она должна быть категориальной, но это было в столбце 0.13, где категоричным был гражданин третьего класса), принимая 27 различных значений: ['Accounting & Finance Jobs','Admin Jobs',...,'Travel Jobs']
. Так что это легко можно pd.Categorical.from_array()
с помощью pd.Categorical.from_array()
При проверке ограничение находится внутри pandas.tools.plotting.py:boxplot()
, который преобразует объект столбца без упорядочения:
Я полагаю, что я могу либо взломать пользовательскую версию pandas boxplot(), либо достучаться до внутреннего объекта. А также подайте запрос на расширение.
Ответы
Ответ 1
Трудно сказать, как это сделать без рабочего примера. Мое первое предположение было бы просто добавить целочисленный столбец с порядком, который вы хотите.
Простой способ грубой силы состоит в том, чтобы добавлять каждый блокпост по одному.
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]()
Ответ 2
На самом деле я застрял с тем же вопросом. И я решил это, сделав карту и сбросив xticklabels, с кодом следующим образом:
df = pd.DataFrame({"A":["d","c","d","c",'d','c','a','c','a','c','a','c']})
df['val']=(np.random.rand(12))
df['B']=df['A'].replace({'d':'0','c':'1','a':'2'})
ax=df.boxplot(column='val',by='B')
ax.set_xticklabels(list('dca'))
Ответ 3
Обратите внимание, что pandas теперь может создавать категориальные столбцы. Если вы не возражаете, чтобы все столбцы присутствовали на вашем графике или соответствующим образом обрезали их, вы можете сделать что-то вроде ниже:
http://pandas.pydata.org/pandas-docs/stable/categorical.html
df['Category'] = df['Category'].astype('category', ordered=True)
Недавний pandas также позволяет positions
проходить весь путь от кадра к осям.
Ответ 4
РЕДАКТИРОВАТЬ: это правильный ответ после того, как прямая поддержка была добавлена где-то между версиями 0.15-0.18
Добавление отдельного ответа, что, возможно, может быть другой вопрос - обратная связь приветствуется.
Я хотел добавить пользовательский порядок столбцов в группе, что поставило передо мной много проблем. В конце концов, мне пришлось избегать попытки использовать boxplot
из объекта groupby
, а вместо этого самому проходить каждый подзаговор, чтобы groupby
явные позиции.
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()
В моем конечном коде было еще немного сложнее определять позиции, потому что у меня было несколько точек данных для каждого значения сортировки, и мне пришлось выполнить следующее:
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)
Ответ 5
Это может звучать глупо, но многие сюжеты позволяют вам определить порядок. Например:
Библиотека и набор данных
import seaborn as sns
df = sns.load_dataset('iris')
Конкретный заказ
p1=sns.boxplot(x='species', y='sepal_length', data=df, order=["virginica", "versicolor", "setosa"])
sns.plt.show()