簡體   English   中英

標准化二維直方圖

[英]Normalising a 2D histogram

我有一個二維直方圖 h1,x 軸上有 var1,y 軸上有 var2,這是我從dataframe繪制的。 我已經在 c++ 中對其進行了標准化,但現在需要在 python 中執行相同的操作,並且正在努力解決如何獲取和設置 bin 內容。

這個想法是消除在分布的一部分中比在另一部分中具有更多事件的影響,並且只保留var1var2之間的相關性。

c++中的工作代碼:

double norm = h1->GetEntries()/h1->GetNbinsX();
 
    int nbins = h1->GetNbinsX();
    for(int i = 1; i< nbins+1; i++)
      {
        double nevents = 0.;
        for(int iy = 1; iy< h1->GetNbinsY()+1; iy++)
          {
          float bincont = h1->GetBinContent(i,iy);
          nevents+=bincont;
          }

        for(int iy = 1; iy< h1->GetNbinsY()+1; iy++) 
        {
          float bincont = h1->GetBinContent(i,iy);
          float fact = norm/nevents;
          float value = bincont*fact;
          h1->SetBinContent(i,iy,value);
        }
      }

嘗試 python 中的代碼:

plt.hist2d(var1, var2, bins=(11100, 1030), cmap=plt.cm.BuPu)

norm = 10
for i in var1:
    nevents = 0.
    for j in var2:
        plt.GetBinContent(i,j)
        nevents+=bincont

    for j in var2:
        plt.GetBinContent(i,j)
        fact = norm/nevents
        value = bincont*fact

        plt.SetBinContent(i, j, value)

在@JohanC 的幫助下進行編輯:

問題已解決。 確保正常化時沒有 nan-s,因為與它們打交道總是很痛苦。

要操作垃圾箱的內容,您可以先計算它們,更改它們,然后才能繪制 plot。

plt.hist2d()返回 bin 內容(二維矩陣)以及兩個方向的 bin 邊緣。 為了在不繪圖的情況下獲得相同的信息, np.histogram2d()返回完全相同的值。 之后,可以通過plt.pcolormesh()繪制結果。

由於某種原因,返回的矩陣被轉置。 所以,第一步是再次轉置它。

為了計算和並在 2D arrays 上進行乘法和除法,numpy 具有一些強大的數組和廣播操作。 C++ 中的雙循環只是 numpy 中的一項操作: hist *= norm / hist.sum(axis=0, keepdims=True) 由於分母可以為零,因此可以抑制警告(結果將是NaNInf被忽略以進行繪圖)。

這是一些演示代碼。 請注意,使用bins=(11100, 1030)非常大。 下面的代碼使用小得多的值。

from matplotlib import pyplot as plt
import numpy as np

N = 1000000
var1 = np.concatenate([np.random.uniform(0, 20, size=9 * N // 10), np.random.normal(10, 1, size=N // 10)])
var2 = var1 * 0.1 + np.random.normal(size=N)

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4))

norm = 10
binsX = 200
binsY = 100
ax1.hist2d(var1, var2, bins=(binsX, binsY), cmap='BuPu')
ax1.set_title('regular 2d histogram')

hist, xedges, yedges = np.histogram2d(var1, var2, bins=(binsX, binsY))
hist = hist.T
with np.errstate(divide='ignore', invalid='ignore'):  # suppress division by zero warnings
    hist *= norm / hist.sum(axis=0, keepdims=True)
ax2.pcolormesh(xedges, yedges, hist, cmap='BuPu')
ax2.set_title('normalized columns')
plt.show()

示例圖

PS:關於hist *= norm / hist.sum(axis=0, keepdims=True)

  • hist.sum(axis=0, keepdims=True)創建一個新矩陣(將其命名為s ),其中每個h[i, j]的元素都替換為所有i的總和,因此s[i, j] = sum([h[k,j] for k in range(0, N)]) 如果沒有keepdims=True ,將創建一個只有總和的一維數組。
  • hist *= norm / s在所有i,j上創建一個循環,如h[i,j]=h[i,j]*norm/s[i,j] 除以零會在將零除以零時創建NaN ,在將另一個數字除以零時創建inf 這些值被pcolormesh忽略。

您可以選擇執行nan_to_num()

hist = np.nan_to_num(hist, nan=0, posinf=0, neginf=0)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM