φυβλαςのβλογ
บล็อกของ phyblas



numpy & matplotlib เบื้องต้น บทที่ ๒: การใช้อาเรย์เบื้องต้น
เขียนเมื่อ 2016/06/11 11:13
แก้ไขล่าสุด 2021/09/28 16:42
numpy เป็นมอดูลที่ทำให้เราสามารถใช้ออบเจ็กต์ชนิดที่เรียกว่า ndarray ซึ่งหมายถึงอาเรย์หลายมิติ บางครั้งก็เรียกว่าอาเรย์เฉยๆ

คำว่า "อาเรย์" นั้นเป็นคำที่ถูกใช้ในภาษาอื่นๆอีกหลายภาษา เช่น ภาษาซี, php, จาวาสคริปต์, รูบี เป็นต้น แต่ว่าสำหรับในภาษาไพธอนสิ่งที่มีคุณสมบัติเทียบเท่ากับอาเรย์ในภาษาอื่น นั้นกลับเรียกว่าลิสต์ ส่วนอาเรย์จะหมายถึง ndarray ของ numpy

ในมอดูลมาตรฐานของภาษาไพธอนก็มีสิ่งที่เรียกว่าอาเรย์อยู่ แต่ก็ไม่เป็นที่นิยมใช้ ดังนั้นพอพูดถึงอาเรย์ในภาษาไพธอนแล้วจึงมักหมายถึง ndarray ของ numpy นั่นเอง

ก่อนที่จะเริ่มใช้งานสิ่งที่ต้องทำเป็นอย่างแรกก็คือทำการ import เรียกใช้ขึ้นมาก่อน
import numpy as np

ตัวย่อ np นี้จะใช้แบบนี้ไปตลอดในบทความทุกบท เพราะค่อนข้างเป็นสากล แม้แต่เวลาที่เรียกชื่อฟังก์ชันต่างๆใน numpy ก็จะเรียกโดยขึ้นต้นด้วย np.



การสร้างอาเรย์ขึ้นจากลิสต์
มีอยู่หลายวิธีในการสร้างอาเรย์ แต่วิธีที่พื้นฐานที่สุดคือสร้างขึ้นมาจากลิสต์, ทูเพิล หรือเรนจ์ โดยใช้ np.array(ลิสต์)
aray = np.array(range(3,7))
araya = np.array([[1,2],[3,4]])
print(aray)
print(araya)

ได้
[3 4 5 6]
[[1 2]
 [3 4]]

เท่านี้ก็จะได้อาเรย์ขึ้นมาตามที่ต้องการ ถ้าดูเผินๆจะเห็นว่าไม่ต่างอะไรจากลิสต์นัก แต่ความจริงแล้วต่างไปพอสมควร

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

อย่างต่อมาคืออาเรย์มีแอตทริบิวต์ติดตัวที่สามารถให้ข้อมูลของตัวอาเรย์นั้น เช่น
shape รูปร่างของอาเรย์
size จำนวนสมาชิกในอาเรย์
ndim จำนวนมิติของอาเรย์

ลองเอาอาเรย์ ๒ ตัวจากตัวอย่างเมื่อครู่มาหาแอตทริบิวต์
print(aray.shape) # ได้ (4,)
print(aray.size) # ได้ 4
print(aray.ndim) # ได้ 1
print(araya.shape) # ได้ (2, 2)
print(araya.size) # ได้ 4
print(araya.ndim) # ได้ 2

นอกจากนี้ยังสามารถใช้ฟังก์ชันที่ชื่อเหมือนกับแอตทริบิวต์เหล่านี้ในการหาค่าได้ด้วย ผลที่ได้จะเหมือนกัน
print(np.size(araya))
print(np.shape(araya))
print(np.ndim(araya))

จะเห็นว่ากรณีที่ลิสต์ที่ใช้นั้นมีการซ้อนกันก็จะได้เป็นอาเรย์ ๒ มิติ โดยมีแนวตั้งเป็นมิติที่หนึ่ง แนวนอนเป็นมิติที่สอง

และยังสามารถซ้อนกันเป็นมิติที่สูงขึ้นไปอีกได้ เช่นลองสร้าง ๓ มิติ
araye = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
print(araye)
print(araye.shape)
print(araye.size)
print(araye.ndim)

