Tạo sơ đồ nhiệt trong MatPlotLib bằng cách sử dụng bộ dữ liệu phân tán


187

Tôi có một tập hợp các điểm dữ liệu X, Y (khoảng 10k), dễ dàng vẽ đồ thị như một biểu đồ phân tán nhưng tôi muốn trình bày dưới dạng bản đồ nhiệt.

Tôi đã xem qua các ví dụ trong MatPlotLib và tất cả chúng dường như đã bắt đầu với các giá trị ô bản đồ nhiệt để tạo ra hình ảnh.

Có phương pháp nào chuyển đổi một bó x, y, tất cả khác nhau, thành một bản đồ nhiệt (trong đó các vùng có tần số cao hơn x, y sẽ "ấm hơn") không?


Câu trả lời:


182

Nếu bạn không muốn hình lục giác, bạn có thể sử dụng histogram2dchức năng của numpy :

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()

Điều này làm cho một bản đồ nhiệt 50x50. Nếu bạn muốn, giả sử, 512x384, bạn có thể thực bins=(512, 384)hiện cuộc gọi đến histogram2d.

Thí dụ: Ví dụ bản đồ nhiệt Matplotlib


1
Tôi không có nghĩa là một thằng ngốc, nhưng làm thế nào để bạn thực sự có đầu ra này cho một tệp PNG / PDF thay vì chỉ hiển thị trong một phiên IPython tương tác? Tôi đang cố gắng để có được điều này như một axesví dụ thông thường , nơi tôi có thể thêm tiêu đề, nhãn trục, v.v. và sau đó làm bình thường savefig()như tôi sẽ làm cho bất kỳ âm mưu matplotlib điển hình nào khác.
gotgenes

3
@gotgenes: không plt.savefig('filename.png')hoạt động? Nếu bạn muốn có một phiên bản trục, hãy sử dụng giao diện hướng đối tượng của Matplotlib:fig = plt.figure() ax = fig.gca() ax.imshow(...) fig.savefig(...)
ptomato

1
Thật vậy, cảm ơn! Tôi đoán rằng tôi không hoàn toàn hiểu rằng đó imshow()là trên cùng một loại chức năng như scatter(). Tôi thực sự không hiểu tại sao imshow()chuyển đổi một mảng nổi 2d thành các khối màu phù hợp, trong khi tôi không hiểu scatter()phải làm gì với một mảng như vậy.
gotgenes

14
Một cảnh báo về việc sử dụng imshow để vẽ biểu đồ 2d của các giá trị x / y như thế này: theo mặc định, imshow vẽ sơ đồ gốc ở góc trên bên trái và hoán chuyển hình ảnh. Những gì tôi sẽ làm để có được định hướng tương tự như một âm mưu phân tán làplt.imshow(heatmap.T, extent=extent, origin = 'lower')
Jamie

7
Đối với những người muốn làm một thanh màu logarit, hãy xem câu hỏi này stackoverflow.com/questions/17201172/ và và chỉ cần làmfrom matplotlib.colors import LogNorm plt.imshow(heatmap, norm=LogNorm()) plt.colorbar()
tommy.carstensen

109

Trong từ vựng Matplotlib , tôi nghĩ rằng bạn muốn một cốt truyện hexbin .

Nếu bạn không quen thuộc với loại cốt truyện này, thì đó chỉ là một biểu đồ chia đôi trong đó mặt phẳng xy được nối bởi một lưới các hình lục giác thông thường.

Vì vậy, từ một biểu đồ, bạn có thể chỉ cần đếm số điểm rơi trong mỗi hình lục giác, phân biệt vùng vẽ như một tập hợp các cửa sổ , gán từng điểm cho một trong các cửa sổ này; cuối cùng, ánh xạ các cửa sổ lên một mảng màu và bạn đã có một sơ đồ hexbin.

Mặc dù ít được sử dụng hơn ví dụ như hình tròn hoặc hình vuông, hình lục giác đó là lựa chọn tốt hơn cho hình dạng của thùng chứa thùng là trực quan:

  • hình lục giác có đối xứng lân cận gần nhất (ví dụ: các ô vuông không, ví dụ: khoảng cách từ một điểm trên đường viền của hình vuông đến một điểm bên trong hình vuông đó không phải là mọi nơi bằng nhau) và

  • hình lục giác là đa giác n cao nhất mang lại sự sắp xếp mặt phẳng thông thường (nghĩa là bạn có thể mô hình lại một cách an toàn sàn nhà bếp của mình bằng gạch hình lục giác vì bạn sẽ không có khoảng trống giữa các ô khi bạn hoàn thành - không đúng với tất cả cao hơn n, n> = 7, đa giác).

