วิธีบันทึกและโหลดข้อมูล numpy.array () อย่างถูกต้อง?


107

ฉันสงสัยว่าจะบันทึกและโหลดnumpy.arrayข้อมูลอย่างถูกต้องได้อย่างไร ตอนนี้ฉันใช้numpy.savetxt()วิธีนี้ ตัวอย่างเช่นถ้าฉันมีอาร์เรย์markersซึ่งมีลักษณะดังนี้:

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

ฉันพยายามบันทึกโดยใช้:

numpy.savetxt('markers.txt', markers)

ในสคริปต์อื่นฉันพยายามเปิดไฟล์ที่บันทึกไว้ก่อนหน้านี้:

markers = np.fromfile("markers.txt")

และนั่นคือสิ่งที่ฉันได้รับ ...

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

ข้อมูลที่บันทึกไว้ก่อนมีลักษณะดังนี้:

0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00

แต่เมื่อฉันบันทึกข้อมูลที่โหลดโดยใช้วิธีการเดียวกันคือ. numpy.savetxt()ดูเหมือนว่า:

1.398043286095131769e-76
1.398043286095288860e-76
1.396426376485745879e-76
1.398043286055061908e-76
1.398043286095288860e-76
1.182950697433698368e-76
1.398043275797188953e-76
1.398043286095288860e-76
1.210894289234927752e-99
1.398040649781712473e-76

ผมทำอะไรผิดหรือเปล่า? ปล. ไม่มีการดำเนินการ "หลังเวที" อื่น ๆ ที่ฉันดำเนินการ เพียงแค่บันทึกและโหลดและนั่นคือสิ่งที่ฉันได้รับ ขอบคุณล่วงหน้า.


ผลลัพธ์ของไฟล์ข้อความคืออะไร? ทำไมไม่เขียนลงในไฟล์ CSV ล่ะ?

5
คุณต้องการบันทึกและโหลดเป็นไฟล์ข้อความที่มนุษย์อ่านได้หรือไม่? จะเร็วขึ้น (และไฟล์จะมีขนาดกะทัดรัดมากขึ้น) หากคุณบันทึก / โหลดไฟล์ไบนารีโดยใช้np.save()และnp.load().
ali_m

ขอบคุณสำหรับคำแนะนำ. มันช่วยได้ อย่างไรก็ตามคุณสามารถอธิบายได้หรือไม่ว่าทำไมจึงเป็นเช่นนั้นและมีวิธีใดที่จะอนุญาตให้บันทึกข้อมูลในรูปแบบ * .txt และโหลดได้โดยไม่ปวดหัว ตัวอย่างเช่นเมื่อต้องการทำงานกับ matlab, java หรือเครื่องมือ / ภาษาอื่น ๆ
bluevoxel

3
ในการส่งอาร์เรย์ไปยัง / จาก MATLAB คุณสามารถใช้scipy.io.savematและscipy.io.loadmat.
ali_m

2
ค่าเริ่มต้นfromfileคือการอ่านข้อมูลเป็นไบนารี คือการจับคู่ที่ถูกต้องด้วยloadtxt savetxtดูเอกสารเกี่ยวกับฟังก์ชัน
hpaulj

คำตอบ:


150

วิธีที่น่าเชื่อถือที่สุดที่ฉันพบคือใช้np.savetxtกับnp.loadtxtและไม่np.fromfileเหมาะกับไฟล์ไบนารีที่เขียนด้วยtofile. np.fromfileและnp.tofileวิธีการเขียนและอ่านไฟล์ไบนารีในขณะที่np.savetxtเขียนแฟ้มข้อความ ตัวอย่างเช่น:

In [1]: a = np.array([1, 2, 3, 4])
In [2]: np.savetxt('test1.txt', a, fmt='%d')
In [3]: b = np.loadtxt('test1.txt', dtype=int)
In [4]: a == b
Out[4]: array([ True,  True,  True,  True], dtype=bool)

หรือ:

In [5]: a.tofile('test2.dat')
In [6]: c = np.fromfile('test2.dat', dtype=int)
In [7]: c == a
Out[7]: array([ True,  True,  True,  True], dtype=bool)

ฉันใช้วิธีการเดิมแม้ว่ามันจะช้ากว่าและสร้างไฟล์ที่ใหญ่กว่า (บางครั้ง): รูปแบบไบนารีอาจขึ้นอยู่กับแพลตฟอร์ม (ตัวอย่างเช่นรูปแบบไฟล์ขึ้นอยู่กับความสิ้นสุดของระบบของคุณ)

มีรูปแบบอิสระของแพลตฟอร์มสำหรับอาร์เรย์ NumPy ซึ่งสามารถบันทึกและอ่านด้วยnp.saveและnp.load:

