目錄

在 Python 中使用 NumPy 進行檔案的讀取與寫入

封面圖片是 NumPy 的官方 Logo , 2025 年 2 月 26 日擷取自 Github 。

前言

提到 Python 中的數值、矩陣運算,我們不得不提受到大多數程式設計者歡迎的 NumPy 模組。 NumPy 支援高維度、大規模的多維陣列與矩陣運算,並針對陣列運算提供大量的數學函式函式庫,使得在 Python 中進行數值運算時更加快速與容易。較可惜的是 NumPy 只能在 CPU 運行,無法利用 GPU 加速運算。

本文僅介紹 NumPy 的檔案讀取與寫入,有關 NumPy 的其他功能請參考其他文章或參考官方文件 https://numpy.org/doc/stable/reference/ 。

支援的檔案格式

NumPy 以二進制模式 (binary mode) 讀寫檔案,支援將資料寫入二進制格式檔案及純文字格式檔案。常見的格式有 NumPy 專用的二進制格式 .npy 、 .npz ,二進制格式 .bin ,純文字格式檔案 .txt 、 .csv 等。

.npy 格式

.npy 格式是用於儲存與載入 NumPy 的陣列類別 ndarray 的資料、形狀 (shape)、資料類型 (dtype) 等資訊。由於 .npy 檔案是單個數組儲存格式,因此只能儲存一個 NumPy 陣列。但因為 .npy 檔案採用二進制格式進行儲存,故比 .txt 、 .csv 等格式更節省空間,讀取速度更快。

.npz 格式

.npz 格式與 .npy 格式具有相同功能。不同的是 .npz 格式可以用來儲存多個 NumPy 陣列,且可以使用 .savez_compressed() 將資料進行壓縮。

.bin 格式

.bin 格式雖然也是二進制格式,但與 .npy 格式不同的是,.bin 格式只儲存資料,不儲存資料的形狀及資料類型。因此,在讀取 .bin 格式時總是需要手動指定資料的形狀。

寫入檔案

NumPy 將數值、矩陣寫入檔案的語法有很多種,以下介紹 .save() 、 .savez() 、 .savez_compressed() 、 .savetxt() 、 .tofile() 等方法。

我們首先載入 NumPy 模組,並假設有兩 Numpy 陣列,分別為 arr1 和 arr2 。

1
2
3
4
import numpy as np

arr1 = np.array([10, 20, 30])
arr2 = np.array([[1, 2], [3, 4]])

.save()

適用於:

  • 將單個陣列儲存為 NumPy 的 .npy 二進制格式。

用法:

.save(file, arr, allow_pickle=True)

參數:

  • file: 要儲存的檔案名稱、字串或檔案路徑。
  • arr: 要儲存的陣列。
  • allow_pickle: 布林值,可選填。允許使用 Python pickle 儲存物件陣列,但並非所有 pickle 資料都相容於不同版本的 Python。預設為 True 。

範例程式:

1
np.save("array.npy", arr1) # 儲存到 "array.npy" 檔案

.savez()

適用於:

  • 將多個陣列以未壓縮的格式儲存到 .npz 的單一檔案中。

用法:

.savez(file, *args, allow_pickle=True, **kwds)

參數:

  • file: 要儲存的檔案名稱、字串或檔案路徑。
  • args: 要儲存的陣列,可選填。請使用下方的 kwds 為每個陣列指定名稱,若使用 args 儲存陣列,則預設名稱為 "arr_0" 、 "arr_1" 等等。
  • allow_pickle: 布林值,可選填。允許使用 Python pickle 儲存物件陣列,但並非所有 pickle 資料都相容於不同版本的 Python。預設為 True 。
  • kwds: 要儲存的陣列,可選填。每個陣列將與其對應的自定義名稱一起儲存到輸出的檔案中。

範例程式:

1
np.savez("arrays.npz", first=arr1, second=arr2) # 儲存多個陣列

.savez_compressed()

