記事とコードは [Github ウェアハウス: https://github.com/timerring/dive-into-AI] にアーカイブされているか、[AIShareLab] のpython データ分析への返信も利用できます。
記事ディレクトリ
ファイルとオペレーティング システム
コード例では、ほとんどの場合、ディスク上のデータ ファイルを Python データ構造に読み込むpandas.read_csv
など。しかし、Python のファイル処理に関するいくつかの基本を知る必要があります。
読み書き用にファイルを開くには、組み込みの open 関数を相対または絶対ファイル パスで使用します。
In [207]: path = 'examples/segismundo.txt'
In [208]: f = open(path)
デフォルトでは、ファイルは読み取り専用モード ('r') で開かれます。次に、行を反復するなど、このファイルハンドル f をリストのように処理できます。
for line in f:
pass
行は完全な行末 (EOL) でファイルからフェッチされるため、次のようなコードがよく見られます (EOL なしで一連の行を取得します)。
In [209]: lines = [x.rstrip() for x in open(path)]
In [210]: lines
Out[210]:
['Sueña el rico en su riqueza,',
'que más cuidados le ofrece;',
'',
'sueña el pobre que padece',
'su miseria y su pobreza;',
'',
'sueña el que a medrar empieza,',
'sueña el que afana y pretende,',
'sueña el que agravia y ofende,',
'',
'y en el mundo, en conclusión,',
'todos sueñan lo que son,',
'aunque ninguno lo entiende.',
'']
open を使用してファイル オブジェクトを作成する場合は、必ず close で閉じてください。ファイルを閉じると、オペレーティング システムのリソースが返される場合があります。
In [211]: f.close()
with ステートメントを使用すると、開いているファイルをより簡単にクリーンアップできます。
In [212]: with open(path) as f:
.....: lines = [x.rstrip() for x in f]
これにより、コード ブロックを終了するときにファイルが自動的に閉じられます。
f =open(path,'w') と入力すると、examples/segismundo.txt に新しいファイルが作成され、その場所にある以前のデータが上書きされます。書き込み可能なファイルを作成する xfile モードもありますが、ファイル パスが存在する場合は作成に失敗します。表 3-3 に、すべての読み取り/書き込みモードを示します。
読み取り可能なファイルの場合、いくつかの一般的な方法は read、seek、および tell です。read はファイルから文字を返します。文字の内容は、ファイルのエンコーディング (UTF-8 など) によって決まります。バイナリ モードで開いた場合は、元のバイトになります。
In [213]: f = open(path)
In [214]: f.read(10)
Out[214]: 'Sueña el r'
In [215]: f2 = open(path, 'rb') # Binary mode
In [216]: f2.read(10)
Out[216]: b'Sue\xc3\xb1a el '
読み取りモードは、読み取ったバイト数だけファイルハンドルの位置を進めます。tell は現在の場所を与えることができます:
In [217]: f.tell()
Out[217]: 11
In [218]: f2.tell()
Out[218]: 10
ファイルから 10 文字を読み取りましたが、位置は 11 です。これは、デフォルトのエンコーディングでこれらの 10 文字をデコードするのに非常に多くのバイトが必要だったためです。デフォルトのエンコーディングは sys モジュールで確認できます:
In [219]: import sys
In [220]: sys.getdefaultencoding()
Out[220]: 'utf-8'
seek は、ファイルの位置をファイル内の指定されたバイトに変更します。
In [221]: f.seek(3)
Out[221]: 3
In [222]: f.read(1)
Out[222]: 'ñ'
最後に、ファイルを閉じます。
In [223]: f.close()
In [224]: f2.close()
ファイルに書き込むには、ファイルの write または writelines メソッドを使用できます。たとえば、空白行のないバージョンの prof_mod.py を作成できます。
In [225]: with open('tmp.txt', 'w') as handle:
.....: handle.writelines(x for x in open(path) if len(x) > 1)
In [226]: with open('tmp.txt') as f:
.....: lines = f.readlines()
In [227]: lines
Out[227]:
['Sueña el rico en su riqueza,\n',
'que más cuidados le ofrece;\n',
'sueña el pobre que padece\n',
'su miseria y su pobreza;\n',
'sueña el que a medrar empieza,\n',
'sueña el que afana y pretende,\n',
'sueña el que agravia y ofende,\n',
'y en el mundo, en conclusión,\n',
'todos sueñan lo que son,\n',
'aunque ninguno lo entiende.\n']
表 3-4 に、最も一般的に使用されるファイル メソッドの一部を示します。
ファイルのバイト数と Unicode
Python ファイルのデフォルトの操作は「テキスト モード」です。つまり、Python 文字列 (つまり Unicode) を処理する必要があります。「バイナリモード」の逆で、ファイルモードに b を追加します。前のセクションのファイルを見てみましょう (非 ASCII 文字を含む UTF-8 エンコーディング):
In [230]: with open(path) as f:
.....: chars = f.read(10)
In [231]: chars
Out[231]: 'Sueña el r'
UTF-8 は可変長の Unicode エンコーディングであるため、ファイルから特定の数の文字を要求すると、Python はファイルから十分な (おそらく 10 バイトから 40 バイト程度の) バイトを読み取ってデコードします。ファイルが「rb」モードで開かれている場合、要求された正確なバイト数が読み取られます。
In [232]: with open(path, 'rb') as f:
.....: data = f.read(10)
In [233]: data
Out[233]: b'Sue\xc3\xb1a el '
テキストのエンコーディングに応じて、バイトを str オブジェクトにデコードできますが、エンコードされた各 Unicode 文字が完全に形成されている場合に限ります。
In [234]: data.decode('utf8')
Out[234]: 'Sueña el '
In [235]: data[:4].decode('utf8')
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
<ipython-input-235-300e0af10bb7> in <module>()
----> 1 data[:4].decode('utf8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 3: unexpecte
d end of data
テキスト モードは、open のエンコーディング オプションを組み合わせて、Unicode を別のエンコーディングに変換するためのより便利な方法を提供します。
In [236]: sink_path = 'sink.txt'
In [237]: with open(path) as source:
.....: with open(sink_path, 'xt', encoding='iso-8859-1') as sink:
.....: sink.write(source.read())
In [238]: with open(sink_path, encoding='iso-8859-1') as f:
.....: print(f.read(10))
Sueña el r
バイナリ モードでシークを使用しないでください。ファイルの位置が Unicode 文字を定義するバイトの中間にある場合、後で読み取るとエラーが発生します。
In [240]: f = open(path)
In [241]: f.read(5)
Out[241]: 'Sueña'
In [242]: f.seek(4)
Out[242]: 4
In [243]: f.read(1)
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
<ipython-input-243-7841103e33f5> in <module>()
----> 1 f.read(1)
/miniconda/envs/book-env/lib/python3.6/codecs.py in decode(self, input, final)
319 # decode input (taking the buffer into account)
320 data = self.buffer + input
--> 321 (result, consumed) = self._buffer_decode(data, self.errors, final
)
322 # keep undecoded input until the next call
323 self.buffer = data[consumed:]
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb1 in position 0: invalid s
tart byte
In [244]: f.close()
非 ASCII 文字テキストでデータ分析を頻繁に実行する必要がある場合は、Python の Unicode 関数に精通していることが非常に重要です。詳細については、Python の公式ドキュメントを参照してください。