สร้าง heatmap ใน MatPlotLib โดยใช้ชุดข้อมูลกระจาย


187

ฉันมีชุดข้อมูล X, Y (ประมาณ 10k) ที่ง่ายต่อการพล็อตเป็นพล็อตกระจาย แต่ฉันต้องการที่จะแสดงเป็นแผนที่ความร้อน

ฉันดูตัวอย่างใน MatPlotLib และพวกเขาทั้งหมดเริ่มต้นด้วยค่าเซลล์ความร้อนเพื่อสร้างภาพ

มีวิธีการที่แปลงกลุ่ม x, y, แตกต่างกันทั้งหมดเป็นแผนที่ความร้อน (ที่โซนที่มีความถี่สูงกว่าของ x, y จะ "อุ่น")?


คำตอบ:


182

หากคุณไม่ต้องการรูปหกเหลี่ยมคุณสามารถใช้histogram2dฟังก์ชันของ 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()

สิ่งนี้ทำให้ heatmap 50x50 หากคุณต้องการพูด, 512x384 คุณสามารถใส่ในการเรียกร้องให้bins=(512, 384)histogram2d

ตัวอย่าง: ตัวอย่างแผนที่ความร้อนของ Matplotlib


1
ฉันไม่ได้หมายถึงเป็นคนงี่เง่า แต่จริง ๆ แล้วคุณมีผลลัพธ์นี้ไปยังไฟล์ PNG / PDF แทนที่จะแสดงเฉพาะในเซสชัน IPython แบบโต้ตอบได้อย่างไร ฉันพยายามที่จะได้รับสิ่งนี้เป็นaxesอินสแตนซ์ปกติบางประเภทที่ฉันสามารถเพิ่มชื่อ, ป้ายชื่อแกน ฯลฯ และจากนั้นทำตามปกติsavefig()เหมือนที่ฉันจะทำกับพล็อต matplotlib ทั่วไปอื่น ๆ
gotgenes

3
@gotgenes: ไม่plt.savefig('filename.png')ทำงานใช่ไหม หากคุณต้องการได้รับอินสแตนซ์ของแกนให้ใช้อินเทอร์เฟซเชิงวัตถุของ Matplotlib:fig = plt.figure() ax = fig.gca() ax.imshow(...) fig.savefig(...)
ptomato

1
แน่นอนขอบคุณ! ผมคิดว่าผมไม่เข้าใจว่าอยู่ในหมวดหมู่เดียวกันของฟังก์ชั่นเป็นimshow() scatter()ฉันไม่เข้าใจจริงๆว่าทำไมimshow()แปลงอาร์เรย์ 2d เป็นบล็อกสีที่เหมาะสมในขณะที่ฉันเข้าใจสิ่งที่scatter()ควรทำกับอาร์เรย์ดังกล่าว
gotgenes

14
คำเตือนเกี่ยวกับการใช้ imshow สำหรับการพล็อตฮิสโตแกรม 2d ของค่า x / y เช่นนี้: โดยค่าเริ่มต้น imshow พล็อตที่ต้นกำเนิดในมุมซ้ายบนและสลับภาพ สิ่งที่ฉันจะทำเพื่อให้ได้ทิศทางเดียวกันกับพล็อตกระจายคือplt.imshow(heatmap.T, extent=extent, origin = 'lower')
Jamie

7
สำหรับผู้ที่ต้องการทำแถบสีลอการิทึมดูคำถามนี้stackoverflow.com/questions/17201172/และเพียงทำfrom matplotlib.colors import LogNorm plt.imshow(heatmap, norm=LogNorm()) plt.colorbar()
tommy.carstensen

109

ในพจนานุกรมMatplotlibฉันคิดว่าคุณต้องการพล็อตhexbin

หากคุณไม่คุ้นเคยกับพล็อตประเภทนี้มันก็แค่ฮิสโทแกรมแบบ bivariateที่ xy-plane ถูก tessellated โดยกริดรูปหกเหลี่ยมปกติ

ดังนั้นจากฮิสโตแกรมคุณสามารถนับจำนวนคะแนนที่หล่นในแต่ละรูปหกเหลี่ยมแยกพื้นที่การพล็อตออกเป็นชุดของหน้าต่างกำหนดแต่ละจุดให้กับหนึ่งในหน้าต่างเหล่านี้ ในที่สุดแมปหน้าต่างลงในอาร์เรย์สีและคุณมีไดอะแกรม hexbin