( Matplotlib sử dụng thuật ngữ hexbin , vì vậy (AFAIK) tất cả các thư viện âm mưu cho R ; tôi vẫn không biết liệu đây có phải là thuật ngữ được chấp nhận chung cho các lô loại này hay không, mặc dù tôi nghi ngờ rằng hexbin có ngắn không đối với việc tạo hình lục giác , được mô tả bước thiết yếu trong việc chuẩn bị dữ liệu để hiển thị.)


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()   

nhập mô tả hình ảnh ở đây


Điều đó có nghĩa là "hình lục giác có đối xứng lân cận gần nhất" là gì? Bạn nói rằng "khoảng cách từ một điểm trên đường viền của hình vuông và một điểm bên trong hình vuông đó không phải ở đâu cũng bằng nhau" mà là khoảng cách với cái gì?
Jaan

9
Đối với một hình lục giác, khoảng cách từ trung tâm đến một đỉnh nối hai bên cũng dài hơn từ giữa đến giữa một bên, chỉ có tỷ lệ nhỏ hơn (2 / sqrt (3) 1,15 cho hình lục giác so với sqrt (2) 1,41 cho hình vuông). Hình dạng duy nhất mà khoảng cách từ tâm đến mọi điểm trên đường viền bằng nhau là hình tròn.
Jaan

5
@Jaan Đối với một hình lục giác, mọi hàng xóm đều ở cùng một khoảng cách. Không có vấn đề với 8 khu phố hoặc 4 khu phố. Không có hàng xóm chéo, chỉ là một loại hàng xóm.
isarandi

@doug Làm thế nào để bạn chọn gridsize=tham số. Tôi muốn chọn nó như vậy, để các hình lục giác chỉ cần chạm mà không chồng chéo. Tôi nhận thấy rằng gridsize=100sẽ tạo ra các hình lục giác nhỏ hơn, nhưng làm thế nào để chọn giá trị phù hợp?
Alexander Cska

39

Chỉnh sửa: Để có xấp xỉ tốt hơn câu trả lời của Alejandro, xem bên dưới.

Tôi biết đây là một câu hỏi cũ, nhưng muốn thêm một cái gì đó vào anwser của Alejandro: Nếu bạn muốn có một hình ảnh được làm mịn đẹp mà không cần sử dụng py-sphviewer, bạn có thể sử dụng np.histogram2dvà áp dụng bộ lọc gaussian (từ scipy.ndimage.filters) vào bản đồ nhiệt:

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()

Sản xuất:

Hình ảnh đầu ra

Biểu đồ phân tán và s = ​​16 được vẽ trên đầu mỗi trang cho Agape Gal'lo (nhấp để xem tốt hơn):

Trên đầu mỗi


Một điểm khác biệt tôi nhận thấy với cách tiếp cận bộ lọc gaussian của tôi và phương pháp của Alejandro là phương pháp của ông cho thấy các cấu trúc cục bộ tốt hơn nhiều so với của tôi. Do đó, tôi đã thực hiện một phương pháp lân cận đơn giản gần nhất ở mức pixel. Phương pháp này tính toán cho mỗi pixel tổng cộng nghịch đảo khoảng cách của các nđiểm gần nhất trong dữ liệu. Phương pháp này có độ phân giải cao khá đắt tiền về mặt tính toán và tôi nghĩ rằng có một cách nhanh hơn, vì vậy hãy cho tôi biết nếu bạn có bất kỳ cải tiến nào.

Cập nhật: Như tôi nghi ngờ, có một phương pháp nhanh hơn nhiều bằng Scipy scipy.cKDTree. Xem câu trả lời của Gabriel để thực hiện.

Dù sao, đây là mã của tôi:

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()

Kết quả:

Làm mịn hàng xóm gần nhất


1
Thích cái này. Đồ thị đẹp như câu trả lời của Alejandro, nhưng không yêu cầu gói mới.
Nathan Clement

Rất đẹp ! Nhưng bạn tạo ra một sự bù đắp với phương pháp này. Bạn có thể thấy điều này bằng cách so sánh một biểu đồ phân tán bình thường với biểu đồ màu. Bạn có thể thêm một cái gì đó để sửa nó? Hay chỉ để di chuyển đồ thị theo giá trị x và y?
Agape Gal'lo

1
Agape Gal'lo, bạn có ý nghĩa gì với offset? Nếu bạn vẽ chúng trên đầu mỗi cái chúng khớp nhau (xem phần chỉnh sửa bài viết của tôi). Có lẽ bạn đã bỏ qua vì chiều rộng của phân tán không khớp chính xác với ba phần còn lại.
Phụng vụ