In  [8]: np.save('test3.npy', a)    # .npy extension is added if not given
In  [9]: d = np.load('test3.npy')
In [10]: a == d
Out[10]: array([ True,  True,  True,  True], dtype=bool)

48
.npyไฟล์ (เช่นสร้างโดยnp.save()) ไม่ขึ้นกับแพลตฟอร์มและจะมีขนาดกะทัดรัดและสร้างได้เร็วกว่าไฟล์ข้อความ
ali_m

2
นอกจากนี้np.savezหากคุณต้องการให้เอาต์พุตบีบอัด
tegan

3
@tegan np.savezบันทึกอาร์เรย์หลายบีบอัด - np.savez_compressedจะบีบอัดพวกเขา - ไม่มีnp.save_compressedเลย ดูdocs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns

1
ขอบคุณ xnx ฉันมีปัญหาเดียวกัน (กับ dtype float) โดยใช้ np.savetxt กับ np.loadtxt แก้ไขได้
Yogesh

ฉันมีปัญหากับข้อมูลการประหยัดดองที่มากกว่า 2GB ขอบคุณ xnx ที่แก้ปัญหาได้โดยใช้ a.tofile และ np.fromfile
Azr

49
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load

1
มีปัญหาในการใช้งานpickleหรือไม่?
Charlie Parker

ตัวอย่างเช่นเพื่อให้เราสามารถโหลดข้อมูลx = db["x"]ตามด้วยy = db["y"]?
Charlie Parker

เมื่อฉันลองสิ่งนี้อาร์เรย์ของฉันกลับว่างเปล่า เออ.
Keith

@ คี ธ คุณเพิ่งลองพิมพ์ก่อนที่จะบันทึกอาร์เรย์จำนวนนับของคุณหรือไม่?
Sherzod

@Sherzod ฉันเพิ่งใช้array.shapeและ()กลับมา
Keith

3

np.fromfile()มีsep=อาร์กิวเมนต์คำหลัก:

คั่นระหว่างรายการถ้าไฟล์เป็นไฟล์ข้อความ ตัวคั่นว่าง (“”) หมายถึงไฟล์ควรถือว่าเป็นไบนารี ช่องว่าง ("") ในตัวคั่นตรงกับอักขระช่องว่างศูนย์หรือมากกว่า ตัวคั่นที่ประกอบด้วยช่องว่างเท่านั้นต้องตรงกับช่องว่างอย่างน้อยหนึ่งช่อง

ค่าดีฟอลต์ของsep=""วิธีการที่np.fromfile()พยายามอ่านเป็นไฟล์ไบนารีแทนที่จะเป็นไฟล์ข้อความที่คั่นด้วยช่องว่างดังนั้นคุณจึงได้รับค่าไร้สาระกลับคืนมา หากคุณใช้np.fromfile('markers.txt', sep=" ")คุณจะได้รับผลลัพธ์ที่คุณกำลังมองหา

อย่างไรก็ตามตามที่คนอื่น ๆ ได้ชี้ให้เห็นnp.loadtxt()เป็นวิธีที่ดีกว่าในการแปลงไฟล์ข้อความเป็นอาร์เรย์ numpy และเว้นแต่ว่าไฟล์นั้นจะต้องอ่านได้โดยมนุษย์มักจะใช้รูปแบบไบนารีแทน (เช่นnp.load()/ np.save()) ได้ดีกว่า


มีปัญหาในการใช้งานpickleหรือไม่?
Charlie Parker

1

สำหรับคำตอบสั้น ๆ คุณควรใช้np.saveและnp.load. ข้อดีของสิ่งเหล่านี้คือสร้างขึ้นโดยนักพัฒนาของไลบรารี numpy และใช้งานได้แล้ว (บวกมีแนวโน้มที่จะปรับให้เหมาะสมแล้ว) เช่น

import numpy as np
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

np.save(path/'x', x)
np.save(path/'y', y)

x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')

print(x is x_loaded) # False
print(x == x_loaded) # [[ True  True  True  True  True]]

คำตอบเพิ่มเติม:

ในท้ายที่สุดมันขึ้นอยู่กับความต้องการของคุณเพราะคุณสามารถบันทึกรูปแบบที่มนุษย์อ่านได้ (ดูที่การถ่ายโอนอาร์เรย์ NumPy ลงในไฟล์ csv ) หรือแม้กระทั่งกับไลบรารีอื่น ๆ หากไฟล์ของคุณมีขนาดใหญ่มาก (ดูวิธีที่ดีที่สุดในการรักษาอาร์เรย์จำนวนนับนี้ บนดิสก์สำหรับการสนทนาแบบขยาย)

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

