φυβλαςのβλογ
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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

月別記事

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2019年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

もっと前の記事

ไทย

日本語

中文