ได้
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
(2, 2, 2)
8
3

โดยมิติที่สามนั้นหากนำมาวาดเป็นรูปแล้วละก็อาจแสดงได้ในรูปของแถวในแนวลึกที่เพิ่มเข้ามา



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

เนื้อหาส่วนใหญ่ในบทต้นๆจะเน้นหนึ่งถึงสองมิติเป็นหลัก และสำหรับสามมิติจะเริ่มเน้นในบทที่ ๒๓



มีข้อควรระวังคือลิสต์ที่จะใช้สร้างอาเรย์จะต้องมีจำนวนสมาชิกในลิสต์ย่อยแต่ละลิสต์เท่ากันไม่เช่นนั้นจะถูกตีความเป็นออบเจ็กต์ทั่วไป
arayu = np.array([[1,2],[3,4,5]])
print(arayu.shape) # ได้ (2,)
print(arayu.size) # ได้ 2
print(arayu.ndim) # ได้ 1

จะเห็นว่าผลที่ได้คือมันกลายเป็นอาเรย์มิติเดียวซึ่งมีขนาดเป็น 2 นั่นเพราะ [1,2] และ [3,4,5] ถูกตีความเป็นออบเจ็กต์อย่างละชิ้น แทนทีจะคิดเป็นตัวๆแยกกัน



ชนิดของข้อมูลในอาเรย์
สามารถตรวจสอบชนิดของข้อมูลในอาเรย์ได้โดยดูที่แอตทริบิวต์ชื่อ dtype

เช่นลองใช้อาเรย์ที่สร้างในตัวอย่างก่อน
araye = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
arayu = np.array([[1,2],[3,4,5]])
print(araye.dtype) # ได้ int64
print(arayu.dtype) # ได้ object

จะเห็นว่า arayu ซึ่งสร้างขึ้นมาจากลิสต์ที่มีจำนวนสมาชิกไม่เท่ากันนั้นได้ข้อมูลประเภท object แทนที่จะเป็น int อย่างที่ควรเป็น

ส่วน araye นั้นกลายเป็นชนิด int ตามที่ควรจะเป็น โดยเลข 64 ใน int64 นี้บอกถึงขนาดของหน่วยความจำเป็นบิตที่ใช้ในการเก็บตัวเลข ปกติแล้วในภาษาไพธอนจำนวนเต็มจะไม่ได้แบ่งชนิดย่อย แต่ในบางภาษาเช่นภาษาซีจำนวนเต็มจะถูกแบ่งเป็นชนิดตามขนาดของหน่วยความจำที่ ใช้

ปกติแล้วถ้าไม่ได้ระบุอะไรข้อมูลจำนวนเต็มจะถูกตั้งให้เป็น int64 ซึ่งเป็นขนาดใหญ่สุด นอกจาก int64 แล้วก็ยังมี int8 int16 int32 ซึ่งจะกินพื้นที่น้อยกว่า และ float เองก็มีแบ่งเช่นกัน

ชนิดของข้อมูลสามารถกำหนดได้ตอนที่สร้างอาเรย์ขึ้นมา โดยเพิ่มคีย์เวิร์ด dtype เข้าไป
ari = np.array([1,2,3,4],dtype='int16')
ariy = np.array([1,2,3,4],dtype='float32')
print(ariy) # ได้ [ 1.  2.  3.  4.]

ถ้าตอนสร้างมีสมาชิกที่มีทศนิยมแม้แต่ตัวเดียวทั้งหมดก็จะกลายเป็น float64 ทันที
arey = np.array([1,2,3.14,4])
print(arey) # ได้ [ 1.    2.    3.14  4.  ]
print(arey.dtype) # ได้ float64

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

กรณีที่มีสายอักขระปนอยู่ตัวอื่นก็จะถูกเปลี่ยนเป็นสายอักขระไปด้วย เช่น
arayo = np.array([[1,2],[3.,'4']])
print(arayo)
print(arayo.dtype)

ได้
[['1' '2']
 ['3.0' '4']]
 <U32
 
U ในที่นี้หมายถึงเป็นยูนิโค้ด และ 32 เป็นจำนวนหน่วยความจำที่ใช้ โดยปกติจะเท่ากับจำนวนตัวอักษรแต่ถ้าสั้นกว่า 32 จะถูกกำหนดให้เป็น 32