Cảm ơn rất nhiều vì đã vẽ đồ thị cho tôi! Tôi hiểu sai lầm của mình: Tôi đã sửa đổi "phạm vi" để xác định giới hạn x và y. Bây giờ tôi hiểu nó đã sửa đổi nguồn gốc của biểu đồ. Sau đó, tôi có một câu hỏi cuối cùng: làm thế nào tôi có thể mở rộng các giới hạn của biểu đồ, ngay cả đối với khu vực không có dữ liệu hiện có? Ví dụ: từ -5 đến +5 cho x và y.
Agape Gal'lo

1
Giả sử bạn muốn trục x đi từ -5 đến 5 và trục y từ -3 đến 4; trong myplothàm, thêm rangetham số vào np.histogram2d: np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])và trong vòng lặp for, đặt x và y lim của trục : ax.set_xlim([-5, 5]) ax.set_ylim([-3, 4]). Ngoài ra, theo mặc định, imshowgiữ tỷ lệ khung hình giống với tỷ lệ trục của bạn (vì vậy trong ví dụ của tôi tỷ lệ 10: 7), nhưng nếu bạn muốn nó khớp với cửa sổ cốt truyện của mình, hãy thêm tham số aspect='auto'vào imshow.
Phụng vụ

31

Thay vì sử dụng np.hist2d, nói chung tạo ra các biểu đồ khá xấu xí, tôi muốn tái chế py-sphviewer , một gói python để hiển thị mô phỏng hạt bằng cách sử dụng hạt nhân làm mịn thích ứng và có thể dễ dàng cài đặt từ pip (xem tài liệu trang web). Hãy xem xét đoạn mã sau, dựa trên ví dụ:

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()

tạo ra hình ảnh sau đây:

nhập mô tả hình ảnh ở đây

Như bạn thấy, hình ảnh trông khá đẹp và chúng tôi có thể xác định các cấu trúc khác nhau trên nó. Những hình ảnh này được xây dựng trải đều một trọng số cho trước cho mỗi điểm trong một miền nhất định, được xác định bởi độ dài làm mịn, lần lượt được cho bởi khoảng cách đến nb gần hơn hàng xóm (tôi đã chọn 16, 32 và 64 cho các ví dụ). Vì vậy, các khu vực mật độ cao hơn thường được trải rộng trên các khu vực nhỏ hơn so với các khu vực mật độ thấp hơn.

Hàm myplot chỉ là một hàm rất đơn giản mà tôi đã viết để cung cấp dữ liệu x, y cho py-sphviewer để thực hiện phép thuật.


2
Một nhận xét cho bất cứ ai đang cố gắng cài đặt py-sphviewer trên OSX: Tôi gặp khá nhiều khó khăn, xem: github.com/alejandrobll/py-sphviewer/issues/3
Sam Finnigan

Quá tệ, nó không hoạt động với python3. Nó cài đặt, nhưng sau đó gặp sự cố khi bạn cố gắng sử dụng nó ...
Fábio Dias

1
@Fabio Dias, Phiên bản mới nhất (1.1.x) hiện hoạt động với Python 3.
Alejandro

29

Nếu bạn đang sử dụng 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


17

Seaborn hiện có chức năng khớp nối nên hoạt động độc đáo ở đây:

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()

hình ảnh demo


Đơn giản, đẹp và phân tích hữu ích.
ryanjdillon

@wordsforthewise làm thế nào để bạn tạo một dữ liệu 600k có thể đọc được bằng cách sử dụng này? (cách thay đổi kích thước)
nrmb

Tôi không chắc ý của bạn là gì; có lẽ tốt nhất là bạn hỏi một câu hỏi riêng biệt và liên kết nó ở đây. Bạn có nghĩa là thay đổi kích thước toàn bộ con số? Đầu tiên tạo hình với fig = plt.figure(figsize=(12, 12)), sau đó lấy trục hiện tại với ax=plt.gca(), sau đó thêm đối số ax=axcho jointplothàm.
lời giới thiệu

@wordsforthewise bạn có thể vui lòng trả lời câu hỏi này không: stackoverflow.com/questions/50997662/ cảm ơn
ebrahimi

4

và câu hỏi ban đầu là ... làm thế nào để chuyển đổi giá trị phân tán thành giá trị lưới, phải không? histogram2dkhông tính tần số trên mỗi ô, tuy nhiên, nếu bạn có dữ liệu khác trên mỗi ô chứ không chỉ tần số, bạn cần một số công việc bổ sung để thực hiện.

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