แม้ว่าจะใช้น้อยกว่าเช่นวงกลมหรือสี่เหลี่ยม แต่รูปหกเหลี่ยมนั้นเป็นตัวเลือกที่ดีกว่าสำหรับรูปทรงเรขาคณิตของภาชนะบรรจุ binning นั้นใช้งานง่าย:

  • รูปหกเหลี่ยมมีความสมมาตร - เพื่อนบ้านที่ใกล้ที่สุด (เช่นช่องเก็บของรูปสี่เหลี่ยมจัตุรัสไม่เช่นระยะห่างจากจุดหนึ่งบนเส้นขอบของรูปสี่เหลี่ยมถึงจุดภายในสี่เหลี่ยมนั้นไม่เท่ากันทุกแห่ง) และ

  • hexagon เป็น n-polygon สูงสุดที่ให้เครื่องบินแบบเทสเซลเลชันปกติ (เช่นคุณสามารถสร้างแบบจำลองพื้นห้องครัวของคุณใหม่ได้อย่างปลอดภัยด้วยกระเบื้องรูปหกเหลี่ยมเพราะคุณจะไม่มีช่องว่างระหว่างกระเบื้องเมื่อคุณทำเสร็จ - ไม่เป็นความจริงสำหรับ high-n อื่น ๆ ทั้งหมด, n> = 7, รูปหลายเหลี่ยม)

( Matplotlibใช้พล็อตhexbinคำนั้นทำ (AFAIK) ไลบรารีการพล็อตทั้งหมดสำหรับRยังไม่ทราบว่านี่เป็นคำที่ยอมรับโดยทั่วไปสำหรับพล็อตประเภทนี้หรือไม่แม้ว่าฉันสงสัยว่ามันน่าจะเป็นเพราะhexbinนั้นสั้น สำหรับการทำหกเหลี่ยมซึ่งอธิบายขั้นตอนสำคัญในการเตรียมข้อมูลสำหรับการแสดงผล)


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

ป้อนคำอธิบายรูปภาพที่นี่


หมายความว่า "รูปหกเหลี่ยมมีความสมมาตรใกล้เคียง" คุณบอกว่า "ระยะทางจากจุดหนึ่งบนเส้นขอบของสแควร์และจุดภายในสแควร์นั้นไม่เท่ากันทุกที่" แต่ระยะทางถึงอะไร?
Jaan

9
สำหรับรูปหกเหลี่ยมระยะทางจากจุดกึ่งกลางถึงจุดสุดยอดที่รวมกันทั้งสองด้านนั้นยาวกว่าจากกึ่งกลางถึงด้านข้างด้วยเพียงอัตราส่วนที่เล็กกว่า (2 / sqrt (3) ≈ 1.15 สำหรับรูปหกเหลี่ยมกับ sqrt (2) ≈ 1.41 สำหรับตาราง) รูปร่างเดียวที่ระยะทางจากจุดศูนย์กลางไปยังจุดทุกจุดบนขอบเท่ากันคือวงกลม
Jaan

5
@Jan สำหรับรูปหกเหลี่ยมเพื่อนบ้านทุกคนอยู่ในระยะทางเดียวกัน ไม่มีปัญหากับ 8-Neighborhood หรือ 4-Neighborhood ไม่มีเพื่อนบ้านแนวทแยงเพียงแค่เพื่อนบ้านประเภทหนึ่ง
isarandi

@doug คุณเลือกgridsize=พารามิเตอร์ได้อย่างไร ฉันต้องการเลือกแบบนี้เพื่อให้รูปหกเหลี่ยมสัมผัสได้โดยไม่ทับซ้อนกัน ฉันสังเกตเห็นว่าgridsize=100จะผลิตรูปหกเหลี่ยมขนาดเล็กลง แต่จะเลือกค่าที่เหมาะสมได้อย่างไร
Alexander Cska

40

แก้ไข: เพื่อการประมาณที่ดีขึ้นของคำตอบของ Alejandro ดูด้านล่าง

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ต้องการเพิ่มบางสิ่งบางอย่างใน Anwser ของ Alejandro: หากคุณต้องการภาพที่ราบรื่นโดยไม่ใช้ py-sphviewer คุณสามารถใช้np.histogram2dและใช้ตัวกรอง gaussian (จากscipy.ndimage.filters) ลงใน heatmap แทน

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 = 16 พล็อตที่ด้านบนของ eachother สำหรับ Agape Gal'lo (คลิกเพื่อดูดีกว่า):

ด้านบนของ eachother