ใน ภาษาซีเวลาที่ประกาศตัวแปรชนิดสายอักขระจะต้องกำหนดความยาวไว้ตายตัว ดังนั้นอาเรย์ซึ่งตั้งอยู่บนพื้นฐานของภาษาซีจึงมีลักษณะการจัดเก็บข้อมูลใน ลักษณะนี้ไปด้วย

อนึ่ง
ความยาวของสายอักขระสามารถกำหนดขึ้นเองได้ และถ้ากำหนดความยาวต่ำกว่าจำนวนตัวอักษรก็จะถูกตัดทอนหายไป
print(np.array([[123456789]],dtype='<U5')) # ได้ [['12345']]

นี่เป็นเนื้อหาที่เกี่ยวเนื่องมาจากภาษาซี จะไม่เน้นมาก ณ ที่นี้เพราะงานหลักของอาเรย์ที่จะใช้คือใช้กับตัวเลขเพื่อคำนวณ

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

ชนิดของอาเรย์ทั้งหมดสามารถดูได้ที่แอตทริบิวต์ np.sctypes
print(np.sctypes)

ผลลัพธ์
{'int': [<class 'numpy.int8'>, <class 'numpy.int16'>, , <class 'numpy.int64'>], 'uint': [, <class 'numpy.uint16'>, , <class 'numpy.uint64'>], 'others': [, <class 'object'>, <class 'str'>, , <class 'numpy.void'>], 'float': [, <class 'numpy.float32'>, , <class 'numpy.float128'>], 'complex': [<class 'numpy.complex64'>, <class 'numpy.complex128'>, <class 'numpy.complex256'>]}

ชนิดของสมาชิกในอาเรย์สามารถเปลี่ยนได้ด้วยเมธอด astype บนตัวอาเรย์
x = np.array([3.5,4.7,9,11.3,15])
print(x) # ได้ [  3.5   4.7   9.   11.3  15. ]
print(x.astype(int)) # ได้ [ 3  4  9 11 15]
print(x.astype(str)) # ได้ ['3.5' '4.7' '9.0' '11.3' '15.0']



การอ้างอิงถึงข้อมูลในอาเรย์
เช่น เดียวกับลิสต์ อาเรย์ก็ใช้การเติมวงเล็บเหลี่ยม [ ] เพื่ออ้างอิงข้อมูล โดยเลขในกรณีสองมิตินั้น ตัวแรกคือดัชนีของแนวตั้ง (เลขแถว) และตัวหลังคือแนวนอน (เลขหลัก)
ariyu = np.array([[1,2,3],[4,5,6]])
print(ariyu[0][1]) # ได้ 2
print(ariyu[1][2]) # ได้ 6

แต่นอกจากนั้นแล้วยังสามารถเขียนโดยใช้เป็นคู่อันดับโดยมีจุลภาค , คั่นในวงเล็บเหลี่ยมตัวเดียวแทนการใส่วงเล็บเหลี่ยมสองอันได้ด้วย ซึ่งแบบนี้ลิสต์ไม่สามารถทำได้
print(ariyu[0,2]) # ได้ 3
print(ariyu[1,1]) # ได้ 5

การเข้าถึงสมาชิกทีละหลายตัวก็ทำได้ด้วยการใช้โคลอน : เช่นเดียวกับลิสต์ แต่สำหรันอาเรย์สองมิติแทนที่จะใช้วงเล็บเหลี่ยมวางต่อกันสองอันสามารถใช้จุลภาคแทนได้เช่นกัน
print(ariyu[1][:]) # ได้ [4 5 6]
print(ariyu[1,:]) # ได้ [4 5 6]



ซึ่งการที่ใช้จุลภาคแทนได้นั้นมีข้อดีคือเข้าถึงสมาชิกที่อยู่ในหลัก (แนวตั้ง) เดียวกันแต่คนละแถว (แนวนอน) โดยการใส่ : ไว้ทางซ้าย
print(ariyu[:,1]) # ได้ [2 5]