適用於:

  • 將多個陣列以壓縮的格式儲存到 .npz 的單一檔案中。

用法:

.savez_compressed(file, *args, allow_pickle=True, **kwds)

參數:

  • file: 要儲存的檔案名稱、字串或檔案路徑。
  • args: 要儲存的陣列,可選填。請使用下方的 kwds 為每個陣列指定名稱,若使用 args 儲存陣列,則預設名稱為 "arr_0" 、 "arr_1" 等等。
  • allow_pickle: 布林值,可選填。允許使用 Python pickle 儲存物件陣列,但並非所有 pickle 資料都相容於不同版本的 Python。預設為 True 。
  • kwds: 要儲存的陣列,可選填。每個陣列將與其對應的自定義名稱一起儲存到輸出的檔案中。

範例程式:

1
np.savez_compressed("arrays_compressed.npz", first=arr1, second=arr2)

.savetxt()

適用於:

  • 將陣列儲存為純文字檔案 (.txt 、 .csv) 。

用法:

.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ', encoding=None)

參數:

  • fname: 要儲存的檔案名稱、字串或檔案路徑。如果副檔名為 .gz ,則將自動儲存為 gzip 壓縮格式, .loadtxt() 也會自動解壓縮讀取 gzip 壓縮檔案。
  • X: 要儲存到純文字檔案的一維或二維陣列。
  • fmt: 字串或字串序列,可選填。此參數較複雜,請參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.savetxt.html 。
  • delimiter: 資料間的分隔符號,用於分隔每一列。可為字串或字元,可選填。
  • newline: 換行符號,用於分隔每一行。可為字串或字元,可選填。
  • header: 寫在檔案開頭的字串。
  • footer: 寫在檔案末端的字串。
  • comments: 寫在 header 與 footer 前的註解符號,預設為 "# " 。
  • encoding: None 或字串,可選填。 NumPy 對輸出的檔案編碼進行的編碼,預設為 "latin1" 。

範例程式:

1
np.savetxt("array.txt", arr1, delimiter=",")

.tofile()

適用於:

  • 以二進制或純文字格式儲存,預設為二進制格式。

用法:

.tofile(fid, sep='', format='%s')

參數:

  • fid: 要儲存的檔案名稱、字串或檔案路徑。
  • sep: 字串,資料間的分隔符號。
  • format: 字串,文字檔案輸出的格式字串。

範例程式:

1
2
arr1.tofile("array.bin") # 預設為二進制格式
arr2.tofile("array.txt", sep=",", format="%d") # 以純文字格式儲存

讀取檔案

以下介紹使用 .load() 、 .loadtxt() 、 .genfromtxt() 、 .fromregex() 、 .fromstring() 、 .fromfile() 等方法將檔案讀取到 NumPy 中。

我們首先載入 NumPy 模組。

1
import numpy as np

.load()

適用於:

  • 從 .npy 、 .npz 或 pickle 檔案讀取陣列或 pickle 物件。

用法:

.load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, encoding='ASCII', *, max_header_size=10000)

參數:

  • file: 要讀取的檔案名稱、字串或檔案路徑。
  • mmap_mode: None 、 r+ 、 r 、 w+ 或 c ,可選填。此參數較複雜,請參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.load.html 。
  • allow_pickle: 布林值,可選填。是否允許載入儲存在 .npy 檔案中的 pickle 物件陣列。預設為 False 。
  • fix_imports: 布林值,可選填。僅在 Python 3 上載入 Python 2 產生的 pickle 檔案時有用。
  • encoding: "latin1" 、 "ASCII" 或 "bytes",可選填。讀取 Python 2 字串時使用的編碼,預設 "ASCII" 。
  • max_header_size: 整數,可選填。允許的最大 header 大小。較大的 header 可能不安全,導致無法安全載入。

範例程式:

1
2
3
4
5
loaded_arr = np.load("array.npy") # 讀取 `.npy`
print(loaded_arr)

