NumPyでCSVファイルを読み込み・書き込み(入力・出力)

NumPyではCSV(カンマ区切り)やTSV(タブ区切り)などのテキストファイルを配列ndarrayとして読み込んだり、ndarrayをテキストファイルとして書き出したりできます。 ここでは以下の内容について説明します。なお、タイトルおよび見出しでは便宜上CSVとしているが、カンマ区切りに限らず任意の文字列で区切られたテキストファイル(CSV: Character Separated Value)を対象とします。

CSVファイルを読み込み(入力): np.loadtxt() 基本的な使い方 区切り文字(デリミタ)を指定: 引数delimiter データ型を指定: 引数dtype 読み込む行・列を指定: 引数skiprows, usecols

複雑なCSVファイルを読み込み(入力): np.genfromtxt() 欠損値の処理 異なるデータ型の処理

CSVファイルに書き込み(出力): np.savetxt() 基本的な使い方 フォーマットを指定: 引数fmt 区切り文字(デリミタ)を指定: 引数delimiter 出力できるのは一次元配列と二次元配列のみ

pandasを利用した読み書き(入出力) 見出し行・列が付いたCSVファイルの処理 欠損値の処理 異なるデータ型の処理

最後に触れるようにヘッダー(見出し行)を含んでいたり、数値や文字列の列が混在しているようなファイルの読み書き(入出力)はpandasの方が便利。 また、他のアプリケーションで使う必要がなければテキストではなくNumPy独自のバイナリ形式で保存する方が楽。以下の記事を参照。

なお、すべての引数について触れているわけではないので詳細は公式ドキュメントを参照されたい。

CSVファイルを読み込み(入力): np.loadtxt()

基本的な使い方

任意の文字で区切られたテキストファイルをndarrayとして読み込むにはnp.loadtxt()を使います。

numpy.loadtxt — NumPy v1.15 Manual

スペースで数値が区切られた以下のファイルを例とします。説明のため以降もファイルの中身をopen()およびread()で示す。open()については以下の記事を参照。

import numpy as np

with open('data/src/sample.txt') as f:
    print(f.read())
# 11 12 13 14
# 21 22 23 24
# 31 32 33 34

第一引数に読み込むファイルのパスを指定するとndarrayが返される。デフォルトではデータ型dtypeはfloat(ビット数は環境依存)。

a = np.loadtxt('data/src/sample.txt')

print(type(a))
# <class 'numpy.ndarray'>

print(a)
# [[11. 12. 13. 14.]
#  [21. 22. 23. 24.]
#  [31. 32. 33. 34.]]

print(a.dtype)
# float64

区切り文字(デリミタ)を指定: 引数delimiter

カンマ区切りのファイル(CSVファイル)を例とします。

with open('data/src/sample.csv') as f:
    print(f.read())
# 11,12,13,14
# 21,22,23,24
# 31,32,33,34

デフォルトではエラーとなり読み込めない。

# print(np.loadtxt('data/src/sample.csv'))
# ValueError: could not convert string to float: '11,12,13,14'

引数delimiterに文字列でカンマ','を指定します。

print(np.loadtxt('data/src/sample.csv', delimiter=','))
# [[11. 12. 13. 14.]
#  [21. 22. 23. 24.]
#  [31. 32. 33. 34.]]

引数delimiterを省略した場合はデフォルト値のスペース' 'となり、上述のようなスペース区切りのファイルは読み込めるがそれ以外のファイルは読み込めないため、適宜指定する必要があります。 TSV(タブ区切り)の場合は'\t'とすればよい。

データ型を指定: 引数dtype

上述のようにデフォルトではデータ型dtypeはfloat(ビット数は環境依存)。引数dtypeに任意のデータ型を指定できます。

a = np.loadtxt('data/src/sample.csv', delimiter=',', dtype='int64')

print(a)
# [[11 12 13 14]
#  [21 22 23 24]
#  [31 32 33 34]]

print(a.dtype)
# int64

読み込む行・列を指定: 引数skiprows, usecols

不要なデータが含まれている場合は、引数skiprows, usecolsで読み込む行・列を指定できます。 引数skiprowsは先頭から何行スキップして読み込むかを整数値で指定します。 引数usecolsは読み込む列をリストなどのシーケンスオブジェクトで指定します。一列のみ読み込む場合は整数値でもよい。 見出し行と見出し列を含む以下のファイルを例とします。

with open('data/src/sample_header_index.csv') as f:
    print(f.read())
# ,a,b,c,d
# ONE,11,12,13,14
# TWO,21,22,23,24
# THREE,31,32,33,34

引数skiprows, usecolsを指定すると文字列を除外した数値のみのデータが読み込める。