ซึ่งจะเห็นได้ว่าการใช้วงเล็บเหลี่ยมคู่ [ ][ ] จะวาง [:] ไว้ซ้ายหรือขวาก็ให้ผลไม่ต่างจากเดิม คือให้สมาชิกที่อยู่ในแถวแนวนอนแถวเดียวกันเท่านั้น
print(ariyu[:][1]) # ได้ [4 5 6]]

จะเห็นว่า [1,:] กับ [1][:] และ [:][1] ให้ผลเหมือนกัน แต่ [:,1] เท่านั้นที่จะให้ผลต่าง

ถ้าลองสร้างลิสต์แบบเดียวกันมาโดยไม่แปลงเป็นอาเรย์จะพบว่าไม่สามารถทำในสิ่งเดียวกันได้
liyu = [[1,2,3],[4,5,6]]
print(liyu[:][1]) # ได้ [4 5 6]
print(liyu[:,1]) # ได้ TypeError: list indices must be integers or slices, not tuple

สรุปเป็นตารางเพื่อให้เห็นภาพชัด สมมุติว่าอาเรย์มี n แถว m หลัก
แถว/หลัก 0 1 2 3 .. m-1
0 [0,0] [0,1] [0,2] [0,3] [0,..] [0,m-1]
1 [1,0] [1,1] [1,2] [1,3] [1,..] [1,m-1]
2 [2,0] [2,1] [2,2] [2,3] [2,..] [2,m-1]
3 [3,0] [3,1] [3,2] [3,3] [3,..] [3,m-1]
.. [..,0] [..,1] [..,2] [..,3] [..,..] [..,m-1]
n-1 [n-1,0] [n-1,1] [n-1,2] [n-1,3] [n-1,..] [n-1,m-1]

สำหรับสามมิติซึ่งมีขนาด 3,3,3 อาจเขียนได้ดังนี้



การวางตัวเลขไว้หน้าและหลัง : เพื่อคัดเลือกอาเรย์เฉพาะในช่วงที่ต้องการก็ทำได้เช่นเดียวกับลิสต์

ตัวอย่างกรณีหนึ่งมิติ
 

aroi = np.array([13,14,15,16,17,18,19])

print(aroi[:3]) # ได้ [13 14 15]

print(aroi[3:5]) # ได้ [16 17]

print(aroi[5:]) # ได้ [18 19]


และเลขติดลบก็แสดงถึงสมาชิกที่ไล่จากท้าย โดย -1 คือสมาชิกตัวท้ายสุด
print(aroi[-1]) # ได้ 19

print(aroi[-3:-1]) # ได้ [17 18]

print(aroi[5:-1]) # ได้ [18]


หากมี : เพิ่มมาอีกตัวแล้ววางตัวเลขไว้ทางขวา : อีกจะเป็นการกำหนดระยะเว้นช่วง เช่นจะให้เว้นทีละสองก็ใส่ ::2 โดยตัวเลข ๒ ตัวแรกที่อยู่หน้า : อาจไม่ต้องใส่เลยก็ได้ และหากใส่เลขติดลบก็จะกลายเป็นการไล่ถอยหลังได้
 

print(aroi[1:4:2]) # ได้ [14 16]

print(aroi[1::2]) # ได้ [14 16 18]

print(aroi[:6:2]) # ได้ [13 15 17]

print(aroi[::2]) # ได้ [13 15 17 19]

print(aroi[::-1]) # ได้ [19 18 17 16 15 14 13]


จะเห็นว่าหากแค่ต้องการกลับลำดับสมาชิกในอาเรย์ทั้งหมดก็แค่ใส่ [::-1] ไปเท่านั้น เป็นการใช้ที่สะดวกมาก

กรณีสองมิติก็ใช้หลักการเดียวกัน ลองใช้กันดูได้

ตัวอย่าง
 

aroy = np.array([[13,14,15,16],

[17,18,19,20],

[21,22,23,24]])

print(aroy[1:2,2:3]) # ได้ [[19]]

print(aroy[0:2,1:3])# ได้

# [[14 15]
# [18 19]]

print(aroy[0,1:3]) # ได้ [14 15]

print(aroy[::2,2]) # ได้ [15 23]

print(aroy[::-1,::-1]) # ได้

# [[24 23 22 21]
# [20 19 18 17]
# [16 15 14 13]]




