国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

5種方法教你用Python玩轉(zhuǎn)histogram直方圖

simpleapples / 613人閱讀

摘要:使用實(shí)現(xiàn)以上是使用純來完成的簡(jiǎn)單直方圖,但是從數(shù)學(xué)意義上來看,直方圖是分箱到頻數(shù)的一種映射,它可以用來估計(jì)變量的概率密度函數(shù)的。第一種情況你是在估計(jì)一個(gè)未知的概率密度函數(shù),而第二種情況是你是知道分布的,并想知道哪些參數(shù)可以更好的描述數(shù)據(jù)。

作者:xiaoyu

微信公眾號(hào):Python數(shù)據(jù)科學(xué)

知乎:python數(shù)據(jù)分析師


直方圖是一個(gè)可以快速展示數(shù)據(jù)概率分布的工具,直觀易于理解,并深受數(shù)據(jù)愛好者的喜愛。大家平時(shí)可能見到最多就是 matplotlibseaborn 等高級(jí)封裝的庫包,類似以下這樣的繪圖。

本篇博主將要總結(jié)一下使用Python繪制直方圖的所有方法,大致可分為三大類(詳細(xì)劃分是五類,參照文末總結(jié)):

純Python實(shí)現(xiàn)直方圖,不使用任何第三方庫

使用Numpy來創(chuàng)建直方圖總結(jié)數(shù)據(jù)

使用matplotlibpandasseaborn繪制直方圖

下面,我們來逐一介紹每種方法的來龍去脈。

純Python實(shí)現(xiàn)histogram

當(dāng)準(zhǔn)備用純Python來繪制直方圖的時(shí)候,最簡(jiǎn)單的想法就是將每個(gè)值出現(xiàn)的次數(shù)以報(bào)告形式展示。這種情況下,使用 字典 來完成這個(gè)任務(wù)是非常合適的,我們看看下面代碼是如何實(shí)現(xiàn)的。

>>> a = (0, 1, 1, 1, 2, 3, 7, 7, 23)

>>> def count_elements(seq) -> dict:
...     """Tally elements from `seq`."""
...     hist = {}
...     for i in seq:
...         hist[i] = hist.get(i, 0) + 1
...     return hist

>>> counted = count_elements(a)
>>> counted
{0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}

我們看到,count_elements() 返回了一個(gè)字典,字典里出現(xiàn)的鍵為目標(biāo)列表里面的所有唯一數(shù)值,而值為所有數(shù)值出現(xiàn)的頻率次數(shù)。hist[i] = hist.get(i, 0) + 1 實(shí)現(xiàn)了每個(gè)數(shù)值次數(shù)的累積,每次加一。

實(shí)際上,這個(gè)功能可以用一個(gè)Python的標(biāo)準(zhǔn)庫 collection.Counter 類來完成,它兼容Pyhont 字典并覆蓋了字典的 .update() 方法。

>>> from collections import Counter

>>> recounted = Counter(a)
>>> recounted
Counter({0: 1, 1: 3, 3: 1, 2: 1, 7: 2, 23: 1})

可以看到這個(gè)方法和前面我們自己實(shí)現(xiàn)的方法結(jié)果是一樣的,我們也可以通過 collection.Counter 來檢驗(yàn)兩種方法得到的結(jié)果是否相等。

>>> recounted.items() == counted.items()
True

我們利用上面的函數(shù)重新再造一個(gè)輪子 ASCII_histogram,并最終通過Python的輸出格式format來實(shí)現(xiàn)直方圖的展示,代碼如下:

def ascii_histogram(seq) -> None:
    """A horizontal frequency-table/histogram plot."""
    counted = count_elements(seq)
    for k in sorted(counted):
        print("{0:5d} {1}".format(k, "+" * counted[k]))

這個(gè)函數(shù)按照數(shù)值大小順序進(jìn)行繪圖,數(shù)值出現(xiàn)次數(shù)用 (+) 符號(hào)表示。在字典上調(diào)用 sorted() 將會(huì)返回一個(gè)按鍵順序排列的列表,然后就可以獲取相應(yīng)的次數(shù) counted[k]

>>> import random
>>> random.seed(1)

>>> vals = [1, 3, 4, 6, 8, 9, 10]
>>> # `vals` 里面的數(shù)字將會(huì)出現(xiàn)5到15次
>>> freq = (random.randint(5, 15) for _ in vals)