ข้อแตกต่างประการหนึ่งที่ฉันสังเกตเห็นด้วยวิธีตัวกรองแบบเกาส์เซียนและแนวทางของ Alejandro คือวิธีการของเขาแสดงให้เห็นโครงสร้างในท้องถิ่นดีกว่าของฉันมาก ดังนั้นฉันจึงใช้วิธีเพื่อนบ้านที่ใกล้เคียงที่สุดที่ระดับพิกเซล วิธีนี้จะคำนวณผลรวมผกผันของระยะทางของnจุดที่ใกล้ที่สุดในแต่ละพิกเซลสำหรับแต่ละพิกเซล วิธีนี้มีความละเอียดสูงค่อนข้างแพงและฉันคิดว่ามันมีวิธีที่เร็วกว่าดังนั้นแจ้งให้เราทราบหากคุณมีการปรับปรุงใด ๆ

ปรับปรุง: ขณะที่ผมสงสัยว่ามีวิธีได้เร็วขึ้นมากโดยใช้ scipy.cKDTreeSciPy ดูคำตอบของ Gabrielสำหรับการนำไปใช้

อย่างไรก็ตามนี่คือรหัสของฉัน:

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

ผลลัพธ์:

เพื่อนบ้านที่ใกล้ที่สุดปรับให้เรียบ


1
รักสิ่งนี้. กราฟนั้นดีเท่ากับคำตอบของ Alejandro แต่ไม่จำเป็นต้องมีแพ็คเกจใหม่
Nathan Clement

ดีมาก ! แต่คุณสร้างออฟเซ็ตด้วยวิธีนี้ คุณสามารถดูได้โดยการเปรียบเทียบกราฟกระจายปกติกับกราฟสี คุณสามารถเพิ่มบางสิ่งเพื่อแก้ไขได้ไหม? หรือเพียงแค่เลื่อนกราฟตามค่า x และ y
Agape Gal'lo

1
Agape Gal'lo คุณหมายถึงอะไรกับการชดเชย? หากคุณพล็อตพวกเขาที่ด้านบนของแต่ละคนพวกเขาจะจับคู่ (ดูแก้ไขโพสต์ของฉัน) บางทีคุณอาจถูกเลื่อนออกไปเนื่องจากความกว้างของการกระจายไม่ตรงกับอีกสามประการ
Jurgy

ขอบคุณมากสำหรับการวางแผนกราฟสำหรับฉัน! ฉันเข้าใจความผิดพลาดของฉัน: ฉันได้แก้ไข "ขอบเขต" เพื่อกำหนดขีด จำกัด x และ y ตอนนี้ฉันเข้าใจแล้วว่ามันแก้ไขจุดกำเนิดของกราฟ จากนั้นฉันมีคำถามสุดท้าย: ฉันจะขยายขีด จำกัด ของกราฟได้อย่างไรแม้ในพื้นที่ที่ไม่มีข้อมูลอยู่ ตัวอย่างเช่นระหว่าง -5 ถึง +5 สำหรับ x และ y
Agape Gal'lo

1
สมมติว่าคุณต้องการให้แกน x เลื่อนจาก -5 ถึง 5 และแกน y จาก -3 ถึง 4; ในmyplotฟังก์ชั่นเพิ่มrangeพารามิเตอร์np.histogram2d: np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])และสำหรับวงตั้ง x และ y ax.set_xlim([-5, 5]) ax.set_ylim([-3, 4])ที่ลิมของแกน: นอกจากนี้โดยค่าเริ่มต้นimshowช่วยให้อัตราส่วนเหมือนกันกับอัตราส่วนของแกนของคุณ (ดังนั้นในตัวอย่างของฉันอัตราส่วน 10: 7) แต่ถ้าคุณอยากให้มันตรงกับหน้าต่างพล็อตของคุณเพิ่มพารามิเตอร์เพื่อaspect='auto' imshow
Jurgy

31

แทนที่จะใช้ np.hist2d ซึ่งโดยทั่วไปสร้างฮิสโตแกรมค่อนข้างน่าเกลียดฉันต้องการรีไซเคิลpy-sphviewerซึ่งเป็นแพคเกจหลามสำหรับการจำลองอนุภาคโดยใช้เคอร์เนลที่ปรับให้เรียบและสามารถติดตั้งได้ง่ายจาก pip (ดูเอกสารประกอบหน้าเว็บ) พิจารณารหัสต่อไปนี้ซึ่งขึ้นอยู่กับตัวอย่าง:

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 เพื่อทำเวทย์มนตร์