a = np.loadtxt('data/src/sample_header_index.csv', delimiter=',', dtype='int64',
               skiprows=1, usecols=[1, 2, 3, 4])

print(a)
# [[11 12 13 14]
#  [21 22 23 24]
#  [31 32 33 34]]

なお、このようなファイルはpandasを使ったほうが楽。後述。

複雑なCSVファイルを読み込み(入力): np.genfromtxt()

np.genfromtxt()を使うと、欠損値を含んでいたり複数の異なるデータ型を含んでいたりする、より複雑な構造のCSVファイルの読み込みが可能。 ただし、特に複数のデータ型を含むファイルはpandasを使ったほうが便利なので、ここでは簡単な紹介のみとします。詳細は以下の公式ドキュメントを参照。pandasについては後述。

numpy.genfromtxt — NumPy v1.15 Manual

欠損値の処理

以下のように値が欠損しているファイルを例とします。np.loadtxt()だとエラーとなります。

with open('data/src/sample_nan.csv') as f:
    print(f.read())
# 11,12,,14
# 21,,,24
# 31,32,33,34

# a = np.loadtxt('data/src/sample_nan.csv', delimiter=',')
# ValueError: could not convert string to float:

np.genfromtxt()を使うと欠損値がnp.nanとして読み込まれる。

a = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')

print(a)
# [[11. 12. nan 14.]
#  [21. nan nan 24.]
#  [31. 32. 33. 34.]]

print(a[0, 2])
# nan

print(type(a[0, 2]))
# <class 'numpy.float64'>

NumPyにおける欠損値の処理については以下の記事を参照。

異なるデータ型の処理

以下のように列ごとに異なるデータ型(文字列と数値)を持つファイルを例とします。

with open('data/src/sample_pandas_normal.csv') as f:
    print(f.read())
# name,age,state,point
# Alice,24,NY,64
# Bob,42,CA,92
# Charlie,18,CA,70
# Dave,68,TX,70
# Ellen,24,CA,88
# Frank,30,NY,57

上の説明では省略したが、引数dtypeに適切な値を指定すればnp.loadtxt()でもこのようなファイルを構造化配列(Structured array)として読み込むことが可能。

a = np.loadtxt('data/src/sample_pandas_normal.csv', delimiter=',', skiprows=1,
               dtype={'names': ('name', 'age', 'state', 'point'),
                      'formats': ('<U7', '<i8', '<U2', '<i8')})

print(type(a))
# <class 'numpy.ndarray'>

print(a)
# [('Alice', 24, 'NY', 64) ('Bob', 42, 'CA', 92) ('Charlie', 18, 'CA', 70)
#  ('Dave', 68, 'TX', 70) ('Ellen', 24, 'CA', 88) ('Frank', 30, 'NY', 57)]

print(a.dtype)
# [('name', '<U7'), ('age', '<i8'), ('state', '<U2'), ('point', '<i8')]

np.genfromtxt()では、引数namesをTrue、引数dtypeをNoneとすると、一行目の値がフィールド名で、列ごとに型が自動的に決定された構造化配列として読み込まれる。

a = np.genfromtxt('data/src/sample_pandas_normal.csv', delimiter=',',
                  names=True, dtype=None, encoding='utf-8')

print(type(a))
# <class 'numpy.ndarray'>

print(a)
# [('Alice', 24, 'NY', 64) ('Bob', 42, 'CA', 92) ('Charlie', 18, 'CA', 70)
#  ('Dave', 68, 'TX', 70) ('Ellen', 24, 'CA', 88) ('Frank', 30, 'NY', 57)]

print(a.dtype)
# [('name', '<U7'), ('age', '<i8'), ('state', '<U2'), ('point', '<i8')]

構造化配列(Structured array)についての詳細は以下の公式ドキュメントを参照。

Structured arrays — NumPy v1.15 Manual

繰り返しになるが、このようなファイルはpandasを使ったほうが簡単。

CSVファイルに書き込み(出力): np.savetxt()

ndarrayを任意の文字列で区切られたテキストファイルとして書き込むにはnp.savetxt()を使います。

numpy.savetxt — NumPy v1.15 Manual

以下のndarrayを例とします。

a = np.arange(6).reshape(2, 3)
print(a)
# [[0 1 2]
#  [3 4 5]]

基本的な使い方

第一引数に出力先のファイルのパス、第二引数に元のndarrayを指定します。

np.savetxt('data/temp/np_savetxt.txt', a)

以下のような内容のファイルが作成される。

with open('data/temp/np_savetxt.txt') as f:
    print(f.read())