การเขียนทับข้อมูลในอาเรย์
เช่นเดียวกับลิสต์ อาเรย์ก็สามารถเขียนทับแก้ข้อมูลข้างในเมื่อไหร่ก็ได้ด้วยการใส่ค่าทับลงไป
aruy = np.array([[2,2,2],[2,2,2],[2,2,2]])
print(aruy)
aruy[1,1] = 3
print(aruy)

ได้
[[2 2 2]
 [2 2 2]
 [2 2 2]]
[[2 2 2]
 [2 3 2]
 [2 2 2]]

แต่ที่สะดวกกว่านั้นก็คือหากอยากแก้ค่าของหลายตัวในแถวหรือหลักเดียวกันทีเดียวก็สามารถทำได้
aruy[1,:] = 4
print(aruy)
aruy[:,2] = 5
print(aruy)
aruy[:,:] = 6
print(aruy)

ได้
[[2 2 2]
 [4 4 4]
 [2 2 2]]
[[2 2 5]
 [4 4 5]
 [2 2 5]]
[[6 6 6]
 [6 6 6]
 [6 6 6]]
 




จะเห็นว่าถ้าเขียน [:,:] จะเป็นการอ้างถึงข้อมูลทั้งหมด และทุกตัวจะถูกเปลี่ยนให้มีค่าเท่ากันหมด
 
ลักษณะนี้เรียกว่าเป็นการกระจายค่า (broadcast) คือสามารถใช้เลขตัวเดียวมาแทนค่าเพื่อยัดใส่แทนสมาชิกหลายตัวในอาเรย์ได้ในทีเดียว

ที่น่าสนใจกว่านั้นหน่อยคือการกระจายค่าไม่ได้จำกัดอยู่แค่ตัวเลขเดี่ยว แต่ยังใช้กับอาเรย์ที่มีจำนวนมิติน้อยกว่าได้ด้วย เช่น
aruy[:,:] = np.array([7,8,9]) # หรือจะใช้ในรูปลิสต์ aruy[:,:] = [7,8,9] ก็ได้
print(aruy)

ได้
[[7 8 9]
 [7 8 9]
 [7 8 9]]



จะเห็นว่าค่า 7 8 9 ถูกกระจายเข้าไปในแต่ละแถวเหมือนกันหมด

แต่ขนาดของอาเรย์ที่จะมาแทนต้องเท่ากัน ไม่เช่นนั้นจะเกิดข้อผิดพลาด
aruy[:,:] = [7,8] # ได้ ValueError: could not broadcast input array from shape (2) into shape (3,3)

ในการกระจายนั้นจะกระจายตามแนวนอน ดังนั้นต่อให้มีจำนวนแถวแนวตั้งเท่ากับขนาดของอาเรย์ที่มาแทนก็ไม่ได้อยู่ดี
aruyo = np.array([[2,2,2],[2,2,2]])
aruyo[:,:] = [4,5] # ได้ ValueError: could not broadcast input array from shape (2) into shape (2,3)

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

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



การสร้างอาเรย์ด้วยฟังก์ชัน
นอกจากจะสร้างจากลิสต์แล้วอาเรย์ก็ยังสร้างจากฟังก์ชันต่างๆที่มีอยู่ในมอดูล numpy เองได้

ในที่นี้ขอแนะนำฟังก์ชันที่ใช้บ่อย ได้แก่
np.arange สร้างอาเรย์หนึ่งมิติที่มีเลขเรียงกัน
np.linspace สร้างอาเรย์หนึ่งมิติตามจำนวนที่กำหนดโดยเว้นช่วงเท่าๆกัน
np.ones สร้างอาเรย์ที่มีแต่เลข 1 ตามขนาดที่กำหนด
np.zeros สร้างอาเรย์ที่มีแต่เลข 0 ตามขนาดที่กำหนด
np.full สร้างอาเรย์ที่มีแต่เลขอะไรก็ได้เลขเดียวตามที่กำหนด โดยมีขนาดตามที่กำหนด
np.empty สร้างอาเรย์เปล่าๆ ตามขนาดที่กำหนด
np.identity สร้างอาเรย์ที่เป็นเมทริกซ์เอกลักษณ์ (เมทริกซ์สองมิติที่มีค่าเป็น 1 เมื่อพิกัดแนวตั้งและนอนเท่ากัน นอกนั้นเป็น 0)
np.eye เหมือนกับ np.identity แต่ขนาดแนวตั้งและนอนไม่ต้องเท่ากันก็ได้