2
ความคิดเห็นสำหรับทุกคนที่พยายามติดตั้ง py-sphviewer บน OSX: ฉันมีความยากลำบากมากดู: github.com/alejandrobll/py-sphviewer/issues/3
Sam Finnigan

น่าเสียดายที่มันไม่ทำงานกับ python3 จะติดตั้ง แต่แล้วก็เกิดปัญหาเมื่อคุณพยายามที่จะใช้มัน ...
Fábio Dias

1
@Fabio Dias เวอร์ชันล่าสุด (1.1.x) ทำงานร่วมกับ Python 3 ได้แล้ว
Alejandro


17

ตอนนี้ Seaborn มีฟังก์ชั่นข้อต่อซึ่งควรจะทำงานได้ดีที่นี่:

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

ภาพตัวอย่าง


เรียบง่ายสวยและมีประโยชน์ในเชิงวิเคราะห์
ryanjdillon

@words ต่อไปคุณจะสร้างข้อมูล 600k ที่อ่านได้โดยใช้วิธีนี้อย่างไร (วิธีปรับขนาด)
nrmb

ฉันไม่แน่ใจว่าคุณหมายถึงอะไร อาจเป็นการดีที่สุดที่คุณถามคำถามแยกต่างหากและเชื่อมโยงที่นี่ คุณหมายถึงการปรับขนาดรูปทั้งหมด? ก่อนอื่นให้สร้างรูปfig = plt.figure(figsize=(12, 12))จากนั้นรับแกนปัจจุบันด้วยax=plt.gca()จากนั้นเพิ่มอาร์กิวเมนต์ax=axลงในjointplotฟังก์ชัน
Wordsforthewise

@wordsforthewise โปรดช่วยตอบคำถามนี้: stackoverflow.com/questions/50997662/…ขอบคุณ
ebrahimi

4

และคำถามเริ่มต้นคือ ... จะแปลงค่าการกระจายเป็นค่ากริดได้อย่างไร 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

ดังนั้นฉันมีชุดข้อมูลที่มี Z-results สำหรับพิกัด X และ Y อย่างไรก็ตามฉันกำลังคำนวณจุดสองสามจุดนอกพื้นที่ที่น่าสนใจ (ช่องว่างขนาดใหญ่) และจำนวนจุดในพื้นที่เล็ก ๆ ที่น่าสนใจ

ใช่ที่นี่มันจะยากขึ้น แต่ก็สนุกขึ้น ห้องสมุดบางแห่ง (ขออภัย):

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

pyplot เป็นโปรแกรมกราฟิกของฉันวันนี้ cm เป็นแผนที่สีที่หลากหลายพร้อมตัวเลือกที่ไม่มี initeresting ต้องการการคำนวณและ griddata สำหรับแนบค่ากับกริดคงที่

อันสุดท้ายมีความสำคัญโดยเฉพาะอย่างยิ่งเพราะความถี่ของคะแนน xy นั้นไม่ได้กระจายกันในข้อมูลของฉัน ก่อนอื่นเรามาเริ่มกันด้วยขอบเขตที่เหมาะสมกับข้อมูลของฉันและขนาดกริดโดยพลการ ข้อมูลต้นฉบับมีดาต้าพอยน์นอกขอบเขต x และ y

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

ดังนั้นเราจึงกำหนดกริดด้วย 500 พิกเซลระหว่างค่าต่ำสุดและสูงสุดของ x และ y

ในข้อมูลของฉันมีค่ามากกว่า 500 ค่าในพื้นที่ที่มีความสนใจสูง ในขณะที่ในพื้นที่ที่มีดอกเบี้ยต่ำไม่มีแม้แต่ 200 ค่าในกริดทั้งหมด ระหว่างขอบเขตกราฟิกของx_minและx_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()

บริเวณรอบ ๆ รูปตัววีคุณจะเห็นว่าฉันทำการคำนวณจำนวนมากระหว่างการค้นหาจุดที่น่าสนใจในขณะที่ชิ้นส่วนที่น่าสนใจน้อยกว่าเกือบทุกที่อื่นจะมีความละเอียดที่ต่ำกว่า

Heatmap ของ SVC ด้วยความละเอียดสูง


คุณสามารถปรับปรุงคำตอบเพื่อให้ได้รหัสที่สมบูรณ์และ runnable ได้หรือไม่ นี่เป็นวิธีที่น่าสนใจที่คุณได้เตรียมไว้ ฉันพยายามที่จะเข้าใจในขณะนี้ ฉันไม่เข้าใจเลยว่าทำไมถึงมีรูปร่าง V เช่นกัน ขอบคุณ
ldmtwo

