[python] 분산 형 데이터 세트를 사용하여 MatPlotLib에서 히트 맵 생성

산점도로 플롯하기 쉽지만 히트 맵으로 나타내려는 X, Y 데이터 포인트 (약 10k) 세트가 있습니다.

MatPlotLib의 예제를 살펴본 결과 이미지를 생성하기 위해 이미 히트 맵 셀 값으로 시작하는 것 같습니다.

x, y를 모두 다른 히트 맵으로 변환하는 방법이 있습니까?



답변

육각형을 원하지 않으면 numpy의 histogram2d함수를 사용할 수 있습니다 .

import numpy as np
import numpy.random
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()

이것은 50×50 히트 맵을 만듭니다. 512×384 bins=(512, 384)와 같은 전화를 원하면에 전화를 걸 수 histogram2d있습니다.

예: Matplotlib 히트 맵 예


답변

에서 하기 matplotlib의 어휘, 난 당신이 원하는 생각 hexbin의 플롯을.

이 유형의 플롯에 익숙하지 않은 경우 xy 평면이 규칙적인 육각형 격자로 테셀 레이트 되는 이변 량 히스토그램 일뿐 입니다.

히스토그램에서 각 육각형에 떨어지는 점의 수를 세고, 플로팅 영역을 일련의 창으로 분류하고 , 각 점을이 창 중 하나에 할당 할 수 있습니다. 마지막으로 창을 색상 배열 에 매핑하면 16 진 다이어그램이 나타납니다.

예를 들어 원이나 사각형보다 덜 일반적으로 사용되지만, 육각형이 비닝 컨테이너의 형상에 더 적합한 선택입니다.

  • 육각형이 가장 가까운 이웃 대칭을 (예, 사각형 쓰레기통 예는, 거리가 없습니다 에서 사각형 테두리의 한 점 그 사각형 안에 포인트가 사방 같지 않음) 및

  • 육각형은 규칙적인 평면 테셀레이션 을 제공하는 가장 높은 n- 폴리곤입니다. 즉, 완성 된 타일 사이에 빈 공간이 없기 때문에 육각형 타일로 부엌 바닥을 안전하게 리모델링 할 수 있습니다. 다른 모든 더 높은 n, n> = 7, 다각형).

( Matplotlib헥스 빈 플롯 이라는 용어를 사용합니다 . (AFAIK) R에 대한 모든 플로팅 라이브러리도 마찬가지입니다 . 여전히 이것이이 유형의 플롯에 일반적으로 허용되는 용어 인지모르겠지만 헥스 빈이 짧을 것으로 생각됩니다. 위한 육각형 비닝 ,되는 표시 용 데이터를 준비하는 필수 단계를 설명한다.)


from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP

n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)

# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then 
# the result is a pure 2D histogram 

PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])

cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()   

여기에 이미지 설명을 입력하십시오


답변

편집 : Alejandro의 대답을 더 잘 보려면 아래를 참조하십시오.

나는 이것이 오래된 질문이라는 것을 알고 있지만 Alejandro의 anwser에 무언가를 추가하고 싶었습니다 : py-sphviewer를 사용하지 않고 멋진 부드러운 이미지를 원한다면 np.histogram2d가우스 필터 ( scipy.ndimage.filters)를 히트 맵에 대신 적용 할 수 있습니다 .

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter


def myplot(x, y, s, bins=1000):
    heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
    heatmap = gaussian_filter(heatmap, sigma=s)

    extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
    return heatmap.T, extent


fig, axs = plt.subplots(2, 2)

# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

sigmas = [0, 16, 32, 64]

for ax, s in zip(axs.flatten(), sigmas):
    if s == 0:
        ax.plot(x, y, 'k.', markersize=5)
        ax.set_title("Scatter plot")
    else:
        img, extent = myplot(x, y, s)
        ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
        ax.set_title("Smoothing with  $\sigma$ = %d" % s)

plt.show()

생산 :

출력 이미지

아가페 갈로 (Agape Gal’lo)에 대해 서로의 위에 산점도 및 s = 16을 표시했습니다 (더 잘 보려면 클릭).

서로의 위에


내가 가우시안 필터 접근 방식과 Alejandro의 접근 방식에서 주목 한 한 가지 차이점은 그의 방법이 로컬 구조를 내 것보다 훨씬 잘 보여주는 것입니다. 따라서 픽셀 수준에서 가장 가까운 가장 가까운 이웃 방법을 구현했습니다. 이 방법은 각 픽셀 n에 대해 데이터에서 가장 가까운 점 의 거리의 역합을 계산 합니다. 이 방법은 계산 비용이 많이 드는 고해상도이며 더 빠른 방법이 있다고 생각하므로 개선 사항이 있으면 알려주십시오.

업데이트 : 의심 한 것처럼 Scipy ‘s를 사용하는 훨씬 빠른 방법이 scipy.cKDTree있습니다. 구현에 대한 가브리엘의 답변 을 참조하십시오 .

어쨌든, 여기 내 코드가 있습니다 :

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm


def data_coord2view_coord(p, vlen, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * vlen
    return dv


def nearest_neighbours(xs, ys, reso, n_neighbours):
    im = np.zeros([reso, reso])
    extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]

    xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
    yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
    for x in range(reso):
        for y in range(reso):
            xp = (xv - x)
            yp = (yv - y)

            d = np.sqrt(xp**2 + yp**2)

            im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])

    return im, extent


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250

fig, axes = plt.subplots(2, 2)

