【问题标题】:How to plot a dictionary如何绘制字典
【发布时间】:2020-10-09 05:04:59
【问题描述】:

我在绘制以下值时遇到了一些问题:

my_dict={'word1': ['31', '131', '2'], 'word2': ['42', '33', '154', '21']}

我所做的是

plt.bar(my_dict.keys(), my_dict.values(), color='g')

但我得到了这个错误:

TypeError: ufunc 'add' 不包含带有签名匹配的循环 类型 dtype('

然后我尝试了

plt.plot(*zip(*sorted(my_dict.items())))
plt.show()

但我得到了另一个错误:

TypeError: unhashable type: 'list'

我会对频率感兴趣。

我应该怎么做才能解决它?

来自原始数据集(因为我在复制代码时遇到了一些错误):

my_dict = defaultdict(list)

print({ k : v for k, v in my_dict.items() })

输出:

{'word1': ['122', '121.2', '132', '132', '144', '144.5', '144', '150', '150,5', '150,5', '150,5'], 'word2': ['230', '230', '230', '230'], 'word3': ['542', '542', '540'], 'word4': ['134', '134']}

我需要绘制每个单词中值的频率(例如,对于 word1,132 和 144 的频率应为 2,150.5 的频率应为 3,所有其他值的频率应为 1)。

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    您可以使用matplotlib 做到这一点:

    import matplotlib.pyplot as plt
    from numpy import random
    
    mydict={'word1': ['122', '121.2', '132', '132', '144', '144.5', '144', '150', '150,5', '150,5', '150,5'], 'word2': ['230', '230', '230', '230'], 'word3': ['542', '542', '540'], 'word4': ['134', '134']}
    
    
    for k,l in mydict.items():
        labeled = False
        c=random.rand(3,)
        for v in l:
            if labeled:
                plt.bar(v,len([d for d in l if d==v]),color=c)
            else:
                plt.bar(v,len([d for d in l if d==v]),label=k,color=c)
                labeled = True
    
    plt.legend()
    plt.show()
    

    【讨论】:

    • 是的,但是轴应该倒置。我需要 y 轴上的频率和 x 轴上 word1 和 word2 的值。为了区分它们,我想改变颜色,看看哪些与 word1 相关,哪些与 word2 相关。我不明白 x 轴上有什么。它应该是一个频率图,不是吗?
    • 非常感谢@Ann Zen :)
    【解决方案2】:

    使用pandaszip_longest

    • Pandas 要求列的长度相同,因此zip_longest 将用None 填充空白。
    • 有许多选项可以根据您想要的绘图方式来塑造数据。
    import pandas as pd
    from itertools import zip_longest
    import matplotlib.pyplot as plt
    
    # data
    d = {'word1': ['122', '121.2', '132', '132', '144', '144.5', '144', '150', '150.5', '150.5', '150.5'], 'word2': ['230', '230', '230', '230'], 'word3': ['542', '542', '540'], 'word4': ['134', '134']}
    
    # since the values lists are uneven
    cols = d.keys()
    val = list(zip_longest(*d.values()))
    
    # dataframe
    df = pd.DataFrame(val, columns=cols, dtype=float)
    
        word1  word2  word3  word4
    0   122.0  230.0  542.0  134.0
    1   121.2  230.0  542.0  134.0
    2   132.0  230.0  540.0    NaN
    3   132.0  230.0    NaN    NaN
    4   144.0    NaN    NaN    NaN
    5   144.5    NaN    NaN    NaN
    6   144.0    NaN    NaN    NaN
    7   150.0    NaN    NaN    NaN
    8   150.5    NaN    NaN    NaN
    9   150.5    NaN    NaN    NaN
    10  150.5    NaN    NaN    NaN
    

    带有注释的绘图

    ax = df.plot.bar()
    
    f = [df[c].value_counts().to_dict() for c in df.columns]  # list of list of value counts
    f = dict(kv for d in f for kv in d.items())  # this will break if the values for each word aren't unique
    
    for p in ax.patches:
    
        if p.get_height() > 0:
    
            # add value at top of bar
            ax.annotate(format(p.get_height(), '.1f'),
                        (p.get_x() + p.get_width() / 2., p.get_height() + 10),
                        ha = 'center', va = 'center', fontsize=9, rotation=90,
                        xytext = (0, 10), textcoords = 'offset points')
    
            # add frequency of value at center of bar
            ax.annotate(format(f[p.get_height()], '.0f'),
                (p.get_x() + p.get_width() / 2., p.get_height() / 2),
                ha = 'center', va = 'center', fontsize=9, rotation=0,
                xytext = (0, 10), textcoords = 'offset points')
    

    tdf = df.T  # transpose dataframe df
    
    ax = tdf.plot.bar()
    
    f = [df[c].value_counts().to_dict() for c in df.columns]  # list of list of value counts
    f = dict(kv for d in f for kv in d.items())  # this will break if the values for each word aren't unique
    
    for p in ax.patches:
    
        if p.get_height() > 0:
    
            # add value at top of bar
            ax.annotate(format(p.get_height(), '.1f'),
                        (p.get_x() + p.get_width() / 2., p.get_height() + 10),
                        ha = 'center', va = 'center', fontsize=9, rotation=90,
                        xytext = (0, 10), textcoords = 'offset points')
    
            # add frequency of value at center of bar
            ax.annotate(format(f[p.get_height()], '.0f'),
                (p.get_x() + p.get_width() / 2., p.get_height() / 2),
                ha = 'center', va = 'center', fontsize=9, rotation=0,
                xytext = (0, 10), textcoords = 'offset points')
    

    没有注释

    • hue 着色根据hue 使用的列中唯一值的数量,在本例中为word,使条形偏离中心。
      • 在下面的示例中,所有四个单词都包含值150.5,因此您可以在图中看到它们被分组。
    • 条形是水平的以容纳大量值。
      • 只需增加figsize 的高度。
    import seaborn as sns
    
    d = {'word1': ['122', '121.2', '132', '132', '144', '144.5', '144', '150', '150.5', '150.5', '150.5'], 'word2': ['230', '230', '230', '230', '150.5'], 'word3': ['542', '542', '540', '150.5'], 'word4': ['134', '134', '150.5']}
    
    cols = d.keys()
    val = list(zip_longest(*d.values()))
    
    # dataframe
    df = pd.DataFrame(val, columns=cols, dtype=float)
    
    # convert from wide to long
    df['id'] = df.index
    dfl = pd.wide_to_long(df, stubnames='word', j='x', i='id').reset_index().rename(columns={'word': 'v', 'x': 'word'}).dropna()
    
    # groupby for frequency counts
    dflg = dfl.groupby('word').agg({'v': 'value_counts'}).rename(columns={'v': 'freq_count'}).reset_index().sort_values('v')
    
    # plot
    plt.figure(figsize=(6, 10))
    p = sns.barplot(y='v', x='freq_count', data=dflg, hue='word', orient='h')
    

    【讨论】:

    • 谢谢@Trenton McKinney,这就是我一直在寻找的。是否可以在 y 轴上看到频率(相同项目的数量)?不幸的是,当我使用原始数据集进行绘图时,我只能看到最后一项(word2)。
    • 非常感谢@Trenton McKinney 也感谢您的回答和花时间帮助我
    猜你喜欢
    • 2019-10-17
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 2021-10-09
    • 2022-10-18
    • 2021-07-01
    • 1970-01-01
    • 2022-01-19
    相关资源
    最近更新 更多