Python School 2.0.0 documentation

ファイルを読み込む

«  CSV ファイルの処理方法   ::   Contents   ::   標準モジュール csv を使う  »

ファイルを読み込む

カンマ区切りのCSVファイルを読み込んで、データを処理してみます。 対象データとして、 株価データダウンロードサイト (k-db.com) から日経平均株価の日足を利用させて頂きます。

以下のデータ (csv-1.csv) は「日付,始値,高値,安値,終値」の並び順で、 6月第1週の日経平均株価です。

2014-06-06,15138.75,15144.34,15042.59,15077.24
2014-06-05,15112.59,15141.14,15016.81,15079.37
2014-06-04,15067.41,15071.78,14985.21,15067.96
2014-06-03,15089.04,15091.49,15026.01,15034.25
2014-06-02,14777.51,14963.91,14777.51,14935.92

列番号と配列インデックス、その内容は以下の表のようにまとめられます。

日経平均株価の日足データ
列番号 配列インデックス 内容 データ型
1 0 日付 文字列/日付
2 1 始値 小数
3 2 高値 小数
4 3 安値 小数
5 4 終値 小数

自力で実装する方法

Python の基本的な部分から学習するために、組み込みの機能だけで実装してみます。 open() でファイルを開き、イテレータを使って CSV 形式 (カンマ区切りテキスト) のファイルを読み込みます。 with を使うことでリソースリークなどを予防できます。 文字列から小数に変換するには float() を使い、小数点以下N桁で丸めるには round() を使います。

スクリプトファイルの構成 で作成したスクリプトテンプレートから csv-1.py を作ってみましょう。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Parse daily Tokyo stock prices.
"""

import argparse
import logging


def parse_args():
    """Parse arguments and set up logging verbosity.

    :rtype: parsed arguments as Namespace object.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--file", dest="filename",
                        help="setting file", metavar="FILE")
    parser.add_argument("-o", "--output", dest="output",
                        help="output file", metavar="FILE")
    parser.add_argument("-n", "--dryrun", dest="dryrun",
                        help="dry run", default=False, action="store_true")
    parser.add_argument("-v", "--verbose", dest="verbose", default=False,
                        action="store_true", help="verbose mode")
    parser.add_argument("-q", "--quiet", dest="quiet", default=False,
                        action="store_true", help="quiet mode")
    # Add this line from boilerplate.
    parser.add_argument("filename", nargs=1, help="CSV file path")

    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)
    elif not args.quiet:
        logging.basicConfig(level=logging.INFO)

    return args


def process(args):
    """Parse daily Tokyo stock prices, and calculate up/down.
    """
    with open(args.filename[0]) as fp:
        for line in fp:
            l = line.rstrip('\r\n')
            t = l.split(',')
            # Assign each field on individual variables.
            day = t[0]
            price_begin = float(t[1])
            price_max = float(t[2])
            price_min = float(t[3])
            price_end = float(t[4])
            # Calculate the differenciate of the day.
            diff = price_end - price_begin
            if diff > 0:
                message = 'up'
            elif diff < 0:
                message = 'down'
            else:
                message = 'same'
            # Write out day, up/down/same, and diff.
            print('{}\t{:5}\t{}'.format(day, message, round(diff, 2)))


def main():
    args = parse_args()
    process(args)


def test():
    pass

if __name__ == '__main__':
    main()

# vim: set et ts=4 sw=4 cindent fileencoding=utf-8 :

実行結果

$ python csv-1.py csv-1.csv
2014-06-06  down    -61.51
2014-06-05  down    -33.22
2014-06-04  up      0.55
2014-06-03  down    -54.79
2014-06-02  up      158.41

このスクリプトでは、入力データに意図しないカンマが混入した場合に想定外の出力となります。 たとえば、フランスでは小数点の区切り文字がカンマなので、数値をうまく分割できないでしょう。 このスクリプトを改善しても構いませんが、次からは標準モジュール csv を使っていきましょう。

そもそも CSV とは何か?

インターネットにおけるデータ交換方式、という観点からは RFC で規定されています。

  • RFC 4180 (Common Format and MIME Type for Comma-Separated Values (CSV) Files)

しかし、一般に広く普及している形式は Microsoft Excel が書き出す形式であり、 RFC 4180 と等価ではありません。 記号のエスケープルールや、暗黙的な型変換に違いがあります。

Comma-Separated Values - ja.wikipedia.org:
 レコードにコンマやダブルクォートが含まれている場合、エスケープされている場合でも、ソフトによって解釈が異なり、区切り方が変わることがある。 その結果、データが破壊されることや、修正の手間が生じることがある。 レコードにタブ文字が含まれている場合よりも、レコードにコンマやダブルクォートが含まれている場合のほうが多い。 従って、CSVの代わりに、タブ区切りテキスト形式(TSV)を使うことで問題を避けられることがある。

また、数値をダブルクォートで囲まない場合、小数点の記号と混同される地域もあります。 たとえば、Windows のパソコンでロケールをフランス語にして Excel を使うと、カンマが小数点の区切り文字になります。

小数点 - ja.wikipedia.org:
 また非英語圏の国においては、コンマ (,) が小数点として用いられ、ピリオド (.) が3桁ごとの位取りに用いられる。 すなわち、日本と逆である。

したがって、「CSV でデータをください」という話題が出た場合には注意しましょう。 一見簡単そうですが、細かい部分に違いがあります。 可能ならば JSON (RFC 4627) のように構造化されてデータ型に制限のあるフォーマットを検討してください。 人間が読み書きするデータとコンピュータが読み書きするデータは、処理の難易度が必ずしも等価でないことに気をつけましょう。

«  CSV ファイルの処理方法   ::   Contents   ::   標準モジュール csv を使う  »