在列上循环时如何在熊猫中生成清晰的图?

ark*_*diy 5 python python-3.x pandas

生成数据帧以实现可复制性:

df = pd.DataFrame(np.random.randn(50, 1000), columns=list('ABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDED'))
Run Code Online (Sandbox Code Playgroud)

检查每个变量的分布是否正常(注意:这需要很长时间才能运行)

# Set the column names

columns= df.columns

# Loop over all columns

fig, axs = plt.subplots(len(df.columns), figsize=(5, 25))
for n, col in enumerate(df.columns):
    df[col].hist(ax=axs[n])
Run Code Online (Sandbox Code Playgroud)

结果会生成难以辨认的直方图,并且需要很长时间才能运行。

时间长度还可以,但是我很好奇是否有人建议生成清晰的直方图(不必花哨),可以对整个数据框进行快速检查以确保分布的正态性。

Nat*_*iel 5

此代码生成 1000 个直方图,并允许您足够详细地查看每个直方图,以了解列的正态分布情况:

import pandas as pd
import matplotlib.pyplot as plt

cols = 1000
df = pd.DataFrame(np.random.normal(0, 1, [50, cols]))

# Loop over all columns
fig, ax = plt.subplots(figsize = (16, 10))
for n, col in enumerate(df.columns):
    plt.subplot(25, 40, n+1)
    df[col].hist(ax = plt.gca())
    plt.axis('off')
plt.tight_layout()

plt.savefig('1000_histograms.png', bbox_inches='tight', pad_inches = 0, dpi = 200)
Run Code Online (Sandbox Code Playgroud)

1000 个直方图

另一种确定正态性的方法是使用 QQ 图,与直方图相比,它可能更容易批量可视化:

import statsmodels.api as sm

cols = 1000
df = pd.DataFrame(np.random.normal(0,1, [50, cols]))

fig, axs = plt.subplots(figsize=(18, 12))
for n, col in enumerate(df.columns):
    plt.subplot(25,40,n+1)
    sm.qqplot(df[col], ax=plt.gca(), #line='45', 
              marker='.', markerfacecolor='C0', markeredgecolor='C0', 
              markersize=2)
#    sm.qqline(ax=plt.gca(), line='45', fmt='lightgray')
    plt.axis('off')

plt.savefig('1000_QQ_plots13.png', bbox_inches='tight', pad_inches=0, dpi=200)
Run Code Online (Sandbox Code Playgroud)

1000个QQ图

每条线越接近 45 度对角线,列数据的分布越正常。


Lon*_*rer 5

  1. 绘图与正态性检验
  2. 主张
  3. 输出示例
  4. 对应的代码示例

绘图与正态性检验

正如下面评论中所讨论的,OP 问题已更改为数千个地块管理。从这个角度来看,纳撒尼尔的回答是恰当的

但是,我觉得未说明的意图是决定给定变量是否呈正态分布,需要考虑数千个变量。

检查每个变量的分布正态性(注意:这需要很长时间才能运行)

考虑到这一点,(对我而言)让人类审查数千个图以发现正态/非正态分布似乎是一种不恰当的方法。有一个法语成语:“usine à gaz”(“gas factory”)

因此,此答案侧重于以编程方式执行分析并提供某种更简洁的报告。

主张

在大量列上执行数据正态性分析。它依赖于这个答案中表达的建议。

这个想法是:

  • 对所有列执行分布测试(正态性)
  • 将结果大写为数据框
  • 将正常/非正常比率报告到图表中。
  • 报告非正常列名。

通过这种方法,我们可以进一步使用编程来操作正常/非正常列。例如,我们可以执行额外的分布测试,或者只绘制非正态分布,从而减少实际观察的图形数量。

输出示例:

------------
Columns probably not a normal dist:
  Column  Not_Normal  p-value   Normality
0      V        True      0.0  Not Normal
0      W        True      0.0  Not Normal
0      X        True      0.0  Not Normal
0      Y        True      0.0  Not Normal
0      Z        True      0.0  Not Normal
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

免责声明:所使用的方法在统计上可能不是“规范的”。使用统计工具时应该非常小心,因为每个工具都是其特定的使用领域/用例。

我选择了 0.01 (1%) p 值,因为它可能是科学出版物中即将发布的标准值,而不是通常的 0.05 (5%))

人们应该阅读https://en.wikipedia.org/wiki/Normalality_test

