我想在数据框Z
中按类别df
和X
绘制一个列Y
的箱线图。如何按中位数按降序对箱线图进行排序?
import pandas as pd
import random
n = 100
# this is probably a strange way to generate random data; please feel free to correct it
df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)],
"Y": [random.choice(["a","b","c"]) for i in range(n)],
"Z": [random.gauss(0,1) for i in range(n)]})
df.boxplot(column="Z", by=["X", "Y"])
请注意this question非常相似,但它们使用不同的数据结构。我对pandas比较陌生(并且一般只在python上做了一些教程),所以我无法弄清楚如何使我的数据与那里发布的答案一起工作。这可能更像是重塑而不是绘图问题。也许有使用groupby
的解决方案?
答案 0 :(得分:10)
您可以使用How to sort a boxplot by the median values in pandas中的答案,但首先需要对数据进行分组并创建新的数据框:
import pandas as pd
import random
import matplotlib.pyplot as plt
n = 100
# this is probably a strange way to generate random data; please feel free to correct it
df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)],
"Y": [random.choice(["a","b","c"]) for i in range(n)],
"Z": [random.gauss(0,1) for i in range(n)]})
grouped = df.groupby(["X", "Y"])
df2 = pd.DataFrame({col:vals['Z'] for col,vals in grouped})
meds = df2.median()
meds.sort(ascending=False)
df2 = df2[meds.index]
df2.boxplot()
plt.show()
答案 1 :(得分:10)
与Alvaro Fuentes相似answer'以功能形式提供更多便携性
import pandas as pd
def boxplot_sorted(df, by, column):
df2 = pd.DataFrame({col:vals[column] for col, vals in df.groupby(by)})
meds = df2.median().sort_values()
df2[meds.index].boxplot(rot=90)
boxplot_sorted(df, by=["X", "Y"], column="Z")
答案 2 :(得分:5)
要回答标题中的问题,而无需解决绘制两个分类变量的所有组合的额外细节:
n = 100
df = pd.DataFrame({"Category": [np.random.choice(["A","B","C","D"]) for i in range(n)],
"Variable": [np.random.normal(0, 10) for i in range(n)]})
grouped = df.loc[:,['Category', 'Variable']] \
.groupby(['Category']) \
.median() \
.sort_values(by='Variable')
sns.boxplot(x=df.Category, y=df.Variable, order=grouped.index)
我添加了此解决方案,因为很难将可接受的答案简化为单个变量,而且我敢肯定人们正在寻找一种方法来做到这一点。我本人曾多次问这个问题,以寻求这样的答案。
答案 3 :(得分:0)
我遵循了已接受的答案,但是当我想覆盖使用另一个 y 轴(即 ax.twinx()
)的第二个图时遇到了麻烦。问题是第二个图的 x 轴覆盖了排序顺序。
我最终只用 seaborn
完成了以下操作。这类似于@rocksNwaves 的回答,但我是用问题引入的术语来写的。 只需三步:
如果您不介意创建一个包含“X”和“Y”的列,那么使用 seaborn 会让事情变得更容易:
df["XY"] = df["X"] + df["Y"]
当然,您可以按照您想要的任何方式组合这两列。
按XY排序并获得排序索引
grouped = df.groupby(["XY"])
order = grouped.median()["Z"].sort_values().index
使用 seaborn 绘图
sns.boxplot(x="XY", y="Z", data=df, order=order)
请注意,您可以将 order
视为指定标签在 x 轴上的顺序。
一个完整的程序:
import pandas as pd
import random
import seaborn as sns
import matplotlib.pyplot as plt
n = 100
# this is probably a strange way to generate random data; please feel free to correct it
df = pd.DataFrame({"X": [random.choice(["A","B","C"]) for i in range(n)],
"Y": [random.choice(["a","b","c"]) for i in range(n)],
"Z": [random.gauss(0,1) for i in range(n)]})
df["XY"] = df["X"] + df["Y"]
grouped = df.groupby(["XY"])
order = grouped.median()["Z"].sort_values().index
sns.boxplot(x="XY", y="Z", data=df, order=order, palette="light:#5A9")
plt.show()
df
看起来像
X Y Z
0 A a 0.894873
1 C a -0.568682
2 C b 0.985260
3 B c 2.056287
...
情节看起来像