φυβλαςのβλογ
phyblas的博客



numpy & matplotlib เบื้องต้น บทที่ ๒๗: การแจกแจงความหนาแน่น
เขียนเมื่อ 2016/06/12 11:12
แก้ไขล่าสุด 2022/07/21 20:33
ในบทที่ ๑๓ ได้พูดถึงการสร้างฮิสโทแกรมไป ฮิสโทแกรมนั้นมีไว้สำหรับแสดงการแจกแจงความหนาแน่นของอะไรบางอย่างในหนึ่งมิติ

การแสดงการแจกแจงในหนึ่งมิติเราต้องสร้างแผนภาพเป็นสองมิติ ดังนั้นหากต้องการแจกแจงในสองมิติ ผลที่ได้ก็จะเป็นแผนภาพสามมิติ

แต่ในที่นี้เราจะแสดงมิติที่สามในรูปของสี นั่นคือจะสร้างแผนภาพไล่สีขึ้น



การสร้างแผนภาพไล่สีแสดงการแจกแจงความหนาแน่น
matplotlib มีคำสั่งสำหรับสร้างแผนภาพไล่สีแสดงการแจกแจงความหนาแน่น นั่นคือฟังก์ชัน hist2d

ตัวอย่างการใช้ ลองให้แสดงภาพการแจกแจงของตำแหน่งที่สุ่มขึ้นด้วยการแจกแจงแบบปกติ
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(1000000)-2
x[500000:] += 4 # ให้จุดจำนวนครึ่งหนึ่งมีตำแหน่งในแกน x เลื่อนห่างไป
y = np.random.randn(1000000)
plt.hist2d(x,y,bins=100,cmap='coolwarm')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()



คีย์เวิร์ด bins ก็คือจำนวนช่อง คล้ายกับในฮิสโทแกรมหนึ่งมิติ

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

ลองแก้เป็น
plt.hist2d(x,y,bins=[20,100],cmap='coolwarm')



แบบนี้แนวตั้งจะถูกแบ่งละเอียด แต่แนวนอนจะถูกแบ่งหยาบ

ถ้าให้แกนหนึ่งเป็น 1 ก็สามารถทำเป็นการแจกแจงในแกนเดียวได้
plt.hist2d(x,y,bins=[500,1],cmap='coolwarm')



หรือจะใช้เป็นลิสต์หรืออาเรย์ของค่าที่ต้องการจะแบ่ง เช่นลองใช้ np.linspace เพื่อสร้างลิสต์ของค่าจุดแบ่ง
plt.hist2d(x,y,bins=[np.linspace(-6,6,900),np.linspace(-4,4,200)],cmap='coolwarm')



ดังนั้นแบบนี้จะแบ่งช่องให้ไม่เท่ากันก็สามารถทำได้ เพียงแต่ว่าการแบ่งช่องไม่เท่ากันจะทำให้เราตีความความหนาแน่นผิดเพี้ยน เนื่องจากช่องที่ถูกแบ่งแคบจะมีค่าน้อย

ตัวอย่าง
plt.hist2d(x,y,bins=[np.linspace(-1.5,1.5,40)**3,np.linspace(-1.5,1.5,40)**3],cmap='coolwarm')



ค่าการแจกแจงที่เห็นอยู่นี้เป็นไปตามจำนวนที่อยู่ในแต่ละช่วงจริงๆ แต่หากต้องการให้คิดเป็นสัดส่วนก็เพิ่มคีย์เวิร์ด normed=1 (หรือ normed=True) ลงไป ค่าที่ปรากฏในแถบสีจะเป็นค่าที่หารด้วยจำนวนทั้งหมดแล้ว

ตัวอย่าง ลองแก้เป็น
plt.hist2d(x,y,bins=100,normed=1,cmap='coolwarm')



นอกจากนี้ส่วนใหญ่คีย์เวิร์ดที่ใช้ได้ก็จะเหมือนกับกราฟแจกแจงทั่วไป

จะทำเป็นกราฟล็อการิธึมก็ได้โดยใส่คีย์เวิร์ด norm
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
x = np.random.randn(1000000)-2
x[500000:] += 4
y = np.random.randn(1000000)
plt.hist2d(x,y,bins=100,norm=mpl.colors.LogNorm())
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()



ที่เห็นส่วนที่เป็นสีขาวนั่นคือมีค่าการแจกแจงเป็น 0 ซึ่งไม่สามารถหาค่าลอการิธึมได้

อนึ่ง norm กับ normed เป็นคีย์เวิร์ดคนละตัวกัน ต้องระวังอย่าสับสน



การแจกแจงเป็นช่องหกเหลี่ยม
นอกจากจะให้แจกแจงเป็นจุดๆช่องสี่เหลี่ยมธรรมดาแล้ว หากต้องการแบ่งเป็นช่องหกเหลี่ยมก็สามารถทำได้ matplotlib มีฟังก์ชัน plt.hexbin เพื่อใช้ในการนี้

