有什么合适的方式来直观地/图形地描述 2 个 Pandas Dataframes 的分布?

数据挖掘 Python 熊猫 可视化 数据框 matplotlib
2022-02-13 08:16:25

我知道 Pandas Dataframe 的统计描述可以很容易地使用df.describe(). 我有 2 个相同维度的数据框(即两个数据框都有 102 列和 800000 行)。我想直观地描述两个数据帧非常相似/具有统计相似分布的事实。

我不确定如何在 Python 中以视觉/图形方式完成此操作。df.describe方法为数据帧提供count, mean, std, min, 25 %, 50 %, 75 % and max值,但很难从第一个实例中推断出来。我更喜欢任何类型的视觉/图形方法(我不确定 Boxplot 是否有帮助?)。任何建议的方法以及最小可行示例都将受到高度赞赏。干杯!

目前,

# df1 is dataframe 1
# df2 is dataframe 2
df1.describe() # this gives statistical values of df1 dataframe
df2.describe() # this gives statistical values of df2 dataframe
1个回答

您可以使用Kolmogorov-Smirnov 测试来自维基百科

在统计学中,Kolmogorov-Smirnov 检验(K-S 检验或 KS 检验)是连续一维概率分布是否相等的非参数检验,可用于将样本与参考概率分布(单样本 K -S 检验),或比较两个样本(双样本 K-S 检验)。它以 Andrey Kolmogorov 和 Nikolai Smirnov 的名字命名。

对我们有好处, Scipy中已经有一个实现

您可以使用此虚拟代码对其进行测试

from scipy import stats
p_value = 0.05
rejected = 0
for col in range(103):
    test = stats.ks_2samp(df1.ix[col,], df2.ix[col,])
    if test[1] < p_value:
         rejected += 1
print("We rejected",rejected,"columns in total")

我假设您要比较的列在两个数据帧中的同一索引上。如果这不是真的,你需要找到另一种方法。也许如果他们有相同的名字?你可以这样做。

from scipy import stats
p_value = 0.05
rejected = 0
for col in df1:
    test = stats.ks_2samp(df1[col], df2[col])
    if test[1] < p_value:
         rejected += 1
print("We rejected",rejected,"columns in total")

如果 KS 统计量很小或 p 值很高,那么我们不能拒绝两个样本的分布相同的假设。

编辑:我以前没有尝试过,但也许你可以做类似的事情

箱形图

from scipy import stats
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#create 2 dataframes with random integers. I don't have data to simulate your case.

df1 = pd.DataFrame(np.random.randint(0,100,size=(10000, 102)), columns=range(1,103))
df2 = pd.DataFrame(np.random.randint(0,100,size=(10000, 102)), columns=range(1,103))

#apply the Kolmogorov-Smirnov Test

p_value = 0.05
p_values = []
for col in range(103):
    test = stats.ks_2samp(df1.iloc[col,], df2.iloc[col,])
    p_values.append(test[1])

#create the box plot

plt.boxplot(p_values)
plt.title('Boxplot of p-values')
plt.ylabel("p_values")
plt.show()

箱形图

热图

另一种方法是热图。

import matplotlib.patches as mpatches

plt.rcParams["figure.figsize"] = 5,2
x = range(1,104)
y = np.array(p_values)
fig, (ax,ax2) = plt.subplots(nrows=2, sharex=True)

extent = [x[0]-(x[1]-x[0])/2., x[-1]+(x[1]-x[0])/2.,0,1]
im = ax.imshow(y[np.newaxis,:], cmap="plasma", aspect="auto", extent=extent)
ax.set_yticks([])
ax.set_xlim(extent[0], extent[1])

values = np.unique(np.round(y.ravel(),2))

colors = [ im.cmap(im.norm(value)) for value in values]
# create a patch (proxy artist) for every color 
patches = [ mpatches.Patch(color=colors[i], label="Level {l}".format(l=values[i]) ) for i in range(len(values)) ]
# put those patched as legend-handles into the legend
plt.legend(handles=patches, bbox_to_anchor=(1.05, 2.2), loc=2, borderaxespad=0. )

ax2.plot(x,p_values)

plt.tight_layout()
plt.show()

热图

热图代码:stackoverflow