loaded_npz = np.load("arrays.npz") # 讀取 `.npz`
print(loaded_npz["first"]) # 讀取 `arrays.npz` 中的 "first" 陣列

.loadtxt()

適用於:

  • 讀取純文字檔案。

用法:

.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding=None, max_rows=None, *, quotechar=None, like=None)

參數:

  • fname: 要讀取的檔案名稱、字串、檔案路徑或生成器 (generator) 。如果副檔名為 .gz ,會自動解壓縮讀取 gzip 壓縮檔案。
  • dtype: 資料類型,可選填。預設為 float 。
  • comments: 註解符號,字串或 None ,可選填。預設為 "# " 。
  • delimiter: 分隔符號,字串,可選填。預設為空格。
  • converters: 字典 (dict) ,可選填。預設為 None 。
  • skiprows: 跳過前 skiprows 行,包括註解。預設為 0 。
  • usecols: 要讀取哪些列,整數,可選填。 0 表示第一列,以此類推。預設為 None ,表示讀取所有欄位。
  • unpack: 布林值,可選填。為 True 時傳回的陣列將被轉置。預設為 False 。
  • ndmin: 整數,可選填。陣列至少有 ndmin 個維度,有效值為 0(預設)、 1 或 2 。
  • encoding: 字串,可選填。預設為 None 。此參數較複雜,請參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html 。
  • max_rows: 整數,可選填。在 skiprows 行之後讀取 max_rows 行的內容,但不包含空行。
  • quotechar: unicode 字元或 None ,可選填。引用項目的開始和結束的字元,預設為 None 。
  • like: array_like 類別,可選填。建議參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html 。

範例程式:

1
2
loaded_txt = np.loadtxt("array.txt", delimiter=",", dtype=int)
print(loaded_txt)

.genfromtxt()

適用於:

  • 從純文字檔案載入資料,並以指定方式處理缺失值。

用法:

.genfromtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, names=None, excludelist=None, deletechars=" !#$%&'()*+, -./:;<=>?@[\\]^{|}~", replace_space='_', autostrip=False, case_sensitive=True, defaultfmt='f%i', unpack=None, usemask=False, loose=True, invalid_raise=True, max_rows=None, encoding=None, *, ndmin=0, like=None)

參數:

  • fname: 要讀取的檔案名稱、字串、檔案路徑或生成器 (generator) 。如果副檔名為 .gz 或 .bz2 ,會自動解壓縮讀取該壓縮檔案。
  • dtype: 資料類型,可選填。預設為 float 。
  • comment: 註解符號,字串,可選填。
  • delimiter: 分隔符號,字串、整數或序列,可選填。
  • skip_header: 整數,可選填。檔案開頭要跳過的行數。
  • skip_footer: 整數,可選填。檔案末端要跳過的行數。
  • converters: 變數,可選填。將列的資料轉換為值的一組函數,也可為缺失資料提供預設值。
  • missing_values: 變數,可選填。對應到缺失資料的字串。
  • filling_values: 變數,可選填。缺失資料的預設值。
  • usecols: 要讀取哪些列,整數,可選填。 0 表示第一列,以此類推。預設為 None ,表示讀取所有欄位。
  • names: None 、 True 、字串或序列,可選填。如果為 True ,將從 skip_header 行之後的第一行讀取欄位名稱。
  • excludelist: 序列,可選填。要從 names 排除的的清單。
  • deletechars: 字串,可選填。定義要從 names 中刪除的無效字元清單。
  • replace_space: 字元,可選填。替換變數名稱中空格的字元,預設為 "_"。
  • autostrip: 布林值,可選填。是否自動從變數中去除空格。
  • case_sensitive: True 、 False 、 "upper" 或 "lower" ,可選填。如果為 True,則欄位名稱區分大小寫。如果為 False 或 "upper" ,則欄位名稱將轉換為大寫。如果為 "lower" ,則欄位名稱將轉換為小寫。
  • defaultfmt: 字串,可選填。定義預設欄位名稱的格式。
  • unpack: 布林值,可選填。為 True 時傳回的陣列將被轉置。預設為 False 。
  • usemask: 布林值,可選填。為 True 時,回傳一個 masked 陣列。為 False 時,則回傳一個 regular 陣列。
  • loose: 布林值,可選填。為 True 時,不會因無效值而引發錯誤。
  • invalid_raise: 布林值,可選填。為 True 時,偵測到列數不一致時會引發異常。為 False 時,會發出警告並跳過有問題的行。
  • max_rows: 整數,可選填。要讀取的最大行數,不能與 skip_footer 同時使用,且值必須至少為 1。
  • encoding: 字串,可選填。用於解碼輸入檔案的編碼,預設為 None 。
  • ndmin: 整數,可選填。陣列至少有 ndmin 個維度,有效值為 0(預設)、 1 或 2 。
  • like: array_like 類別,可選填。建議參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.genfromtxt.html 。