单变量正态性检验包括以下内容:

  • D'Agostino 的 K 方检验,
  • Jarque-Bera 检验,
  • 安德森-达林测试,
  • Cramer-von Mises 判据,
  • 利利福斯测试,
  • 柯尔莫哥洛夫-斯米尔诺夫检验
  • 夏皮罗-威尔克测试,和
  • Pearson 卡方检验。

代码

您的计算机上的行为可能因 RNG(随机数生成)而异。 以下示例是使用 numpy 进行 5 次正常随机抽样和 5 次帕累托随机抽样。正态性检验在这些条件下表现良好(即使我觉得 0.0 p 值检验即使对于帕累托随机生成也是可疑的) 不过,我认为我们可以同意它是关于方法的,而不是实际的结果。

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

print('System: {}'.format(sys.version))
for module in [pd, np, scipy, sb]:
    print('Module {:10s} - version {}'.format(module.__name__, module.__version__))

nb_lines = 10000
headers_normal = 'ABCDE'
headers_pareto = 'VWXYZ'
reapeat_factor = 1
nb_cols = len(list(reapeat_factor * headers_normal))

df_normal = pd.DataFrame(np.random.randn(nb_lines, nb_cols), columns=list(reapeat_factor * headers_normal))

df_pareto = pd.DataFrame((np.random.pareto(12.0, size=(nb_lines,nb_cols )) + 15.) * 4., columns=list(reapeat_factor * headers_pareto))

df = df_normal.join(df_pareto)

alpha = 0.01
df_list = list()

# normality code taken from https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html
cat_map = {True: 'Not Normal',
           False: 'Maybe Normal'}
for col in df.columns:
    k2, p = stats.normaltest(df[col])
    is_not_normal = p < alpha
    tmp_df = pd.DataFrame({'Column': [col],
                           'Not_Normal': [is_not_normal],
                           'p-value': [p],
                           'Normality': cat_map[is_not_normal]
                           })
    df_list.append(tmp_df)

df_results = pd.concat(df_list)
df_results['Normality'] = df_results['Normality'].astype('category')

print('------------')
print('Columns names probably not a normal dist:')
# full data
print(df_results[(df_results['Normality'] == 'Not Normal')])
# only column names
# print(df_results[(df_results['Normality'] == 'Not Normal')]['Column'])
print('------------')
print('Plotting countplot')
sb.countplot(data=df_results, y='Normality', orient='v')
plt.show()
Run Code Online (Sandbox Code Playgroud)

输出:

System: 3.7.2 (default, Feb 21 2019, 17:35:59) [MSC v.1915 64 bit (AMD64)]
Module pandas     - version 0.24.1
Module numpy      - version 1.16.2
Module scipy      - version 1.2.1
Module seaborn    - version 0.9.0
------------
Columns names probably not a normal dist:
  Column  Not_Normal  p-value   Normality
0      V        True      0.0  Not Normal
0      W        True      0.0  Not Normal
0      X        True      0.0  Not Normal
0      Y        True      0.0  Not Normal
0      Z        True      0.0  Not Normal
------------
Plotting countplot
Run Code Online (Sandbox Code Playgroud)

  • 这是对未提出问题的明智回答。您不会通过查看 1000 个直方图来评估 1000 个样本的正态性。 (3认同)

Gio*_*Gio 2

我真的很喜欢纳撒尼尔的回答,但我会加上我的两分钱。

我会选择seaborn,特别是seaborn.distplot。这将使您能够轻松地将正态分布拟合到每个直方图上,并使可视化更加容易。

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

cols = 1000
df = pd.DataFrame(np.random.normal(0, 1, [50, cols]))
from scipy.stats import norm
fig, ax = plt.subplots(figsize = (16, 10))
for i, col in enumerate(df.columns):
    ax=fig.add_subplot(25, 4, i+1)
    sns.distplot(df[col],fit=norm, kde=False,ax=ax)
plt.tight_layout()
Run Code Online (Sandbox Code Playgroud)

此外,我不确定在您的示例中放置具有相同名称的列是否是故意的。如果是这种情况,循环遍历列的最简单的解决方案是使用.iloc,代码如下所示:

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

 df = pd.DataFrame(np.random.randn(50, 1000), columns=list('ABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDEDABCDABCDED'))

fig, ax = plt.subplots(figsize = (12, 10))
for i, col in enumerate(df.columns):
    plt.subplot(25, 40, i+1)
    sns.distplot(df.iloc[:,i],fit=norm, kde=False,ax=plt.gca())
    plt.axis('off')
plt.tight_layout()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述