# 0.000000000000000000e+00 1.000000000000000000e+00 2.000000000000000000e+00
# 3.000000000000000000e+00 4.000000000000000000e+00 5.000000000000000000e+00

フォーマットを指定: 引数fmt

引数fmtで任意のフォーマットを指定できます。 小数点以下の桁数などを指定できるが、値が丸まった場合は当然そのままテキストとして保存されるので、あとから復元することはできなくなる。注意。 デフォルトは'%.18e'で、上述のように小数点以下18桁の指数表記で書き込まれる。.以降の数字は小数点以下の桁数、eは指数表記を表す。

np.savetxt('data/temp/np_savetxt_5e.txt', a, fmt='%.5e')

with open('data/temp/np_savetxt_5e.txt') as f:
    print(f.read())
# 0.00000e+00 1.00000e+00 2.00000e+00
# 3.00000e+00 4.00000e+00 5.00000e+00

なお、指数表記でもnp.loadtxt()でそのまま読み込めるので、特にこだわりがなければデフォルトのフォーマットにしておけば問題ない。

print(np.loadtxt('data/temp/np_savetxt.txt'))
# [[0. 1. 2.]
#  [3. 4. 5.]]

fは小数。

np.savetxt('data/temp/np_savetxt_5f.txt', a, fmt='%.5f')

with open('data/temp/np_savetxt_5f.txt') as f:
    print(f.read())
# 0.00000 1.00000 2.00000
# 3.00000 4.00000 5.00000

dは整数。

np.savetxt('data/temp/np_savetxt_d.txt', a, fmt='%d')

with open('data/temp/np_savetxt_d.txt') as f:
    print(f.read())
# 0 1 2
# 3 4 5

xは16進数表記。ゼロ埋めも可能。04は全体で4桁、残りを0で埋める、という意味。説明のため10倍して保存します。

print(a * 10)
# [[ 0 10 20]
#  [30 40 50]]

np.savetxt('data/temp/np_savetxt_x.txt', a * 10, fmt='%04x')

with open('data/temp/np_savetxt_x.txt') as f:
    print(f.read())
# 0000 000a 0014
# 001e 0028 0032

16進数表記はnp.loadtxt()ではそのまま読み込めないので再びNumPyで使うような場合は避けたほうがよい。 そのほかフォーマットの詳細は公式ドキュメントを参照。

numpy.savetxt — NumPy v1.15 Manual

区切り文字(デリミタ)を指定: 引数delimiter

np.loadtxt()を同じく、np.savetxt()でもデフォルトでは区切り文字(デリミタ)がスペース' 'となります。 引数delimiterで任意の区切り文字を指定可能。 CSV(カンマ区切り)として保存したい場合はdelimiter=','、TSV(タブ区切り)として保存したい場合はdelimiter='\t'とすればよい。

np.savetxt('data/temp/np_savetxt.csv', a, delimiter=',', fmt='%d')

with open('data/temp/np_savetxt.csv') as f:
    print(f.read())
# 0,1,2
# 3,4,5


np.savetxt('data/temp/np_savetxt.tsv', a, delimiter='\t', fmt='%d')

with open('data/temp/np_savetxt.tsv') as f:
    print(f.read())
# 0 1   2
# 3 4   5

出力できるのは一次元配列と二次元配列のみ

np.savetxt()で出力できるのは一次元配列と二次元配列のみ。三次元以上の配列はエラーとなります。

a_3d = np.arange(24).reshape(2, 3, 4)
print(a_3d)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]
#
#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

# np.savetxt('data/temp/np_savetxt_3d.txt', a_3d)
# ValueError: Expected 1D or 2D array, got 3D array instead

三次元以上の配列はflatten()やreshape()で二次元以下に変換する必要があります。 バイナリファイルで保存すればデータ型や形状がそのまま保持されるので、テキストファイルにこだわらなければそちらのほうが簡単。

pandasを利用した読み書き(入出力)

DataFrameはpd.read_csv()関数とDataFrameのto_csv()メソッドでCSVファイルの読み書きが可能。ヘッダー(見出し行)がついたデータなどをより簡単に処理できます。 NumPyのndarrayとpandasのDataFrameは相互に変換可能なので、pandasを経由して処理できます。

また、pandasではExcelのファイルの読み書きもできます。

見出し行・列が付いたCSVファイルの処理

以下のCSVファイルを例とします。

import numpy as np
import pandas as pd

with open('data/src/sample_header_index.csv') as f:
    print(f.read())
# ,a,b,c,d
# ONE,11,12,13,14
# TWO,21,22,23,24
# THREE,31,32,33,34

pd.read_csv()では、デフォルトで1行目が見出し行、引数index_colで指定した列が見出し列として読み込まれる。