V-Shape นั้นมาจากข้อมูลของฉัน มันคือค่า f1 สำหรับ SVM ที่ผ่านการฝึกอบรม: นี่จะเป็นเพียงเล็กน้อยในทฤษฎีของ SVM หากคุณมีค่า C สูงมันจะรวมคะแนนทั้งหมดของคุณไว้ในการคำนวณเพื่อให้ช่วงแกมม่าที่กว้างขึ้นทำงานได้ แกมมาคือความแข็งของเส้นโค้งที่แยกความดีและไม่ดีออกจากกัน ค่าทั้งสองนั้นจะต้องมีให้กับ SVM (X และ Y ในกราฟิกของฉัน); จากนั้นคุณจะได้รับผลลัพธ์ (Z ในกราฟิกของฉัน) ในพื้นที่ที่ดีที่สุดคุณจะได้รับความสูงที่มีความหมาย
Anderas

ลองครั้งที่สอง: รูปตัว V อยู่ในข้อมูลของฉัน นี่คือค่า f1 สำหรับ SVM: หากคุณมี C สูงมันจะรวมคะแนนทั้งหมดของคุณไว้ในการคำนวณเพื่อให้ช่วงแกมม่าที่กว้างขึ้นทำงานได้ แต่ทำให้การคำนวณช้าลง แกมมาคือความแข็งของเส้นโค้งที่แยกความดีและไม่ดีออกจากกัน ค่าทั้งสองนั้นจะต้องมีให้กับ SVM (X และ Y ในกราฟิกของฉัน); จากนั้นคุณจะได้รับผลลัพธ์ (Z ในกราฟิกของฉัน) ในพื้นที่ที่ได้รับการปรับให้เหมาะสมคุณจะได้รับค่าสูงหรือต่ำกว่าที่อื่น สิ่งที่ฉันแสดงให้เห็นที่นี่ใช้งานได้ถ้าคุณมีค่า Z สำหรับบาง (X, Y) และช่องว่างมากมาย หากคุณมีดาต้าพอยท์ (X, Y, Z) คุณสามารถใช้รหัสของฉันได้
Anderas

4

นี่คือที่ดีที่ใกล้ที่สุดวิธีเพื่อนบ้าน Jurgy ของแต่ดำเนินการโดยใช้scipy.cKDTree ในการทดสอบของฉันมันเร็วกว่าประมาณ 100 เท่า

ป้อนคำอธิบายรูปภาพที่นี่

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
ฉันรู้ว่าการใช้งานของฉันไม่มีประสิทธิภาพ แต่ไม่รู้เกี่ยวกับ cKDTree ทำได้ดี! ฉันจะอ้างอิงคุณในคำตอบของฉัน
สวด

2

สร้างอาร์เรย์แบบสองมิติที่สอดคล้องกับเซลล์ในภาพสุดท้ายของคุณเรียกว่า say heatmap_cellsและยกตัวอย่างเป็นศูนย์ทั้งหมด

เลือกสองปัจจัยการปรับขนาดที่กำหนดความแตกต่างระหว่างแต่ละองค์ประกอบอาร์เรย์ในหน่วยจริงสำหรับแต่ละมิติพูดและx_scale y_scaleเลือกสิ่งเหล่านี้ที่ดาต้าพอยน์ทั้งหมดของคุณจะอยู่ภายในขอบเขตของแถวลำดับความร้อน

สำหรับแต่ละดาต้าพอยน์ดิบที่มีx_valueและy_value:

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


1

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือสิ่งที่ฉันทำบนจุด 1 ล้านที่มี 3 หมวดหมู่ (สีแดงเขียวและน้ำเงิน) นี่คือลิงค์ไปยังที่เก็บหากคุณต้องการลองใช้ฟังก์ชั่น 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

คล้ายกับคำตอบของ @ Pitiมาก แต่ใช้ 1 การโทรแทน 2 เพื่อสร้างคะแนน:

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

เอาท์พุท:

2d_gaussian_heatmap


0

ฉันเกรงว่าฉันจะไปงานปาร์ตี้ช้าไปหน่อย แต่ฉันก็มีคำถามที่คล้ายกันเมื่อไม่นานมานี้ คำตอบที่ได้รับการยอมรับ (โดย @ptomato) ช่วยฉันได้ แต่ฉันก็ต้องการโพสต์สิ่งนี้ในกรณีที่มันใช้กับใครบางคน


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

นี่คือผลลัพธ์ ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.