>>> data = []
>>> for f, v in zip(freq, vals):
...     data.extend([v] * f)

>>> ascii_histogram(data)
    1 +++++++
    3 ++++++++++++++
    4 ++++++
    6 +++++++++
    8 ++++++
    9 ++++++++++++
   10 ++++++++++++

這個(gè)代碼中,vals內(nèi)的數(shù)值是不重復(fù)的,并且每個(gè)數(shù)值出現(xiàn)的頻數(shù)是由我們自己定義的,在5和15之間隨機(jī)選擇。然后運(yùn)用我們上面封裝的函數(shù),就得到了純Python版本的直方圖展示。

總結(jié):純python實(shí)現(xiàn)頻數(shù)表(非標(biāo)準(zhǔn)直方圖),可直接使用collection.Counter方法實(shí)現(xiàn)。

使用Numpy實(shí)現(xiàn)histogram

以上是使用純Python來完成的簡(jiǎn)單直方圖,但是從數(shù)學(xué)意義上來看,直方圖是分箱到頻數(shù)的一種映射,它可以用來估計(jì)變量的概率密度函數(shù)的。而上面純Python實(shí)現(xiàn)版本只是單純的頻數(shù)統(tǒng)計(jì),不是真正意義上的直方圖。

因此,我們從上面實(shí)現(xiàn)的簡(jiǎn)單直方圖繼續(xù)往下進(jìn)行升級(jí)。一個(gè)真正的直方圖首先應(yīng)該是將變量分區(qū)域(箱)的,也就是分成不同的區(qū)間范圍,然后對(duì)每個(gè)區(qū)間內(nèi)的觀測(cè)值數(shù)量進(jìn)行計(jì)數(shù)。恰巧,Numpy的直方圖方法就可以做到這點(diǎn),不僅僅如此,它也是后面將要提到的matplotlib和pandas使用的基礎(chǔ)。

舉個(gè)例子,來看一組從拉普拉斯分布上提取出來的浮點(diǎn)型樣本數(shù)據(jù)。這個(gè)分布比標(biāo)準(zhǔn)正態(tài)分布擁有更寬的尾部,并有兩個(gè)描述參數(shù)(location和scale):

>>> import numpy as np

>>> np.random.seed(444)
>>> np.set_printoptions(precision=3)

>>> d = np.random.laplace(loc=15, scale=3, size=500)
>>> d[:5]
array([18.406, 18.087, 16.004, 16.221,  7.358])

由于這是一個(gè)連續(xù)型的分布,對(duì)于每個(gè)多帶帶的浮點(diǎn)值(即所有的無數(shù)個(gè)小數(shù)位置)并不能做很好的標(biāo)簽(因?yàn)辄c(diǎn)實(shí)在太多了)。但是,你可以將數(shù)據(jù)做 分箱 處理,然后統(tǒng)計(jì)每個(gè)箱內(nèi)觀察值的數(shù)量,這就是真正的直方圖所要做的工作。

下面我們看看是如何用Numpy來實(shí)現(xiàn)直方圖頻數(shù)統(tǒng)計(jì)的。

>>> hist, bin_edges = np.histogram(d)

>>> hist
array([ 1,  0,  3,  4,  4, 10, 13,  9,  2,  4])

>>> bin_edges
array([ 3.217,  5.199,  7.181,  9.163, 11.145, 13.127, 15.109, 17.091,
       19.073, 21.055, 23.037])

這個(gè)結(jié)果可能不是很直觀。來說一下,np.histogram() 默認(rèn)地使用10個(gè)相同大小的區(qū)間(箱),然后返回一個(gè)元組(頻數(shù),分箱的邊界),如上所示。要注意的是:這個(gè)邊界的數(shù)量是要比分箱數(shù)多一個(gè)的,可以簡(jiǎn)單通過下面代碼證實(shí)。

>>> hist.size, bin_edges.size
(10, 11)

那問題來了,Numpy到底是如何進(jìn)行分箱的呢?只是通過簡(jiǎn)單的 np.histogram() 就可以完成了,但具體是如何實(shí)現(xiàn)的我們?nèi)匀蝗徊恢O旅孀屛覀儊韺?np.histogram() 的內(nèi)部進(jìn)行解剖,看看到底是如何實(shí)現(xiàn)的(以最前面提到的a列表為例)。