df = pd.read_csv('data/src/sample_header_index.csv', index_col=0)
print(df)
#         a   b   c   d
# ONE    11  12  13  14
# TWO    21  22  23  24
# THREE  31  32  33  34

ndarrayとして取得したい場合はDataFrameのvalues属性を使います。

a = df.values

print(a)
# [[11 12 13 14]
#  [21 22 23 24]
#  [31 32 33 34]]

print(type(a))
# <class 'numpy.ndarray'>

ndarrayに見出し行・列を付けて保存したい場合は、コンストラクタの引数index, columnsを指定してDataFrameを生成してからto_csv()で書き込む。

a = np.arange(6).reshape(2, 3)
print(a)
# [[0 1 2]
#  [3 4 5]]

df = pd.DataFrame(a, index=['ONE', 'TWO'], columns=['a', 'b', 'c'])
print(df)
#      a  b  c
# ONE  0  1  2
# TWO  3  4  5

df.to_csv('data/temp/sample_pd.csv')

with open('data/temp/sample_pd.csv') as f:
    print(f.read())
# ,a,b,c
# ONE,0,1,2
# TWO,3,4,5

欠損値の処理

以下のCSVファイルを例とします。

with open('data/src/sample_nan.csv') as f:
    print(f.read())
# 11,12,,14
# 21,,,24
# 31,32,33,34

pd.read_csvでは特に何も設定しなくても欠損値はnanとして扱われる。なお、上述のように、デフォルトで1行目が見出し行(ヘッダー)として処理されるため、この例のように見出し行がない場合は引数headerをNoneとします。

df = pd.read_csv('data/src/sample_nan.csv', header=None)
print(df)
#     0     1     2   3
# 0  11  12.0   NaN  14
# 1  21   NaN   NaN  24
# 2  31  32.0  33.0  34

pandasにおける欠損値の処理については以下の記事を参照。

異なるデータ型の処理

以下のCSVファイルを例とします。

with open('data/src/sample_pandas_normal.csv') as f:
    print(f.read())
# name,age,state,point
# Alice,24,NY,64
# Bob,42,CA,92
# Charlie,18,CA,70
# Dave,68,TX,70
# Ellen,24,CA,88
# Frank,30,NY,57

DataFrameはndarrayと異なり各列ごとにデータ型を持つ。pd.read_csv()ではデフォルトでそれぞれの列のデータ型が推測され自動的に設定される。

df = pd.read_csv('data/src/sample_pandas_normal.csv')
print(df)
#       name  age state  point
# 0    Alice   24    NY     64
# 1      Bob   42    CA     92
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 4    Ellen   24    CA     88
# 5    Frank   30    NY     57

print(df.dtypes)
# name     object
# age       int64
# state    object
# point     int64
# dtype: object

pandasにおけるデータ型については以下の記事を参照。

DataFrameのselect_dtypes()メソッドで任意のデータ型の列を抽出できます。

print(df.select_dtypes('int'))
#    age  point
# 0   24     64
# 1   42     92
# 2   18     70
# 3   68     70
# 4   24     88
# 5   30     57

以下のように、文字列などの余分なデータを含んだCSVファイルから数値の列のみを抽出してndarrayとして読み込むことが可能。

a = pd.read_csv('data/src/sample_pandas_normal.csv').select_dtypes('int').values

print(a)
# [[24 64]
#  [42 92]
#  [18 70]
#  [68 70]
#  [24 88]
#  [30 57]]

print(type(a))
# <class 'numpy.ndarray'>

print(a.dtype)
# int64

シェア

関連カテゴリー

Python NumPy CSV

NumPy配列ndarrayの次元をEllipsis(...)で省略して指定 NumPyのarange, linspaceの使い方(連番や等差数列を生成) NumPy配列ndarrayの対角成分の抽出、対角行列の作成(diag, diagonal) NumPyの配列ndarrayの欠損値np.nanを他の値に置換 NumPy配列ndarrayを結合(concatenate, stack, blockなど) NumPyのファンシーインデックス(リストによる選択と代入) 『Python Data Science Handbook』(英語の無料オンライン版あり) pandas参考書『Python for Data Analysis, 2nd Edition』 Pythonで正規化・標準化(リスト、NumPy配列、pandas.DataFrame) Pythonでコンマの後に空白があるcsvを読むときは注意 NumPyで欠損値np.nanを含む配列ndarrayの合計や平均を算出 NumPyで空の配列ndarrayを生成するemptyとempty_like pandasからNumPyの関数などを使う方法(pd.np) NumPyのバージョンを確認(np.version) NumPy配列ndarrayの次元数、形状、サイズ(全要素数)を取得

Last Updated: 6/26/2019, 10:34:03 PM