ในการสร้างอาเรย์ที่เป็นตัวเลขเรียงกันใช้ np.arange หรือ np.linspace
print(np.arange(10))
print(np.arange(1.5,8,2)) # อาร์กิวเมนต์ที่ใช้เหมือนกับ range แต่ไม่จำเป็นต้องเป็นจำนวนจริง
print(np.linspace(4, 7, 6)) # (จุดเริ่ม, จุดปลาย, จำนวน)

ผลลัพธ์
[0 1 2 3 4 5 6 7 8 9]
[ 1.5  3.5  5.5  7.5]
[ 4.   4.6  5.2  5.8  6.4  7. ]

np.linspace ถ้าใส่คีย์เวิร์ด endpoint=0 ไปจะหมายความว่าไม่รวมเลขจุดปลายด้วย และผลที่ได้จะต่างไปจากเดิมเลย
print(np.linspace(1.,4.,6)) # ได้ [ 1.   1.6  2.2  2.8  3.4  4. ]
print(np.linspace(1.,4.,6,endpoint=0)) # ได้ [ 1.   1.5  2.   2.5  3.   3.5]

จะเห็นว่ากรณีที่รวมจุดปลายจะได้ว่า ระยะช่วง = (จุดเริ่ม-จุดสิ้นสุด)/(จำนวน-1)

แต่ถ้าไม่รวมจุดปลายด้วยจะได้ว่า ระยะช่วง = (จุดเริ่ม-จุดสิ้นสุด)/จำนวน

ทั้ง np.arange และ np.linspace ถูกใช้บ่อยๆเวลาวาดกราฟ จึงมีความสำคัญมาก

ในการสร้างอาเรย์ที่มีแต่ตัวเลข 0 หรือ 1 ล้วนๆใช้ np.ones และ np.zeros
print(np.ones(10))
print(np.ones([2,4])) # กรณีสร้างสองมิติขึ้นไปต้องใส่เป็นลิสต์หรือทูเพิล
print(np.zeros([2,5]))