>>> # 取a的最小值和最大值
>>> first_edge, last_edge = a.min(), a.max()

>>> n_equal_bins = 10  # NumPy得默認(rèn)設(shè)置,10個(gè)分箱
>>> bin_edges = np.linspace(start=first_edge, stop=last_edge,
...                         num=n_equal_bins + 1, endpoint=True)
...
>>> bin_edges
array([ 0. ,  2.3,  4.6,  6.9,  9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23. ])

解釋一下:首先獲取a列表的最小值和最大值,然后設(shè)置默認(rèn)的分箱數(shù)量,最后使用Numpy的 linspace 方法進(jìn)行數(shù)據(jù)段分割。分箱區(qū)間的結(jié)果也正好與實(shí)際吻合,0到23均等分為10份,23/10,那么每份寬度為2.3。

除了np.histogram之外,還存在其它兩種可以達(dá)到同樣功能的方法:np.bincount()np.searchsorted(),下面看看代碼以及比較結(jié)果。

>>> bcounts = np.bincount(a)
>>> hist, _ = np.histogram(a, range=(0, a.max()), bins=a.max() + 1)

>>> np.array_equal(hist, bcounts)
True

>>> # Reproducing `collections.Counter`
>>> dict(zip(np.unique(a), bcounts[bcounts.nonzero()]))
{0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}

總結(jié):通過Numpy實(shí)現(xiàn)直方圖,可直接使用np.histogram()或者np.bincount()。

使用Matplotlib和Pandas可視化Histogram

從上面的學(xué)習(xí),我們看到了如何使用Python的基礎(chǔ)工具搭建一個(gè)直方圖,下面我們來看看如何使用更為強(qiáng)大的Python庫包來完成直方圖。Matplotlib基于Numpy的histogram進(jìn)行了多樣化的封裝并提供了更加完善的可視化功能。

import matplotlib.pyplot as plt

#  matplotlib.axes.Axes.hist() 方法的接口
n, bins, patches = plt.hist(x=d, bins="auto", color="#0504aa",
                            alpha=0.7, rwidth=0.85)
plt.grid(axis="y", alpha=0.75)
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.title("My Very Own Histogram")
plt.text(23, 45, r"$mu=15, b=3$")
maxfreq = n.max()
# 設(shè)置y軸的上限
plt.ylim(ymax=np.ceil(maxfreq / 10) * 10 if maxfreq % 10 else maxfreq + 10)


之前我們的做法是,在x軸上定義了分箱邊界,y軸是相對(duì)應(yīng)的頻數(shù),不難發(fā)現(xiàn)我們都是手動(dòng)定義了分箱的數(shù)目。但是在以上的高級(jí)方法中,我們可以通過設(shè)置 bins="auto" 自動(dòng)在寫好的兩個(gè)算法中擇優(yōu)選擇并最終算出最適合的分箱數(shù)。這里,算法的目的就是選擇出一個(gè)合適的區(qū)間(箱)寬度,并生成一個(gè)最能代表數(shù)據(jù)的直方圖來。

如果使用Python的科學(xué)計(jì)算工具實(shí)現(xiàn),那么可以使用Pandas的 Series.histogram() ,并通過 matplotlib.pyplot.hist() 來繪制輸入Series的直方圖,如下代碼所示。

import pandas as pd

size, scale = 1000, 10
commutes = pd.Series(np.random.gamma(scale, size=size) ** 1.5)

commutes.plot.hist(grid=True, bins=20, rwidth=0.9,
                   color="#607c8e")
plt.title("Commute Times for 1,000 Commuters")
plt.xlabel("Counts")
plt.ylabel("Commute Time")
plt.grid(axis="y", alpha=0.75)


pandas.DataFrame.histogram() 的用法與Series是一樣的,但生成的是對(duì)DataFrame數(shù)據(jù)中的每一列的直方圖。

總結(jié):通過pandas實(shí)現(xiàn)直方圖,可使用Seris.plot.hist(),DataFrame.plot.hist(),matplotlib實(shí)現(xiàn)直方圖可以用matplotlib.pyplot.hist()。

繪制核密度估計(jì)(KDE)

