绘制象限图以根据 X 和 Y 的平均值区分 4 组中的人口并找到最终计数

Posted

技术标签:

【中文标题】绘制象限图以根据 X 和 Y 的平均值区分 4 组中的人口并找到最终计数【英文标题】:Plotting quadrant chart to differntiate population in 4 groups based on mean values of X & Y and find the final count 【发布时间】:2021-10-14 08:32:01 【问题描述】:

开始学习如何在 python 上绘制数据,我需要帮助实现以下目标:

我有下面的例子df6:

df6 = pd.DataFrame(
                   'emails': [50, 60 ,30, 40, 90, 10, 0,85 ],
                   'delivered': [20, 16 ,6, 15, 66, 6, 0,55 ]
                   )

df6

看起来像:

    emails  delivered
0       50  20
1       60  16
2       30  6
3       40  15
4       90  66
5       10  6
6       0   0
7       85  55

我需要在 4 象限图表中绘制 emails VS delivered。 X 和 Y 范围将稍微超出最大值,横截面将是两列的平均值。

到目前为止我所做的,使用describe() 获取 df6 的值然后:

fig, ax = plt.subplots()
fig.set_size_inches(7, 5)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)

plt.axhline(y=45.6, color="black", linestyle="--")
plt.axvline(x=23, color="black", linestyle="--")

plt.plot(df6['delivered'],df6['emails'],"o")
plt.xlim([0, df6['delivered'].max()+20])
plt.ylim([0, df6['emails'].max()+20])
plt.show()

到目前为止,我得到了以下输出:

我正在寻找的是将图表分成分散的 4 个组,并用四分之一的总数标记每个组:

【问题讨论】:

【参考方案1】:

您只是缺少设置左/下脊椎位置的代码

import pandas as pd, numpy as np
df6 = pd.DataFrame('emails': [50, 60 ,30, 40, 90, 10, 0,85 ],
                    'delivered': [20, 16 ,6, 15, 66, 6, 0,55 ])

plt.plot(df6['delivered'],df6['emails'],"o")

count = np.count_nonzero(
            (df6['emails'] < df6['delivered'].mean())&
            (df6['delivered'] < df6['emails'].mean()) ) 
plt.annotate('count: %s'%count,(5,60))

plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['left'].set_position(('data',df6['delivered'].mean()))
plt.gca().spines['bottom'].set_position(('data',df6['emails'].mean()))

【讨论】:

【参考方案2】:

因此,要在绘图中使用这些方法,您可以从简单地修改以下 2 行开始:

plt.axhline(y=df6['emails'].mean(), color="black", linestyle="--")
plt.axvline(x=df6['delivered'].mean(), color="black", linestyle="--")

然后我们可以使用pd.value_counts 来计算计数:

counts = df6.transform(lambda s: s >= s.mean()).value_counts()
pos = df6.agg(['min', 'max'])

这里counts 包含每对上/下均值的值:

emails  delivered
False   False        4
True    False        2
        True         2

pos 包含放置盒子的 x/y(或电子邮件/已发送)坐标:

     emails  delivered
min       0          0
max      90         66

所以你可以调整pos来改变注解的位置。

最后要在图上做标注:

for (eml, dlv), num in counts.iteritems():
    ax.text(s=f'count: num',
        x=pos.loc['max' if dlv else 'min', 'delivered'],
        y=pos.loc['max' if eml else 'min', 'emails'],
        ha='right' if dlv else 'left',
        va='top' if eml else 'bottom',
    )

【讨论】:

【参考方案3】:

这是另一种解决方案,具有更对称的图:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(
    
        "emails": [50, 60, 30, 40, 90, 10, 0, 85],
        "delivered": [20, 16, 6, 15, 66, 6, 0, 55],
    
)

plt.plot(df["delivered"], df["emails"], "o")
plt.gca().spines["top"].set_visible(False)
plt.gca().spines["right"].set_visible(False)
plt.gca().spines["left"].set_position(("data", df["delivered"].mean()))
plt.gca().spines["bottom"].set_position(("data", df["emails"].mean()))


def get_lims(df, column, w=0.1):
    mean = df[column].mean()
    max_diff = max(
        abs(df[column].max() - mean),
        abs(df[column].min() - mean),
    )
    return [mean - max_diff - max_diff * w, mean + max_diff + max_diff * w]


plt.xlim(get_lims(df, "delivered"))
plt.ylim(get_lims(df, "emails"))
plt.show()

【讨论】:

【参考方案4】:

我发现在绘图之前对数据进行规范化更容易......更新:搞砸了计数,但代码在这里分析我的错误。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scale = scaler.fit(df6)

# normalize the sen_matrix
norm_df = pd.DataFrame(scale.transform(df6), columns=df6.columns)

quadrant_1 = sum(np.logical_and(norm_df['emails'] < 0, norm_df['delivered'] < 0))
display(quadrant_1)

quadrant_2 = sum(np.logical_and(norm_df['emails'] > 0, norm_df['delivered'] < 0))
display(quadrant_2)

quadrant_3 = sum(np.logical_and(norm_df['emails'] < 0, norm_df['delivered'] > 0))
display(quadrant_3)

quadrant_4 = sum(np.logical_and(norm_df['emails'] > 0, norm_df['delivered'] > 0))
display(quadrant_4)

fig, ax = plt.subplots()
fig.set_size_inches(7, 5)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)

plt.axhline(y=0, color="black", linestyle="--")
plt.axvline(x=0, color="black", linestyle="--")

plt.plot(norm_df['delivered'],norm_df['emails'],"o")
plt.gca().spines['bottom'].set_visible(False)
plt.gca().spines['left'].set_visible(False)
plt.gca().axes.get_xaxis().set_visible(False)
plt.gca().axes.get_yaxis().set_visible(False)
plt.text(0,-2.1,'Delivered',horizontalalignment='center', verticalalignment='center')
plt.text(-2.1,0,'Emails', horizontalalignment='center', verticalalignment='center', rotation=90)

plt.text(1,1,'Count: ' + str(quadrant_1),horizontalalignment='center', verticalalignment='center')
plt.text(-1,1,'Count: ' + str(quadrant_2), horizontalalignment='center', verticalalignment='center')
plt.text(-1,-1,'Count: ' + str(quadrant_3),horizontalalignment='center', verticalalignment='center')
plt.text(1,-1,'Count: ' + str(quadrant_4), horizontalalignment='center', verticalalignment='center')


plt.xlim([-2, 2])
plt.ylim([-2, 2])
plt.show()

【讨论】:

以上是关于绘制象限图以根据 X 和 Y 的平均值区分 4 组中的人口并找到最终计数的主要内容,如果未能解决你的问题,请参考以下文章

分组数据上的ggplot方面

c语言编程问题:输入4个任意数字,然后按从小到大的顺序输入坐标点(x,y),输出该点所在的象限。代码是:

如何平滑和绘制 x 与 y 的加权平均值,由 x 加权?

Python DBSCAN - 如何根据向量的平均值绘制集群?

如何根据列表绘制列表列表?

在 4 个单独的图上绘制每个评级的组平均值