範例程式:

1
2
loaded_gen = np.genfromtxt("array.txt", delimiter=",", dtype=int, filling_values=-1)
print(loaded_gen)

.fromregex()

適用於:

  • 從符合正則表達式的純文字檔案讀取陣列。

用法:

.fromregex(file, regexp, dtype, encoding=None)

參數:

  • file: 要讀取的檔案名稱、字串或檔案路徑。
  • regexp: 字串或或 regexp ,用於解析檔案的正則表達式。
  • dtype: 資料類型 (dtype) 或資料類型的列表。
  • encoding: 字串,可選填。用於解碼輸入檔案的編碼。

範例程式:

1
2
3
4
5
import io
data = io.StringIO("123 abc\n456 def\n789 ghi")
pattern = r"(\d+)\s(\w+)"  # 解析 "數字 + 空格 + 文字"
loaded_regex = np.fromregex(data, pattern, dtype=[("num", int), ("text", "U10")])
print(loaded_regex)

.fromstring()

適用於:

  • 從字串中的文字資料初始化為一個新的陣列。

用法:

.fromstring(string, dtype=float, count=-1, *, sep, like=None)

參數:

  • string: 包含資料的字串。
  • dtype: 資料類型,可選填。預設為 float 。
  • count: 整數,可選填。從 string 中讀取 count 個元素。如果 count 為負數,將讀取整個 string 。
  • sep: 分隔符號,字串,可選填。
  • like: array_like 類別,可選填。建議參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.fromstring.html 。

範例程式:

1
2
3
s = "1,2,3,4,5"
loaded_str = np.fromstring(s, dtype=int, sep=",")
print(loaded_str)

.fromfile()

適用於:

  • 從純文字檔案或二進制格式檔案中的資料建立陣列。

用法:

.fromfile(file, dtype=float, count=-1, sep='', offset=0, *, like=None)

參數:

  • file: 要讀取的檔案名稱、字串或檔案路徑。
  • dtype: 資料類型,可選填。
  • count: 要讀取的數量, -1 表示全部。
  • sep: 分隔符號,如果為純文字檔案,為 "" 。
  • offset: 整數。相對於檔案目前位置的偏移量,預設為 0 。
  • like: array_like 類別,可選填。建議參考原始文件 https://numpy.org/doc/stable/reference/generated/numpy.fromfile.html 。

範例程式:

1
2
3
4
5
loaded_bin = np.fromfile("array.bin", dtype=int)  # 讀取二進制資料
print(loaded_bin)

loaded_txt = np.fromfile("array.txt", dtype=int, sep=",")  # 讀取純文本資料
print(loaded_txt)

結語

想要徹底了解 NumPy 的輸入與輸出是一項大工程,這裡面也不乏許多我看不懂或根本沒用過的指令、參數。透過學習上述的指令,我想,我應該對於 NumPy 有著多一點的認識了吧?

參考資料