KDE(Kernel density estimation)是核密度估計(jì)的意思,它用來估計(jì)隨機(jī)變量的概率密度函數(shù),可以將數(shù)據(jù)變得更平緩。

使用Pandas庫的話,你可以使用 plot.kde() 創(chuàng)建一個(gè)核密度的繪圖,plot.kde() 對(duì)于 Series和DataFrame數(shù)據(jù)結(jié)構(gòu)都適用。但是首先,我們先生成兩個(gè)不同的數(shù)據(jù)樣本作為比較(兩個(gè)正太分布的樣本):

>>> # 兩個(gè)正太分布的樣本
>>> means = 10, 20
>>> stdevs = 4, 2
>>> dist = pd.DataFrame(
...     np.random.normal(loc=means, scale=stdevs, size=(1000, 2)),
...     columns=["a", "b"])
>>> dist.agg(["min", "max", "mean", "std"]).round(decimals=2)
          a      b
min   -1.57  12.46
max   25.32  26.44
mean  10.12  19.94
std    3.94   1.94

以上看到,我們生成了兩組正態(tài)分布樣本,并且通過一些描述性統(tǒng)計(jì)參數(shù)對(duì)兩組數(shù)據(jù)進(jìn)行了簡(jiǎn)單的對(duì)比。現(xiàn)在,我們可以在同一個(gè)Matplotlib軸上繪制每個(gè)直方圖以及對(duì)應(yīng)的kde,使用pandas的plot.kde()的好處就是:它會(huì)自動(dòng)的將所有列的直方圖和kde都顯示出來,用起來非常方便,具體代碼如下:

fig, ax = plt.subplots()
dist.plot.kde(ax=ax, legend=False, title="Histogram: A vs. B")
dist.plot.hist(density=True, ax=ax)
ax.set_ylabel("Probability")
ax.grid(axis="y")
ax.set_facecolor("#d8dcd6")


總結(jié):通過pandas實(shí)現(xiàn)kde圖,可使用Seris.plot.kde(),DataFrame.plot.kde()。

使用Seaborn的完美替代

一個(gè)更高級(jí)可視化工具就是Seaborn,它是在matplotlib的基礎(chǔ)上進(jìn)一步封裝的強(qiáng)大工具。對(duì)于直方圖而言,Seaborn有 distplot() 方法,可以將單變量分布的直方圖和kde同時(shí)繪制出來,而且使用及其方便,下面是實(shí)現(xiàn)代碼(以上面生成的d為例):

import seaborn as sns

sns.set_style("darkgrid")
sns.distplot(d)


distplot方法默認(rèn)的會(huì)繪制kde,并且該方法提供了 fit 參數(shù),可以根據(jù)數(shù)據(jù)的實(shí)際情況自行選擇一個(gè)特殊的分布來對(duì)應(yīng)。

sns.distplot(d, fit=stats.laplace, kde=False)

注意這兩個(gè)圖微小的區(qū)別。第一種情況你是在估計(jì)一個(gè)未知的概率密度函數(shù)(PDF),而第二種情況是你是知道分布的,并想知道哪些參數(shù)可以更好的描述數(shù)據(jù)。

總結(jié):通過seaborn實(shí)現(xiàn)直方圖,可使用seaborn.distplot(),seaborn也有多帶帶的kde繪圖seaborn.kde()。

在Pandas中的其它工具

除了繪圖工具外,pandas也提供了一個(gè)方便的.value_counts() 方法,用來計(jì)算一個(gè)非空值的直方圖,并將之轉(zhuǎn)變成一個(gè)pandas的series結(jié)構(gòu),示例如下:

>>> import pandas as pd

>>> data = np.random.choice(np.arange(10), size=10000,
...                         p=np.linspace(1, 11, 10) / 60)
>>> s = pd.Series(data)

>>> s.value_counts()
9    1831
8    1624
7    1423
6    1323
5    1089
4     888
3     770
2     535
1     347
0     170
dtype: int64

>>> s.value_counts(normalize=True).head()
9    0.1831
8    0.1624
7    0.1423
6    0.1323
5    0.1089
dtype: float64

此外,pandas.cut() 也同樣是一個(gè)方便的方法,用來將數(shù)據(jù)進(jìn)行強(qiáng)制的分箱。比如說,我們有一些人的年齡數(shù)據(jù),并想把這些數(shù)據(jù)按年齡段進(jìn)行分類,示例如下:

>>> ages = pd.Series(
...     [1, 1, 3, 5, 8, 10, 12, 15, 18, 18, 19, 20, 25, 30, 40, 51, 52])
>>> bins = (0, 10, 13, 18, 21, np.inf)  # 邊界
>>> labels = ("child", "preteen", "teen", "military_age", "adult")
>>> groups = pd.cut(ages, bins=bins, labels=labels)

>>> groups.value_counts()
child           6
adult           5
teen            3
military_age    2
preteen         1
dtype: int64

>>> pd.concat((ages, groups), axis=1).rename(columns={0: "age", 1: "group"})
    age         group
0     1         child
1     1         child
2     3         child
3     5         child
4     8         child
5    10         child
6    12       preteen
7    15          teen
8    18          teen
9    18          teen
10   19  military_age
11   20  military_age
12   25         adult
13   30         adult
14   40         adult
15   51         adult
16   52         adult

除了使用方便外,更加好的是這些操作最后都會(huì)使用 Cython 代碼來完成,在運(yùn)行速度的效果上也是非常快的。

總結(jié):其它實(shí)現(xiàn)直方圖的方法,可使用.value_counts()和pandas.cut()。

該使用哪個(gè)方法?

至此,我們了解了很多種方法來實(shí)現(xiàn)一個(gè)直方圖。但是它們各自有什么有缺點(diǎn)呢?該如何對(duì)它們進(jìn)行選擇呢?當(dāng)然,一個(gè)方法解決所有問題是不存在的,我們也需要根據(jù)實(shí)際情況而考慮如何選擇,下面是對(duì)一些情況下使用方法的一個(gè)推薦,僅供參考。

參考:https://realpython.com/python...

關(guān)注微信公眾號(hào):Python數(shù)據(jù)科學(xué),查看更多精彩內(nèi)容。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/42006.html

相關(guān)文章

  • ??蘇州程序大白一文從基礎(chǔ)手把手教你Python數(shù)據(jù)可視化大佬??《??記得收藏??》

    ??蘇州程序大白一文從基礎(chǔ)手把手教你Python數(shù)據(jù)可視化大佬??《??記得收藏??》 目錄 ????開講啦!!!!????蘇州程序大白?????博主介紹前言數(shù)據(jù)關(guān)系可視化散點(diǎn)圖 Scatter plots折線圖強(qiáng)調(diào)連續(xù)性 Emphasizing continuity with line plots同時(shí)顯示多了圖表 數(shù)據(jù)種類的可視化 Plotting with categorical da...

    Drinkey 評(píng)論0 收藏0
  • opencv python 2D方圖

    Histograms - 3 : 2D Histograms 我們已經(jīng)計(jì)算并繪制了一維直方圖,因?yàn)槲覀冎豢紤]一個(gè)特征,即像素的灰度強(qiáng)度值.但在二維直方圖中,需要考慮兩個(gè)特征,通常,它用于查找顏色直方圖,其中兩個(gè)要素是每個(gè)像素的色調(diào)和飽和度值. OpenCV中的2D直方圖 使用函數(shù)cv.calcHist(), 對(duì)于顏色直方圖,我們需要將圖像從BGR轉(zhuǎn)換為HSV。 (請(qǐng)記住,對(duì)于1D直方圖,我們從B...

    BlackFlagBin 評(píng)論0 收藏0
  • Programming Computer Vision with Python (學(xué)習(xí)筆記二)

    摘要:首先介紹跟圖像處理顯示有關(guān)兩個(gè)庫和,然后介紹增強(qiáng)圖像對(duì)比度的實(shí)現(xiàn)原理。直方圖均衡化就是為了達(dá)到這個(gè)目的,均衡化后的圖像,像素落在每個(gè)灰度級(jí)上的個(gè)數(shù)是相等的。 首先介紹跟圖像處理、顯示有關(guān)兩個(gè)庫:NumPy和Matplotlib,然后介紹增強(qiáng)圖像對(duì)比度的實(shí)現(xiàn)原理。 NumPy NumPy是Python用于科學(xué)計(jì)算的基礎(chǔ)庫,提供了一些很有用的概念,如:N維數(shù)組對(duì)象,可用于表示向量、矩陣、圖...

    Berwin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<