for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=2)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:
        im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
        ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])
plt.show()

결과:

가장 가까운 이웃 스무딩


답변

일반적으로 상당히 못생긴 히스토그램을 생성하는 np.hist2d를 사용하는 대신 , 적응 형 스무딩 커널을 사용하여 입자 시뮬레이션을 렌더링하기위한 python 패키지 인 py-sphviewer 를 재활용하고 싶습니다 . 웹 페이지 설명서를 참조하십시오. 예제를 기반으로하는 다음 코드를 고려하십시오.

import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph

def myplot(x, y, nb=32, xsize=500, ysize=500):   
    xmin = np.min(x)
    xmax = np.max(x)
    ymin = np.min(y)
    ymax = np.max(y)

    x0 = (xmin+xmax)/2.
    y0 = (ymin+ymax)/2.

    pos = np.zeros([3, len(x)])
    pos[0,:] = x
    pos[1,:] = y
    w = np.ones(len(x))

    P = sph.Particles(pos, w, nb=nb)
    S = sph.Scene(P)
    S.update_camera(r='infinity', x=x0, y=y0, z=0, 
                    xsize=xsize, ysize=ysize)
    R = sph.Render(S)
    R.set_logscale()
    img = R.get_image()
    extent = R.get_extent()
    for i, j in zip(xrange(4), [x0,x0,y0,y0]):
        extent[i] += j
    print extent
    return img, extent

fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)


# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)

heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)

ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")

ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")

#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")

plt.show()

다음 이미지를 생성합니다.

여기에 이미지 설명을 입력하십시오

보시다시피, 이미지는 매우 멋지게 보이고 이미지의 다른 하위 구조를 식별 할 수 있습니다. 이 이미지는 평활화 길이에 의해 정의 된 특정 도메인 내의 모든 포인트에 대해 주어진 가중치를 분산하여 구성되며, 이는 더 가까운 nb 이웃 까지의 거리에 의해 주어진다 (이 예제에서는 16, 32 및 64를 선택 함). 따라서 밀도가 높은 영역은 일반적으로 밀도가 낮은 영역에 비해 작은 영역에 분산됩니다.

myplot 함수는 x, y 데이터를 py-sphviewer에 제공하여 마법을 수행하기 위해 작성한 매우 간단한 함수입니다.


답변

1.2.x를 사용중인 경우

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()

gaussian_2d_heat_map


답변

Seaborn은 이제 다음과 같이 훌륭하게 작동 하는 jointplot 기능 을 가지고 있습니다 :

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

sns.jointplot(x=x, y=y, kind='hex')
plt.show()

데모 이미지


답변

그리고 초기 질문은 … 산란 값을 그리드 값으로 변환하는 방법이었습니다.
histogram2d셀당 빈도를 계산하지만 셀당 빈도 이외의 다른 데이터가있는 경우 추가 작업이 필요합니다.

x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset

그래서 X 및 Y 좌표에 대한 Z 결과가있는 데이터 세트가 있습니다. 그러나 관심 영역 외부의 몇 점 (큰 간격)과 작은 관심 영역의 점 힙을 계산하고있었습니다.

예, 여기서는 더 어려워 지지만 더 재미 있습니다. 일부 라이브러리 (죄송합니다) :

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata

pyplot은 오늘날 내 그래픽 엔진이며 cm은 initeresting을 선택할 수있는 다양한 색상 맵입니다. 계산을위한 numpy 및 고정 된 그리드에 값을 첨부하기위한 griddata

마지막 것은 xy 포인트의 빈도가 내 데이터에 균등하게 분포되어 있지 않기 때문에 특히 중요합니다. 먼저 내 데이터와 임의의 격자 크기에 맞는 경계로 시작합시다. 원본 데이터에는 해당 x 및 y 경계 외부에도 데이터 포인트가 있습니다.

#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7

따라서 x와 y의 최소값과 최대 값 사이에 500 픽셀의 격자를 정의했습니다.

내 데이터에는 높은 관심 분야에서 사용할 수있는 500 개 이상의 값이 있습니다. 낮은 관심 분야에서는 전체 그리드에 200 개의 값이 없습니다. 그래픽 경계 x_minx_max그 사이 에는 훨씬 적은 수가 있습니다.

멋진 그림을 얻으려면 높은 관심 가치에 대한 평균을 얻고 다른 곳의 차이를 메우는 것이 임무입니다.

이제 그리드를 정의합니다. 각 xx-yy 쌍마다 색상을 원합니다.

xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T

왜 이상한 모양입니까? scipy.griddata 는 (n, D) 모양을 원합니다.

Griddata는 미리 정의 된 방법으로 그리드의 포인트 당 하나의 값을 계산합니다. “가장 가까운”을 선택합니다. 빈 그리드 포인트는 가장 가까운 이웃의 값으로 채워집니다. 이것은 정보가 적은 영역이 셀이 더 큰 것처럼 보입니다 (그렇지 않은 경우에도). “선형”을 보간하도록 선택할 수 있으며 정보가 적은 영역은 덜 선명 해 보입니다. 정말로 맛의 문제.

points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])

그리고 홉, 우리는 음모를 표시하기 위해 matplotlib로 넘겨줍니다.

fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max,  ],
            origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()

V-Shape의 뾰족한 부분 주위에서 스위트 스폿을 검색하는 동안 많은 계산을 수행했지만 거의 모든 곳에서 덜 흥미로운 부분은 해상도가 낮습니다.

고해상도의 SVC 히트 맵