ยกตัวอย่างเช่นพยายามบันทึกด้วยของดอง ฉันพยายามเพื่อความสนุกและใช้เวลาอย่างน้อย 30 นาทีในการตระหนักว่าดองจะไม่บันทึกข้อมูลของฉันเว้นแต่ฉันจะเปิดและอ่านไฟล์ในโหมดไบต์ด้วยwb. ใช้เวลากับ Google ลองทำสิ่งต่างๆทำความเข้าใจกับข้อความแสดงข้อผิดพลาด ฯลฯ ... รายละเอียดเล็ก ๆ น้อย ๆ แต่ความจริงที่ว่าฉันต้องเปิดไฟล์ที่ซับซ้อนด้วยวิธีที่ไม่คาดคิดอยู่แล้ว เพื่อเพิ่มว่าฉันต้องอ่านสิ่งนี้อีกครั้ง (ซึ่ง btw นั้นทำให้สับสน) ความแตกต่างระหว่างโหมด a, a +, w, w + และ r + ในฟังก์ชันเปิดในตัว? .

ดังนั้นหากมีอินเทอร์เฟซที่ตรงกับความต้องการของคุณให้ใช้มันเว้นแต่คุณจะมีเหตุผลที่ดี( มาก ) (เช่นความเข้ากันได้กับ matlab หรือด้วยเหตุผลบางอย่างคุณต้องการอ่านไฟล์และการพิมพ์ใน python จริงๆไม่ตรงกับความต้องการของคุณซึ่ง อาจจะน่าสงสัย) นอกจากนี้ส่วนใหญ่แล้วหากคุณต้องการเพิ่มประสิทธิภาพคุณจะพบในภายหลัง (แทนที่จะใช้เวลานานในการแก้ไขข้อบกพร่องสิ่งที่ไร้ประโยชน์เช่นการเปิดไฟล์ numpy ธรรมดา ๆ )

ดังนั้นการใช้อินเตอร์เฟซ / NumPy ให้ มันอาจจะไม่สมบูรณ์แบบ แต่ก็น่าจะดีโดยเฉพาะอย่างยิ่งสำหรับห้องสมุดที่มีมานานพอ ๆ

ฉันใช้เวลาในการบันทึกและโหลดข้อมูลด้วยจำนวนมากไปแล้วดังนั้นขอให้สนุกกับมันหวังว่ามันจะช่วยได้!

import numpy as np
import pickle
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

# using save (to npy), savez (to npz)
np.save(path/'x', x)
np.save(path/'y', y)
np.savez(path/'db', x=x, y=y)
with open(path/'db.pkl', 'wb') as db_file:
    pickle.dump(obj={'x':x, 'y':y}, file=db_file)

## using loading npy, npz files
x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')
db = np.load(path/'db.npz')
with open(path/'db.pkl', 'rb') as db_file:
    db_pkl = pickle.load(db_file)

print(x is x_loaded)
print(x == x_loaded)
print(x == db['x'])
print(x == db_pkl['x'])
print('done')

ความคิดเห็นเกี่ยวกับสิ่งที่เรียนรู้:

  • np.saveตามที่คาดไว้สิ่งนี้บีบอัดได้ดีอยู่แล้ว (ดูhttps://stackoverflow.com/a/55750128/1601580 ) ใช้งานได้ทันทีโดยไม่ต้องเปิดไฟล์ใด ๆ ทำความสะอาด. ง่าย. มีประสิทธิภาพ ใช้มัน.
  • np.savezใช้รูปแบบที่ไม่มีการบีบอัด (ดูเอกสาร ) Save several arrays into a single file in uncompressed .npz format.หากคุณตัดสินใจใช้สิ่งนี้ (คุณได้รับคำเตือนให้หลีกเลี่ยงโซลูชันมาตรฐานดังนั้นคาดว่าจะมีข้อบกพร่อง!) คุณอาจพบว่าคุณต้องใช้ชื่ออาร์กิวเมนต์เพื่อบันทึกเว้นแต่คุณต้องการ ใช้ชื่อเริ่มต้น ดังนั้นอย่าใช้สิ่งนี้หากงานแรกได้ผล (หรืองานใด ๆ ใช้สิ่งนั้น!)
  • Pickle ยังอนุญาตให้ใช้รหัสโดยอำเภอใจ บางคนอาจไม่ต้องการใช้สิ่งนี้เพื่อเหตุผลด้านความปลอดภัย
  • ไฟล์ที่มนุษย์อ่านได้มีราคาแพงในการทำ ฯลฯ อาจไม่คุ้มค่า
  • มีสิ่งที่เรียกว่าhdf5ไฟล์ขนาดใหญ่ เย็น! https://stackoverflow.com/a/9619713/1601580

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

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