【问题标题】:Visualisation of missing-data occurrence frequency by using seaborn使用 seaborn 可视化缺失数据的出现频率
【发布时间】:2019-06-21 00:15:39
【问题描述】:

我想创建一个 24x20 矩阵(8 个部分,每个部分有 60 个单元格或 6x10),以便通过循环(=每个 480 个值) 通过 panda 数据框在数据集中并为每一列绘制它'A','B','C'

到目前为止,我可以映射创建的 csv 文件并在矩阵中以正确的方式映射值,并在更改缺失数据 (nan & inf) 到0 或类似0.01234 的东西对数据的影响最小,另一方面可以绘制。 以下是我目前的脚本:

import numpy as np
import pandas as pd
import os
import seaborn as sns
import matplotlib.pyplot as plt

def mkdf(ListOf480Numbers):
    normalMatrix = np.array_split(ListOf480Numbers,8)
    fixMatrix = []
    for i in range(8):
        lines = np.array_split(normalMatrix[i],6)
        newMatrix = [0,0,0,0,0,0]
        for j in (1,3,5):
            newMatrix[j] = lines[j]
        for j in (0,2,4):
            newMatrix[j] = lines[j][::-1]
        fixMatrix.append(newMatrix) 
    return fixMatrix

def print_df(fixMatrix):
    values = []
    for i in range(6):
        values.append([*fixMatrix[6][i], *fixMatrix[7][i]])
    for i in range(6):
        values.append([*fixMatrix[4][i], *fixMatrix[5][i]])
    for i in range(6):
        values.append([*fixMatrix[2][i], *fixMatrix[3][i]])
    for i in range(6):
        values.append([*fixMatrix[0][i], *fixMatrix[1][i]])
    df = pd.DataFrame(values)
    return (df)




dft = pd.read_csv('D:\Feryan.TXT', header=None)
id_set = dft[dft.index % 4 == 0].astype('int').values
A = dft[dft.index % 4 == 1].values
B = dft[dft.index % 4 == 2].values
C = dft[dft.index % 4 == 3].values
data = {'A': A[:,0], 'B': B[:,0], 'C': C[:,0]}

df = pd.DataFrame(data, columns=['A','B','C'], index = id_set[:,0])  

nan = np.array(df.isnull())
inf = np.array(df.isnull())
df = df.replace([np.inf, -np.inf], np.nan)
df[np.isinf(df)] = np.nan    # convert inf to nan
#dff = df[df.isnull().any(axis=1)]   # extract sub data frame

#df = df.fillna(0)
#df = df.replace(0,np.nan)



#next iteration create all plots, change the number of cycles
cycles = int(len(df)/480)
print(cycles)
for cycle in range(3):
    count =  '{:04}'.format(cycle)
    j = cycle * 480
    new_value1 = df['A'].iloc[j:j+480]
    new_value2 = df['B'].iloc[j:j+480]
    new_value3 = df['C'].iloc[j:j+480]
    df1 = print_df(mkdf(new_value1))
    df2 = print_df(mkdf(new_value2))
    df3 = print_df(mkdf(new_value3))              
    for i in df:
        try:
            os.mkdir(i)
        except:
            pass
            df1.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None) 
            df2.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None)
            df3.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None)

    #plotting all columns ['A','B','C'] in-one-window side by side


    fig, ax = plt.subplots(nrows=1, ncols=3 , figsize=(20,10))
    plt.subplot(131)

    ax = sns.heatmap(df1.isnull(), cbar=False)
    ax.axhline(y=6, color='w',linewidth=1.5)
    ax.axhline(y=12, color='w',linewidth=1.5)
    ax.axhline(y=18, color='w',linewidth=1.5)
    ax.axvline(x=10, color='w',linewidth=1.5)

    plt.title('Missing-data frequency in A', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
    plt.axis('off')

    plt.subplot(132)
    ax = sns.heatmap(df2.isnull(), cbar=False)
    ax.axhline(y=6, color='w',linewidth=1.5)
    ax.axhline(y=12, color='w',linewidth=1.5)
    ax.axhline(y=18, color='w',linewidth=1.5)
    ax.axvline(x=10, color='w',linewidth=1.5)
    plt.title('Missing-data frequency in B', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
    plt.axis('off')

    plt.subplot(133)
    ax = sns.heatmap(df3.isnull(), cbar=False)
    ax.axhline(y=6, color='w',linewidth=1.5)
    ax.axhline(y=12, color='w',linewidth=1.5)
    ax.axhline(y=18, color='w',linewidth=1.5)
    ax.axvline(x=10, color='w',linewidth=1.5) 
    plt.title('Missing-data frequency in C', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
    plt.axis('off')

    plt.suptitle(f'Missing-data visualization', color='yellow', backgroundcolor='black', fontsize=15, fontweight='bold')
    plt.subplots_adjust(top=0.92, bottom=0.02, left=0.05, right=0.96, hspace=0.2, wspace=0.2)
    fig.text(0.035, 0.93, 'dataset1' , fontsize=19, fontweight='bold', rotation=42., ha='center', va='center',bbox=dict(boxstyle="round",ec=(1., 0.5, 0.5),fc=(1., 0.8, 0.8)))
    #fig.tight_layout()
    plt.savefig(f'{i}/result{count}.png') 
    #plt.show()      

问题是我不知道如何正确绘制缺失数据出现的频率,以了解它经常发生在哪些部分和单元格中。

Note1 缺失值越多颜色越亮,100% 缺失的数据通过循环呈现为白色颜色和纯黑色颜色表示非缺失值。可能会有一个从黑色 0% 到 100% 白色的条形图。

Note2 我还提供了 3 个周期的数据集示例文本文件,其中包含少量缺失数据,但可以手动修改和增加:dataset

预期结果应如下所示:

【问题讨论】:

  • 您没有在代码示例中提供规范化函数,而您其他代码中的函数采用不同数量的参数。
  • 您提供的数据样本也不包括在 1、2 或 3 个周期内会丢失的数据点,它只会在 1 个周期内丢失,因此热图不会显示任何变化频率。您能否提供显示您预期结果的数据?
  • @FreyaW 你说得对,我提供了一个正确的数据集,包括缺失的数据并更新了预期结果。在数据集中,我用一些值替换了 nan 和 inf:对于第 0 部分,我用 nan 和 infs 替换了所有 3 个周期的所有值,这意味着该部分应该完全显示为白色 (100%)。 对于第 7 节,我替换了前 2 个周期的缺失数据,这意味着该区域应该被替换为更暗的区域(67% 白色)。 对于第 3 部分,我只在第一个循环中做了同样的操作,这意味着更暗(33% 白色)。 其余部分没有缺失值,因此它们是纯黑色的。
  • 对不起,我忘记删除规范化过程的脚本了。
  • 您能重新检查您的数据吗?它似乎会在您的脚本中导致一些新错误。如果 id_set = 25 中的条目我会得到很多,但我认为这是不对的,可能某处缺少一行,改变了你的 id 和 A、B、B。你用你提供的数据试过你的脚本了吗?它目前会引发错误。此外,您应该缩进您的代码new_value1 = ...。否则你分配它们三次,因为它们在你的 for i in df: 循环中,当它们不需要时,因为定义中没有任何东西依赖于 ì`

标签: python seaborn missing-data find-occurrences cumulative-frequency


【解决方案1】:

您可以将您的 nan/inf 数据存储在一个单独的数组中,您可以将每个 nan/inf 的周期累加起来。

您的数组似乎总是具有相同的大小,因此我将它们定义为固定大小。您可以更改它以匹配您的数据:

df1MissingDataFrequency = np.zeros((24,20))

然后您可以将它们相加,得到 nan 值(您已经在代码中将 inf 替换为 nan):

df1MissingDataFrequency = df1MissingDataFrequency + np.isnan(df1).astype(int)

你所有的周期。

您的缩进似乎有些问题。我不知道这是否仅适用于您在此处发布的代码,或者在您的实际代码中是否相同,但目前您每个周期都制作一个新图并且您重新定义@ 987654331@ 对应每个i

由于缺少频率数据,您的代码应如下所示:

import numpy as np
import pandas as pd
import os
import seaborn as sns
import matplotlib.pyplot as plt

def mkdf(ListOf480Numbers):
    normalMatrix = np.array_split(ListOf480Numbers,8)
    fixMatrix = []
    for i in range(8):
        lines = np.array_split(normalMatrix[i],6)
        newMatrix = [0,0,0,0,0,0]
        for j in (1,3,5):
            newMatrix[j] = lines[j]
        for j in (0,2,4):
            newMatrix[j] = lines[j][::-1]
        fixMatrix.append(newMatrix) 
    return fixMatrix

def print_df(fixMatrix):
    values = []
    for i in range(6):
        values.append([*fixMatrix[6][i], *fixMatrix[7][i]])
    for i in range(6):
        values.append([*fixMatrix[4][i], *fixMatrix[5][i]])
    for i in range(6):
        values.append([*fixMatrix[2][i], *fixMatrix[3][i]])
    for i in range(6):
        values.append([*fixMatrix[0][i], *fixMatrix[1][i]])
    df = pd.DataFrame(values)
    return (df)


dft = pd.read_csv('D:/Feryan2.txt', header=None)
id_set = dft[dft.index % 4 == 0].astype('int').values
A = dft[dft.index % 4 == 1].values
B = dft[dft.index % 4 == 2].values
C = dft[dft.index % 4 == 3].values
data = {'A': A[:,0], 'B': B[:,0], 'C': C[:,0]}

df = pd.DataFrame(data, columns=['A','B','C'], index = id_set[:,0])  

nan = np.array(df.isnull())
inf = np.array(df.isnull())
df = df.replace([np.inf, -np.inf], np.nan)
df[np.isinf(df)] = np.nan    # convert inf to nan


df1MissingDataFrequency = np.zeros((24,20))
df2MissingDataFrequency = np.zeros((24,20))
df3MissingDataFrequency = np.zeros((24,20))


#next iteration create all plots, change the number of cycles
cycles = int(len(df)/480)
print(cycles)
for cycle in range(3):
    count =  '{:04}'.format(cycle)
    j = cycle * 480
    new_value1 = df['A'].iloc[j:j+480]
    new_value2 = df['B'].iloc[j:j+480]
    new_value3 = df['C'].iloc[j:j+480]
    df1 = print_df(mkdf(new_value1))
    df2 = print_df(mkdf(new_value2))
    df3 = print_df(mkdf(new_value3))              
    for i in df:
        try:
            os.mkdir(i)
        except:
            pass
    df1.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None) 
    df2.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None)
    df3.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None)

    df1MissingDataFrequency = df1MissingDataFrequency + np.isnan(df1).astype(int)
    df2MissingDataFrequency = df2MissingDataFrequency + np.isnan(df2).astype(int)
    df3MissingDataFrequency = df3MissingDataFrequency + np.isnan(df3).astype(int)

#plotting all columns ['A','B','C'] in-one-window side by side
fig, ax = plt.subplots(nrows=1, ncols=3 , figsize=(10,7))
plt.subplot(131)

ax = sns.heatmap(df1MissingDataFrequency, cbar=False, cmap="gray")
ax.axhline(y=6, color='w',linewidth=1.5)
ax.axhline(y=12, color='w',linewidth=1.5)
ax.axhline(y=18, color='w',linewidth=1.5)
ax.axvline(x=10, color='w',linewidth=1.5)

plt.title('Missing-data frequency in A', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
plt.axis('off')

plt.subplot(132)
ax = sns.heatmap(df2MissingDataFrequency, cbar=False, cmap="gray")
ax.axhline(y=6, color='w',linewidth=1.5)
ax.axhline(y=12, color='w',linewidth=1.5)
ax.axhline(y=18, color='w',linewidth=1.5)
ax.axvline(x=10, color='w',linewidth=1.5)
plt.title('Missing-data frequency in B', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
plt.axis('off')

plt.subplot(133)
ax = sns.heatmap(df3MissingDataFrequency, cbar=False, cmap="gray")
ax.axhline(y=6, color='w',linewidth=1.5)
ax.axhline(y=12, color='w',linewidth=1.5)
ax.axhline(y=18, color='w',linewidth=1.5)
ax.axvline(x=10, color='w',linewidth=1.5) 
plt.title('Missing-data frequency in C', fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
plt.axis('off')

plt.suptitle(f'Missing-data visualization', color='yellow', backgroundcolor='black', fontsize=15, fontweight='bold')
plt.subplots_adjust(top=0.92, bottom=0.02, left=0.05, right=0.96, hspace=0.2, wspace=0.2)
fig.text(0.035, 0.93, 'dataset1' , fontsize=19, fontweight='bold', rotation=42., ha='center', va='center',bbox=dict(boxstyle="round",ec=(1., 0.5, 0.5),fc=(1., 0.8, 0.8)))
#fig.tight_layout()
plt.savefig(f'{i}/result{count}.png') 
#plt.show()      

这会给你想要的输出:

编辑

本着DRY 的精神,我编辑了您的代码,这样您就没有 df1、df2、df3、new_values1 ……而且您复制和粘贴的都是相同的东西。您已经循环了i,因此您应该使用它来实际处理数据框中的三个不同列:

dft = pd.read_csv('C:/Users/frefra/Downloads/Feryan2.txt', header=None).replace([np.inf, -np.inf], np.nan)
id_set = dft[dft.index % 4 == 0].astype('int').values
A = dft[dft.index % 4 == 1].values
B = dft[dft.index % 4 == 2].values
C = dft[dft.index % 4 == 3].values
data = {'A': A[:,0], 'B': B[:,0], 'C': C[:,0]}
df = pd.DataFrame(data, columns=['A','B','C'], index = id_set[:,0])


new_values = []
dfs = []
nan_frequencies = np.zeros((3,24,20))

#next iteration create all plots, change the number of cycles
cycles = int(len(df)/480)
print(cycles)
for cycle in range(cycles):
    count =  '{:04}'.format(cycle)
    j = cycle * 480
    for idx,i in enumerate(df):
        try:
            os.mkdir(i)
        except:
            pass
        new_value = df[i].iloc[j:j+480]        
        new_values.append(new_value)
        dfi = print_df(mkdf(new_value))
        dfs.append(dfi)
        dfi.to_csv(f'{i}/norm{i}{count}.csv', header=None, index=None) 
        nan_frequencies[idx] = nan_frequencies[idx] + np.isnan(dfi).astype(int)


#plotting all columns ['A','B','C'] in-one-window side by side
fig, ax = plt.subplots(nrows=1, ncols=3 , figsize=(10,7))

for idx,i in enumerate(df):

    plt.subplot(1,3,idx+1)

    ax = sns.heatmap(nan_frequencies[idx], cbar=False, cmap="gray")
    ax.axhline(y=6, color='w',linewidth=1.5)
    ax.axhline(y=12, color='w',linewidth=1.5)
    ax.axhline(y=18, color='w',linewidth=1.5)
    ax.axvline(x=10, color='w',linewidth=1.5)

    plt.title('Missing-data frequency in ' + i, fontsize=20 , fontweight='bold', color='black', loc='center', style='italic')
    plt.axis('off')

【讨论】:

  • 你太棒了,我喜欢你的 DRY 方法!关于cbar 的小事我已经尝试过cbar=True, cmap="gray", cbar_kws={"ticks":[0,20,40,60,80,100]} 的最后一张照片'C',但我无法在cbar 的右侧修正成绩。甚至我尝试了post 中的解决方案,对我们的脚本进行了最小的更改,但我没有成功。在第一种方法中,我还注意到它不会将矩阵 'A''B' 保存为文件夹中的 csv 文件,但它会保存 'C' 你知道为什么吗?
  • 我也测试了 DRY 版本,但它的输出不会并排打印 A 、 B 、 C ,但方法很酷。它的输出提醒我由于我在 for 循环中的错误而无法在一个窗口中绘制所有 A、B、C 并且您在上一个问题中修复了它。为什么会这样?
  • 能否请您也看看这个重要的question?这对我来说非常重要。我不知道如何重塑
  • @Mario,使用干法原理的清理版本应该给出完全相同的输出。至于另一个问题,似乎已经有了答案。另外,就像我说的,你应该将你的问题减少到 20 行代码或更少,以将其减少到核心问题。如果您不知道如何重塑,请提供一个最小示例(最好不要使用任何外部数据集)来说明您正在尝试做什么。
  • 你是这里唯一熟悉我的脚本结构的人,这就是我指望你的原因。你记得我们从文本文件数据集中提取了 3 个参数,并在标准化前后将它们映射到单独的矩阵中,并将它们保存为 csv 文件。现在我的问题是我需要他们为每个周期组合这 3 个矩阵的元素,这样对于每个周期我可以将 ie: 第一行作为第一个周期 [A(1,1), B(1,1),C(1,1),...,A(24,20), B(24,20),C(24,20)] 和它们下面的其他行作为其他周期它有点 reshape 我认为我们可以通过完成 for-loop 来实现它。
猜你喜欢
  • 2018-03-20
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 2023-01-15
  • 2021-07-05
  • 2020-10-19
相关资源
最近更新 更多