ผลลัพธ์
[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

สำหรับค่าอื่นที่ไม่ใช่ 0 และ 1 ให้ใช้ np.full โดยใส่อาร์กิวเมนต์ตัวแรกเป็นมิติของอาเรย์ที่ต้องการ ส่วนตัวหลังเป็นค่าที่ต้องการซ้ำ
print(np.full(4,10))
print(np.full([2,2],5))

ผลลัพธ์
[ 10.  10.  10.  10.]
[[ 5.  5.]
 [ 5.  5.]]

นอกจากนี้ยังมี np.empty ซึ่งมีไว้สำหรับสร้างอาเรย์ตามขนาดที่ต้องการขึ้นมาโดยจะมีสมาชิกเป็นอะไรก็ไม่รู้ซึ่งเราไม่อาจควบคุมได้ เหมาะสำหรับเอาไว้สร้างอาเรย์เปล่าๆที่ไม่จำเป็นต้องสนว่ามีข้อมูลอะไรอยู่ก่อน สนแค่ขนาดเท่านั้น ข้อดีคือเร็วกว่า ones, zeros และ full เนื่องจากไม่จำเป็นต้องเตรียมค่าเริ่มต้น
print(np.empty([2,7]))

ผลลัพธ์
[[  0.00000000e+000   0.00000000e+000   9.48788057e+150   2.67670692e+015
   -1.13067367e+192  -3.37744342e+056   2.20318863e+228]
 [  6.21927996e+092  -2.62364069e+269  -7.83943927e+133   5.11600539e+305
    1.44472795e+170   1.43897597e-314   9.73469813e-309]]

อาเรย์ของเมทริกซ์เอกลักษณ์สามารถสร้างโดย np.identity กับ np.eye
print(np.identity(3)) # ใส่อาร์กิวเมนต์ตัวเดียว สร้างได้แค่เมทริกซ์จตุรัสเท่านั้น
print(np.eye(2)) # ใส่อาร์กิวเมนต์เดียวจะได้ผลเหมือน np.identity
print(np.eye(2,5)) # ใส่สองอาร์กิวเมนต์ได้ แถวหรือหลักที่เกินจะเป็น 0 หมด

ผลลัพธ์
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
[[ 1.  0.]
 [ 0.  1.]]
[[ 1.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.]]



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

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

ตัวอย่าง
aime = np.array([1,2,3,4,5])
aiment = aime
print(aiment) # ได้ [1 2 3 4 5]
print(aime) # ได้ [1 2 3 4 5]
aiment[1] = 6
print(aiment) # ได้ [1 6 3 4 5]
print(aime) # ได้ [1 6 3 4 5]

จะเห็นว่า aiment = aime ทำให้ aiment กลายเป็นตัวแปรที่ใช้แทน aime พอมีการเปลี่ยนแปลงภายใน aiment (เช่นในที่นี้คือแก้ค่าสมาชิก [1] เป็น 6) aime ก็จะเปลี่ยนแปลงตาม

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

แต่นอกจากนี้แล้วอาเรย์ยังสามารถถ่ายทอดด้วยชิ้นส่วนที่ถูกตัดมาด้วย
aime = np.array([1,2,3,4,5])
aimez = aime[2:]
print(aimez) # ได้ [3 4 5]
print(aime) # ได้ [1 2 3 4 5]
aimez[1] = 8
print(aimez) # ได้ [3 8 5]
print(aime) # ได้ [1 2 3 8 5]

จะเห็นว่า aimez = aime[2:] ทำให้ aimez กลายเป็นตัวแทนของส่วนตั้งแต่ตำแหน่ง [2] ของ aime จากนั้นพอมีการแก้ค่าภายใน aimez ค่าภายใน aime ก็จะถูกเปลี่ยนแปลงไปด้วย

คุณสมบัตินี้ไม่สามารถใช้กับลิสต์ได้ ลองเทียบดู
a = [1,2,3,4,5] # สร้าง a เป็นลิสต์ธรรมดา
avez = a[2:]
print(avez) # ได้ [3, 4, 5]
avez[1] = 8
print(avez) # ได้ [3, 8, 5]
print(a) # ได้ [1, 2, 3, 4, 5]

จะเห็นว่าในที่นี้ avez แค่มารับเอาค่าในช่วงตั้งแต่ตำแหน่ง [2] ของ a แต่ไม่ได้เป็นตัวแทน ดังนั้นพอมีการแก้ค่าใน avez จึงไม่ทำให้ค่าใน a เปลี่ยนแปลงตาม

จากตรงนี้จะเห็นได้ถึงข้อแตกต่างระหว่างอาเรย์กับลิสต์อีกอย่าง

คุณสมบัติตรงนี้อาจเป็นได้ทั้งประโยชน์และโทษ

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

เพื่อที่จะหลีกเลี่ยงเรื่องแบบนั้น จำเป็นจะต้องใช้เมธอด copy() เวลาที่ต้องการสร้างอาเรย์ใหม่จากอาเรย์เก่า แบบนี้จะเป็นการสร้างอาเรย์ใหม่ขึ้นมาโดยไม่เกี่ยวกับตัวเก่าอีกเลย

ตัวอย่าง
aime = np.array([1,2,3,4,5])
aimons = aime[2:].copy()
print(aimons) # ได้ [3 4 5]
print(aime) # ได้ [1 2 3 4 5]
aimons[1] = 8
print(aimons) # ได้ [3 8 5]
print(aime) # ได้ [1 2 3 4 5]

จะเห็นว่าเมื่อเติม .copy() ต่อท้ายลงไปตอนสร้างอาเรย์ aimons ขึ้นมาจะทำให้อาเรย์นี้กลายเป็นอาเรย์ใหม่ที่ไม่มีความเกี่ยวข้องอะไรกับ aime ทีนี้แม้ว่าจะมีการเปลี่ยนแปลงค่าภายในไปก็จะไม่กระทบต่ออาเรย์เก่า

copy นี้นอกจากจะเขียนในรูปเมธอดต่อท้ายแบบนี้ยังอาจเขียนในรูปฟังก์ชัน เป็น np.copy() ได้ด้วย



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



อ้างอิง


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


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

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

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

หมวดหมู่

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

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

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



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

  ค้นหาบทความ

  บทความแนะนำ

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

บทความแต่ละเดือน

2024年

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

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月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文