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



numpy & matplotlib เบื้องต้น บทที่ ๓๙: การอ่านและเขียนอาเรย์ลงไฟล์
เขียนเมื่อ 2016/07/01 03:12
แก้ไขล่าสุด 2024/02/22 05:52
แม้ว่าในไพธอนจะมีฟังก์ชันสำหรับจัดการไฟล์อยู่แล้ว แต่เพื่อที่จะจัดการบางอย่างที่จำเพาะสำหรับอาเรย์แล้ว numpy มีคำสั่งสำหรับทำตรงนี้โดยเฉพาะ



การเปิดไฟล์ข้อความเพื่อสร้างอาเรย์
สมมุติว่ามีไฟล์ชื่อ 123456789.txt เขียนอะไรแบบนี้ไว้
1 2 3
4 5 6
7 8 9

หากต้องการให้เลขเหล่านี้กลายมาเป็นอาเรย์ ถ้าใช้ฟังก์ชันมาตรฐานของไพธอนจะเขียนแบบนี้
import numpy as np
f = open('123456789.txt','r')
m = f.readlines() # อ่านข้อความในไฟล์โดยแยกเป็นแต่ละแถวไว้ในลิสต์
a = [x.split() for x in m] # ใช้ split เพื่อแยกข้อความด้านในเป็นลิสต์ย่อย
ari = np.array(a,dtype=float) # นำมาเปลี่ยนแป็นอาเรย์ โดยกำหนดชนิดให้ด้วยไม่เช่นนั้นจะเป็นสายอักขระ
f.close()

(รายละเอียดเกี่ยวกับเรื่องการเปิดอ่านไฟล์แบบทั่วไปอ่านได้ในเนื้อหาภาษาไพธอนเบื้องต้นบทที่ ๑๗)

ซึ่งก็จะเห็นว่าประกอบไปด้วยหลายขั้นตอนกว่าจะมาเป็นอาเรย์ แต่หากเรารู้อยู่แล้วว่าเราต้องการเปิดไฟล์ขึ้นมาเพื่อสร้างอาเรย์ละก็ กรณีแบบนี้ใช้คำสั่ง np.loadtxt ของ numpy จะเร็วกว่า

หากใช้ np.loadtxt สามารถเขียนใหม่ได้เป็น
ari = np.loadtxt('123456789.txt')

เท่านี้ก็จะได้ผลลัพธ์แบบเดียวกันด้วยการเขียนแค่บรรทัดเดียว

แต่ทีนี้บางทีมันก็ไม่ง่ายเช่นนั้น เพราะตัวเลขอาจจะไม่ได้ถูกกั้นด้วยช่องว่าง แต่อาจใช้อะไรบางอย่างเช่นจุลภาคเป็นต้น เช่น
1, 2, 3
4, 5, 6
7, 8, 9

กรณีแบบนั้นจำเป็นต้องเพิ่มคีย์เวิร์ด delimiter เข้าไป
ari = np.loadtxt('123456789.txt',delimiter=',')

ในบางครั้งภายในไฟล์ก็อาจไม่ได้มีแต่ข้อมูลที่เราต้องการ แต่มีการจั่วหัว เช่น
sawatdi rao chue array
x, y, z
1, 2, 3
4, 5, 6
7, 8, 9

กรณีแบบนี้ต้องเติมคีย์เวิร์ด skiprows โดยใส่ค่าเท่ากับจำนวนบรรทัดที่ต้องการข้าม เพื่อใหัมันโดดข้ามไปที่บรรทัดที่ต้องการอ่านจริงๆ
ari = np.loadtxt('123456789.txt',delimiter=',',skiprows=2)

เพียงแต่ว่าในกรณีที่ในไฟล์มีตัวอักษรที่ไม่ใช่ ascii ปนอยู่ด้วย เช่น
สวัสดี เราชื่ออาเรย์
x, y, z
1, 2, 3
4, 5, 6
7, 8, 9

แบบนี้มันจะไม่สามารถอ่านได้ จำเป็นต้องเปิดไฟล์ด้วย open แล้วจึงใช้ไฟล์นั้นมาใส่ใน np.loadtxt อีกที จึงเป็นแบบนี้
f = open('123456789.txt',encoding='utf-8')
ari = np.loadtxt(f,delimiter=',',skiprows=2)

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

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

ตัวอย่างเช่นข้อความเป็นแบบนี้
o, x, y, z
a, 1, 2, 3
b, 4, 5, 6
c, 7, 8, 9

ก็ต้องเขียนแบบนี้
ari = np.loadtxt('123456789.txt',delimiter=',',skiprows=1,usecols=[1,2,3])

แบบนี้ a b c ก็จะไม่ถูกนำมารวมในอาเรย์ที่โหลดขึ้นมาด้วย

ถ้ากำหนดคีย์เวิร์ด unpack=1 จะทำให้อาเรย์ที่ได้ถูกทรานสโพสสลับแกนไป
ari = np.loadtxt('123456789.txt',delimiter=',',skiprows=1,usecols=[1,2,3],unpack=1)

ผลลัพธ์
[[ 1.  4.  7.]
 [ 2.  5.  8.]
 [ 3.  6.  9.]]

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

เช่นถ้าต้องการจำนวนเต็ม
ari = np.loadtxt('123456789.txt',delimiter=',',skiprows=1,usecols=[1,2,3],dtype=int)

ได้
[[1 2 3]
 [4 5 6]
 [7 8 9]]



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



การบันทึกอาเรย์
ในทางตรงกันข้ามกับการอ่านอาเรย์ คำสั่งที่ใช้บันทึกอาเรย์คือ savetxt
arai = np.arange(1,9).reshape(2,4)
np.savetxt('12345678.txt',arai)

พอเปิดไฟล์ก็จะได้เป็นแบบนี้
1.000000000000000000e+00 2.000000000000000000e+00 3.000000000000000000e+00 4.000000000000000000e+00
5.000000000000000000e+00 6.000000000000000000e+00 7.000000000000000000e+00 8.000000000000000000e+00

นั่นเพราะเราไม่ได้กำหนดรูปแบบการแสดงผลมันก็เลยออกมาเป็นแบบนี้ รูปแบบการแสดงผลสามารถระบุได้โดยใส่คีย์เวิร์ด fmt โดยค่าที่ใส่ก็คือพวก %d %f อ่านรายละเอียดได้ในเนื้อหาภาษาไพธอนเบื้องต้นบทที่ ๑๐

คีย์เวิร์ด fmt อยู่ในตำแหน่งที่ ๓ อยู่แล้ว ดังนั้นอาจใส่เป็นอาร์กิวเมนต์ตัวที่ ๓ ไปโดยไม่ต้องพิมพ์ fmt= ก็ได้

ลองแก้เป็น
np.savetxt('12345678.txt',arai,'%05d')

จะได้
00001 00002 00003 00004
00005 00006 00007 00008

สามารถกำหนดตัวคั่นได้ด้วยคีย์เวิร์ด delimiter เช่นเดียวกับตอนอ่าน

หากต้องการให้เปิดอ่านในไมโครซอฟต์เอ็กซ์เซลเป็นตารางได้เลยก็อาจคั่นด้วย , และนิยมเซฟไฟล์เป็น .csv
np.savetxt('12345678.csv',arai,'%d',delimiter=',')

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

ตัวอย่าง
np.savetxt('12345678.txt',arai,'%d',delimiter='_',newline='||')

จะได้
1_2_3_4||5_6_7_8||

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

ลอง
np.savetxt('12345678.txt',arai,'%d',header='header',footer='footer')

จะได้เป็น
# header
1 2 3 4
5 6 7 8
# footer

จะเห็นว่าข้อความเป็นไปตามที่พิมพ์แต่มีเพิ่ม # เข้ามาด้านหน้า หากเราเอาไฟล์นี้ไปเปิดด้วยคำสั่ง np.loadtxt จะพบว่ามันไม่อ่านตรงนี้โดยที่เราไม่จำเป็นต้องใส่คีย์เวิร์ด skiprows ด้วย

แต่หากเราไม่ต้องการให้มี # นำหน้าหรืออยากเปลี่ยนเป็นอย่างอื่นก็ต้องเพิ่มคีย์เวิร์ดไปอีกตัวคือ comments
np.savetxt('12345678.txt',arai,'%d',header='header',footer='footer',comments='!!!')

ผลที่ได้ก็จะเป็น
!!!header
1 2 3 4
5 6 7 8
!!!footer

สรุปคีย์เวิร์ดทั้งหมด
fmt รูปแบบตัวหนังสือที่จะเขียน
delimiter ตัวคั่นระหว่างหลัก ถ้าไม่ใส่จะเป็นการเว้นช่องว่างหนึ่งช่อง
newline ตัวคั่นระหว่างแถว ถ้าไม่ใส่จะเป็น \n
header ข้อความส่วนหัว
footer ข้อความส่วนท้าย
comments ข้อความที่นำหน้าข้อความส่วนหัวและท้าย ถ้าไม่ใส่จะเป็น #



การบันทึกเป็นไฟล์เฉพาะสำหรับ numpy
นอกจากการจัดการกับไฟล์ทั่วไปดังที่กล่าวไปแล้ว numpy ยังมีวิธีการบันทึกเป็นไฟล์ในรูปแบบของตัวเองด้วย ทำได้โดยใช้ฟังก์ชัน np.save

ไฟล์ของ numpy นั้นมีชื่อสกุลเป็น .npy เวลาที่เซฟเราต้องพิมพ์ชื่อไฟล์ให้เป็น .npy ไม่เช่นนั้น .npy จะถูกเติมต่อท้ายให้โดยอัตโนมัติ

ตัวอย่าง
aay = np.arange(1,5).reshape(2,2)
np.save('1234',aay)

จากนั้นก็จะได้ไฟล์ชื่อ 1234.npy มา ซึ่งเราจะไม่สามารถเปิดอ่านดูภายในได้เพาะเป็นไบนารี

การเปิดอ่านไฟล์ทำได้โดยใช้ฟังก์ชัน np.load
yaa = np.load('1234.npy')

หากต้องการบันทึกอาเรย์หลายตัวไว้ในไฟล์เดียวก็สามารถทำได้ด้วยคำสั่น np.savez

(นอกเรื่อง) คำว่า savez เป็นภาษาฝรั่งเศส เป็นรูปผันของคำว่า savoir แปลว่า "รู้" ใช้กับประธานบุรุษที่สองพหูพจน์ในกาลปัจจุบัน

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

ไฟล์ที่ได้จากคำสั่งนี้จะมีชื่อสกุลเป็น npz

ตัวอย่าง
axa = np.arange(1,5)
aya = np.arange(11,15)
aza = np.arange(101,105)
np.savez('aaa',axa,aya,aza)

จะได้ไฟล์ชื่อ aaa.npz มา ซึ่งไม่สามารถเปิดอ่านได้โดยตรง แต่ว่าอาเรย์ทั้งหมดก็ได้ถูกเก็บอยู่ในนั้นแล้ว

จากนั้นก็เปิดอ่านขึ้นมาได้ด้วยฟังก์ชัน np.load เหมือนกับอาเรย์เดี่ยว แต่ว่าออบเจ็กต์ที่ได้มาจะอยู่ในรูป numpy.lib.npyio.NpzFile ซึ่งยังเข้าถึงอาเรย์แต่ละตัวไม่ได้ในทันที จะเข้าถึงได้ในลักษณะการเขียนเป็นแบบดิกชันนารี โดยที่ชื่อจะเป็น arr_0, arr_1, arr_2 ตามลำดับที่ใส่เข้าไป

ตัวอย่าง
awa = np.load('aaa.npz')
print(awa['arr_0']) # ได้ [1 2 3 4]
print(awa['arr_1']) # ได้ [11 12 13 14]
print(awa['arr_2']) # ได้ [101 102 103 104]

แต่ว่าเราสามารถตั้งชื่อให้กับอาเรย์ที่ใส่เข้าไปได้ตามที่ต้องการได้ โดยใส่ในรูปของคีย์เวิร์ด แล้วคีย์เวิร์ดนั้นจะกลายมาเป็นชื่อ
axa = np.arange(1,5)
aya = np.arange(11,15)
aza = np.arange(101,105)
np.savez('aaa',xa=axa,ya=aya,za=aza)
awa = np.load('aaa.npz')
print(awa['xa']) # ได้ [1 2 3 4]

เราสามารถตรวจดูชื่ออาเรย์ทั้งหมดที่เก็บอยู่ในไฟล์นั้นได้โดยดูที่แอตทริบิวต์ files
awa = np.load('aaa.npz')
print(awa.files) # ได้ ['ya', 'za', 'xa']



อ้างอิง


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


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

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

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

หมวดหมู่

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

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

สารบัญ

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

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

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



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

  ค้นหาบทความ

  บทความแนะนำ

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

ไทย

日本語

中文