Vì vậy, tôi có một bộ dữ liệu với kết quả Z cho tọa độ X và Y. Tuy nhiên, tôi đã tính toán một vài điểm bên ngoài khu vực quan tâm (khoảng trống lớn) và hàng đống điểm trong một khu vực nhỏ quan tâm.

Có ở đây nó trở nên khó khăn hơn nhưng cũng vui hơn. Một số thư viện (xin lỗi):

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

pyplot là công cụ đồ họa của tôi ngày hôm nay, cm là một loạt các bản đồ màu với một số lựa chọn không chính xác. numpy cho các tính toán và griddata để gắn các giá trị vào một lưới cố định.

Điều cuối cùng rất quan trọng đặc biệt là vì tần số của các điểm xy không được phân phối đều trong dữ liệu của tôi. Trước tiên, hãy bắt đầu với một số ranh giới phù hợp với dữ liệu của tôi và kích thước lưới tùy ý. Dữ liệu gốc có các điểm dữ liệu bên ngoài các ranh giới x và y đó.

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

Vì vậy, chúng tôi đã xác định lưới có 500 pixel giữa giá trị tối thiểu và tối đa của x và y.

Trong dữ liệu của tôi, có rất nhiều hơn 500 giá trị có sẵn trong lĩnh vực được quan tâm cao; trong khi ở khu vực lãi suất thấp, thậm chí không có 200 giá trị trong tổng lưới; giữa ranh giới đồ họa của x_minx_maxthậm chí còn ít hơn.

Vì vậy, để có được một bức ảnh đẹp, nhiệm vụ là lấy trung bình cho các giá trị lãi suất cao và lấp đầy các khoảng trống ở nơi khác.

Tôi xác định lưới của tôi bây giờ. Đối với mỗi cặp xx-yy, tôi muốn có một màu.

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

Tại sao hình dạng lạ? scipy.griddata muốn một hình dạng (n, D).

Griddata tính toán một giá trị cho mỗi điểm trong lưới, theo phương pháp được xác định trước. Tôi chọn "gần nhất" - các điểm lưới trống sẽ được điền với các giá trị từ hàng xóm gần nhất. Điều này trông giống như các khu vực có ít thông tin có các ô lớn hơn (ngay cả khi nó không phải là trường hợp). Người ta có thể chọn nội suy "tuyến tính", sau đó các khu vực có ít thông tin trông kém sắc nét. Vật chất của hương vị, thực sự.

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])

Và hy vọng, chúng tôi bàn giao cho matplotlib để hiển thị cốt truyện

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()

Xung quanh phần nhọn của V-Shape, bạn thấy tôi đã tính toán rất nhiều trong quá trình tìm kiếm điểm ngọt, trong khi những phần ít thú vị hơn hầu hết mọi nơi khác có độ phân giải thấp hơn.

Sơ đồ nhiệt của một SVC ở độ phân giải cao


Bạn có thể cải thiện câu trả lời của bạn để có mã hoàn chỉnh và có thể chạy được không? Đây là một phương pháp thú vị mà bạn đã cung cấp. Tôi đang cố gắng để hiểu rõ hơn vào lúc này. Tôi cũng không hiểu tại sao lại có hình chữ V. Cảm ơn.
ldmtwo

Hình chữ V xuất phát từ dữ liệu của tôi. Đó là giá trị F1 cho một SVM được đào tạo: Điều này sẽ đi đôi chút trong lý thuyết về SVM. Nếu bạn có điểm C cao, nó bao gồm tất cả các điểm của bạn trong phép tính, cho phép phạm vi gamma rộng hơn hoạt động. Gamma là độ cứng của đường cong phân tách tốt và xấu. Hai giá trị đó phải được trao cho SVM (X và Y trong đồ họa của tôi); sau đó bạn nhận được một kết quả (Z trong đồ họa của tôi). Trong khu vực tốt nhất bạn có thể hy vọng đến độ cao có ý nghĩa.
Andera

Thử thứ hai: Hình chữ V có trong dữ liệu của tôi. Đó là giá trị F1 cho một SVM: Nếu bạn có C cao, nó bao gồm tất cả các điểm của bạn trong phép tính, cho phép phạm vi gamma rộng hơn hoạt động, nhưng làm cho phép tính chậm. Gamma là độ cứng của đường cong phân tách tốt và xấu. Hai giá trị đó phải được trao cho SVM (X và Y trong đồ họa của tôi); sau đó bạn nhận được một kết quả (Z trong đồ họa của tôi). Trong khu vực được tối ưu hóa, bạn nhận được giá trị cao, nơi khác có giá trị thấp. Những gì tôi đã trình bày ở đây có thể sử dụng được nếu bạn có giá trị Z cho một số (X, Y) và nhiều khoảng trống ở nơi khác. Nếu bạn có dữ liệu (X, Y, Z), bạn có thể sử dụng mã của tôi.
Andera