ตัวอย่าง
x = np.random.randn(1000000)-2
x[500000:] += 4
y = np.random.randn(1000000)
plt.hexbin(x,y,gridsize=20,cmap='coolwarm')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1,0.95)
plt.show()



จำนวนเส้นที่แบ่งกำหนดโดยคีย์เวิร์ด gridsize จะให้สองแกนแบ่งไม่เท่ากันก็ทำได้ด้วยการใส่เป็นคู่อันดับเช่นกัน
plt.hexbin(x,y,gridsize=[5,30],cmap='coolwarm')



ขอบเขตของการแสดงผลการกระจายสามารถกำหนดด้วยคีย์เวิร์ด extent
plt.hexbin(x,y,gridsize=[20,30],extent=[-10,10,-5,5],cmap='coolwarm')





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

หากเราเอาตัวแปรมารับฟังก์ชัน hist2d จะพบว่าได้ค่าคืนกลับมาเป็นทูเพิลที่มีสมาชิกอยู่ ๔ ตัว ซึ่งก็คือ
- ค่าแสดงความหนาแน่นของแต่ละจุด อยู่ในรูปอาเรย์สองมิติ
- อาเรย์รวมค่าจุดขีดแบ่งในแกน x
- อาเรย์รวมค่าจุดขีดแบ่งในแกน y
- ออบเจ็กต์ของตัวฮิสโทแกรม

ตัวอย่าง
x = np.random.randn(1000000)-2
x[500000:] += 4
y = np.random.randn(1000000)
h = plt.hist2d(x,y,bins=100,cmap='hsv')
plt.colorbar()
plt.show()
print(h[0].shape) # ได้ (100, 100)
print('%.3f,%.3f'%(h[0].min(),h[0].max())) # ได้ 0.000,1061.000
print(h[0].sum()) # ได้ 1000000.0
print(h[1].shape) # ได้ (101,)
print('%.3f,%.3f'%(h[1].min(),h[1].max())) # ได้ -6.549,6.384
print(h[2].shape) # ได้ (101,)
print('%.3f,%.3f'%(h[2].min(),h[2].max())) # ได้ -4.882,4.894
print(h[3]) # ได้ AxesImage(80,52.8;396.8x369.6)



เราสามารถเอาข้อมูลที่ได้จากตรงนี้มาลองวาดเป็นกราฟแสดงค่าการแจกแจงต่ออีกทีได้
x = (h[1][1:]+h[1][:-1])/2
y = (h[2][1:]+h[2][:-1])/2
zx = h[0].sum(axis=1)
zy = h[0].sum(axis=0)
plt.subplot(2,1,1)
plt.plot(x,zx)
plt.subplot(2,1,2)
plt.plot(y,zy)
plt.show()





การใช้ histogram2d ของ numpy
จะเห็นว่า plt.hist2d ทำให้เราได้ค่าความหนาแน่นการกระจายออกมาได้ แต่หากเราแค่ต้องการค่าความหนาแน่นโดยที่ไม่ต้องมาวาดกราฟแล้วละก็ ใน numpy เองก็มีคำสั่งที่ใช้ทำได้อยู่แล้ว นั่นคือ np.histogram2d

การใช้ np.histogram2d นั้นจะคล้ายกับ plt.hist2d เพียงแต่ np.histogram2d จะได้แค่ค่าคืนกลับแต่ไม่ได้วาดกราฟออกมา และค่าคืนกลับที่ได้ก็จะมีแค่ ๓ ตัว ซึ่งก็คือสามตัวแรกของ np.histogram2d

ตัวอย่าง ลองใช้ np.histogram2d กับ plt.hist2d เทียบกัน
x = np.random.randn(1000000)-2
x[500000:] += 4
y = np.random.randn(1000000)
hisa = np.histogram2d(x,y,bins=[150,100])
his = plt.hist2d(x,y,bins=[150,100])
print(np.all(hisa[0]==his[0])) # ได้ True
print(np.all(hisa[1]==his[1])) # ได้ True
print(np.all(hisa[2]==his[2])) # ได้ True

ผลที่ได้จาก np.histogram2d ลองเอาไปใช้กับ plt.pcolor ก็จะได้ผลเป็นภาพที่เหมือนกับใช้ plt.hist2d แต่แรก
hx,hy = np.meshgrid(hisa[1],hisa[2])
hz = hisa[0].T
plt.figure()
plt.axes(xlim=[-6,6],ylim=[-4,4])
plt.pcolor(hx,hy,hz,cmap='Spectral')
plt.colorbar(pad=0.01)
plt.subplots_adjust(0.05,0.05,1.05,0.95)
plt.show()



นอกจากนี้แล้วก็ยังมีฟังก์ชัน np.histogram สำหรับสร้างค่าเพื่อใช้ทำฮิสโทแกรมหนึ่งมิติ กับ np.histogramdd ที่ใช้เตรียมฮิสโทแกรมกี่มิติก็ได้



อ้างอิง



<< บทที่แล้ว     บทถัดไป >>
หน้าสารบัญ


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> matplotlib
-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> numpy

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