4

Đây là cách tiếp cận hàng xóm gần nhất tuyệt vời của Jemony nhưng được thực hiện bằng scipy.cKDTree . Trong các thử nghiệm của tôi, nó nhanh hơn khoảng 100 lần.

nhập mô tả hình ảnh ở đây

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree


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


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

resolution = 250

extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])


def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
    """
    """
    # Create the tree
    tree = cKDTree(np.array([xv, yv]).T)
    # Find the closest nnmax-1 neighbors (first entry is the point itself)
    grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
    dists = tree.query(grid, neighbours)
    # Inverse of the sum of distances to each grid point.
    inv_sum_dists = 1. / dists[0].sum(1)

    # Reshape
    im = inv_sum_dists.reshape(resolution, resolution)
    return im


fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):

    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=5)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:

        im = kNN2DDens(xv, yv, resolution, neighbours)

        ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])

plt.savefig('new.png', dpi=150, bbox_inches='tight')

1
Tôi biết việc triển khai của mình rất kém hiệu quả nhưng không biết về cKDTree. Làm tốt! Tôi sẽ tham khảo bạn trong câu trả lời của tôi.
Ngày

2

Tạo một mảng 2 chiều tương ứng với các ô trong hình ảnh cuối cùng của bạn, được gọi là say heatmap_cellsvà khởi tạo nó dưới dạng tất cả các số 0.

Chọn hai hệ số tỷ lệ xác định sự khác biệt giữa từng thành phần mảng trong các đơn vị thực, cho từng thứ nguyên, nói x_scaley_scale. Chọn những cái này sao cho tất cả các điểm dữ liệu của bạn sẽ nằm trong giới hạn của mảng bản đồ nhiệt.

Đối với mỗi datapoint thô với x_valuey_value:

heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1


1

nhập mô tả hình ảnh ở đây

Đây là một điểm tôi đã thực hiện trên bộ 1 triệu điểm với 3 danh mục (màu Đỏ, Xanh lục và Xanh lam). Đây là một liên kết đến kho lưu trữ nếu bạn muốn thử chức năng. Github Repo

histplot(
    X,
    Y,
    labels,
    bins=2000,
    range=((-3,3),(-3,3)),
    normalize_each_label=True,
    colors = [
        [1,0,0],
        [0,1,0],
        [0,0,1]],
    gain=50)

0

Rất giống với câu trả lời của @ Piti , nhưng sử dụng 1 cuộc gọi thay vì 2 để tạo điểm:

import numpy as np
import matplotlib.pyplot as plt

pts = 1000000
mean = [0.0, 0.0]
cov = [[1.0,0.0],[0.0,1.0]]

x,y = np.random.multivariate_normal(mean, cov, pts).T
plt.hist2d(x, y, bins=50, cmap=plt.cm.jet)
plt.show()

Đầu ra:

2d_gaussian_heatmap


0

Tôi sợ tôi đến bữa tiệc muộn một chút nhưng tôi đã có một câu hỏi tương tự trước đây. Câu trả lời được chấp nhận (bởi @ptomato) đã giúp tôi nhưng tôi cũng muốn đăng nó trong trường hợp nó được sử dụng cho ai đó.


''' I wanted to create a heatmap resembling a football pitch which would show the different actions performed '''

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

#fixing random state for reproducibility
np.random.seed(1234324)

fig = plt.figure(12)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Ratio of the pitch with respect to UEFA standards 
hmap= np.full((6, 10), 0)
#print(hmap)

xlist = np.random.uniform(low=0.0, high=100.0, size=(20))
ylist = np.random.uniform(low=0.0, high =100.0, size =(20))

#UEFA Pitch Standards are 105m x 68m
xlist = (xlist/100)*10.5
ylist = (ylist/100)*6.5

ax1.scatter(xlist,ylist)

#int of the co-ordinates to populate the array
xlist_int = xlist.astype (int)
ylist_int = ylist.astype (int)

#print(xlist_int, ylist_int)

for i, j in zip(xlist_int, ylist_int):
    #this populates the array according to the x,y co-ordinate values it encounters 
    hmap[j][i]= hmap[j][i] + 1   

#Reversing the rows is necessary 
hmap = hmap[::-1]

#print(hmap)
im = ax2.imshow(hmap)

Đây là kết quả nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.