pythonでのcsvファイルの読み込み


# はじめに
csvファイルを読み込みたいときは多々あると思います。
pythonでのcsvファイルの読み込み方。また、読み込んだデータの扱い方についてまとめていきます。

# 注意
この記事の中で読み込むCSVファイルは、以下のファイルとします。
ファイル名「TEST_STOCK.csv」。

```text:TEST_STOCK.csv
コード,銘柄名,市場,始値,高値,安値,終値,出来高,売買代金
8111-T,Gウイン,東証1部,249.00,251.00,248.00,249.00,104000,25907000
8112-T,東スタイル,東証1部,1299.00,1319.00,1292.00,1312.00,132000,172590000
8113-T,ユニチャーム,東証1部,7100.00,7150.00,7020.00,7040.00,163500,1159842000
8114-T,デサント,東証1部,604.00,611.00,604.00,610.00,47000,28620000
8126-J,三光薬,JQ,324.00,324.00,322.00,322.00,4000,1294000
8127-T,ヤマトインタ,東証2部,1001.00,1019.00,1001.00,1019.00,800,810000
```

# csv
まずは、pythonの標準ライブラリのcsvを使用してみます。

## 読み込み
csvを使用してcsvファイルを読み込むには以下のようにします。

```py
import csv

csv_file = open("./TEST_STOCK.csv", "r", encoding="ms932")
#リスト形式
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
辞書形式
f = csv.DictReader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)

# もろもろの処理の後、close
csv_file.close()
```
このコードでは、csvファイルをopen関数で読み込みファイルオブジェクトを作成して、そのファイルオブジェクトをcsv.readerに読み込ませています。

## こんなエラーが発生するかも
実行したときに、以下のようなエラーが発生する人もいるかもしれません。
```py
AttributeError: module 'csv' has no attribute 'reader'
```
このエラーが発生したときは、csvライブラリが読み込まれていません。だいたい、自身がテスト実行しているpythonファイルのファイル名が「csv.py」になっているとかが原因なので、ファイル名を修正してやれば実行できます。

## open使用時の注意
openを使用した場合は、必ずcloseしましょう。
しなくても、ガベージコレクションによってcloseされますが、closeされるか分からないので、予期しない動きになることがあります。
使用するタイミングが終わるとcloseするのが基本的なお作法になります。
ただ、closeするのを忘れることも多いかと思います。なので、openを使用するときは以下のようにwithを使用すると良いです。
withを使用すると、そのブロックが終了すると自動的にcloseを実施してくれます。

```py
import csv

with open("./TEST_STOCK.csv", "r", encoding="ms932") as csv_file
    #リスト形式
    f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
    #辞書形式
    f = csv.DictReader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
```


## 各メソッドの説明
各メソッドの引数でよく使用すると思われるものをピックアップしてメモっておきます。

### open

|引数名|説明|
|:-----------|:------------|
|mode|どのようにファイルを読み込むのか指定する。<br>’r’(読み込み用に開く。CSV読み込みならこの指定。) <br>'w'(書き込み用に開き、まずファイルを切り詰める。)<br>'x'(排他的な生成に開き、ファイルが存在する場合は失敗する。)<br>'a'(書き込み用に開き、ファイルが存在する場合は末尾に追記する。)|
|encoding|CSVファイルの文字コードを指定する。例）ms932, utf_8|
|newline| universal newlines モードの動作を制御します。None, '', '\n', '\r', '\r\n' の指定が可能。|

### csv.reader or csv.DictReader
csv.reader、csv.DictReaderの違いは、返却される型です。ともに、イテレータ(iterator)プロトコルに対応したオブジェクトを返却しますが、CSVファイルの行の表現は、csv.readerはリスト型、csv.DictReaderは辞書型になります。
また、以下のパラメータは、厳密にいうと Dialect クラスの属性になります。

|引数名|説明|デフォルト|
|:-----------|:------------|:------------|
|delimiter|フィールド間を分割するのに使用する文字。|','(カンマ)|
|doublequote|フィールド内のquotecharがその文字自身である場合どのようにクオートするか。True の場合、この文字は二重化。 False の場合、 escapechar は quotechar の前に置かれます。|True|
|escapechar|エスケープ用の文字列をしてします。読み込み時、escapechar はそれに引き続く文字の特別な意味を取り除きます。|None|
|lineterminator|writerを使用する際に、各行の終端を表すのに使用する文字。readerでは、'\r' または '\n' を終端とするようにハードコードされているので関係ない。|'\r\n'|
|quotechar|delimiter や quotechar といった特殊文字を含むか、改行文字を含むフィールドをクオートする際に用いられる 1 文字からなる文字|'"'|
|skipinitialspace|True の場合、 delimiter の直後に続く空白は無視されます。|False|

## データの抽出方法
### csv.reader 
csv.reader で返却されるオブジェクトでのデータの抽出方法です。
イテレータ(iterator)プロトコルに対応したオブジェクトなのでfor文やnextで行データを取得することが可能です。
行データはリストなのでインデックスでアクセスできます。

```py
f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
header = next(f)
print(header)
for row in f:
    #rowはList
    #row[0]で必要な項目を取得することができる
    print(row)
```

```text:出力
['コード', '銘柄名', '市場', '始値', '高値', '安値', '終値', '出来高', '売買代金']
['8111-T', 'Gウイン', '東証1部', '249.00', '251.00', '248.00', '249.00', '104000', '25907000']
['8112-T', '東スタイル', '東証1部', '1299.00', '1319.00', '1292.00', '1312.00', '132000', '172590000']
['8113-T', 'ユニチャーム', '東証1部', '7100.00', '7150.00', '7020.00', '7040.00', '163500', '1159842000']
['8114-T', 'デサント', '東証1部', '604.00', '611.00', '604.00', '610.00', '47000', '28620000']
['8126-J', '三光薬', 'JQ', '324.00', '324.00', '322.00', '322.00', '4000', '1294000']
['8127-T', 'ヤマトインタ', '東証2部', '1001.00', '1019.00', '1001.00', '1019.00', '800', '810000']
```

### csv.DictReader
csv.DictReader で返却されるオブジェクトでのデータの抽出方法です。
csv.readerの場合と同じく、イテレータ(iterator)プロトコルに対応したオブジェクトで返却されます。違うところは、行データが辞書型で表現されている点で、カラム名を指定して取得することができます。

```py
f = csv.DictReader(csv_file)
for row in f:
    #rowはdictionary
    #row["column_name"] or row.get("column_name")で必要な項目を取得することができる
    print(row)
```

```text:出力
OrderedDict([('コード', '8111-T'), ('銘柄名', 'Gウイン'), ('市場', '東証1部'), ('始値', '249.00'), ('高値', '251.00'), ('安値', '248.00'), ('終値', '249.00'), ('出来高', '104000'), ('売買代金', '25907000')])
OrderedDict([('コード', '8112-T'), ('銘柄名', '東スタイル'), ('市場', '東証1部'), ('始値', '1299.00'), ('高値', '1319.00'), ('安値', '1292.00'), ('終値', '1312.00'), ('出来高', '132000'), ('売買代金', '172590000')])
OrderedDict([('コード', '8113-T'), ('銘柄名', 'ユニチャーム'), ('市場', '東証1部'), ('始値', '7100.00'), ('高値', '7150.00'), ('安値', '7020.00'), ('終値', '7040.00'), ('出来高', '163500'), ('売買代金', '1159842000')])
OrderedDict([('コード', '8114-T'), ('銘柄名', 'デサント'), ('市場', '東証1部'), ('始値', '604.00'), ('高値', '611.00'), ('安値', '604.00'), ('終値', '610.00'), ('出来高', '47000'), ('売買代金', '28620000')])
OrderedDict([('コード', '8126-J'), ('銘柄名', '三光薬'), ('市場', 'JQ'), ('始値', '324.00'), ('高値', '324.00'), ('安値', '322.00'), ('終値', '322.00'), ('出来高', '4000'), ('売買代金', '1294000')])
OrderedDict([('コード', '8127-T'), ('銘柄名', 'ヤマトインタ'), ('市場', '東証2部'), ('始値', '1001.00'), ('高値', '1019.00'), ('安値', '1001.00'), ('終値', '1019.00'), ('出来高', '800'), ('売買代金', '810000')])
```

# pandas
続いて使用してみるのは、pandasです。
pandasとは、データ分析用のライブラリです。データ分析のためのライブラリなので、データの取得に関しては専門ではありませんが、pandasで読み込んだデータはDataFrameオブジェクトとして読み込まれ読み込んだ後の操作がしやすいので少し紹介してみます。

## 読み込み

```py
import pandas as pd
csv_input = pd.read_csv(filepath_or_buffer="D:\株価情報CSV\TEST_STOCK.csv", encoding="ms932", sep=",")
```

## こんなエラーが発生するかも
実行するとこんなエラーが発生するかもしれません。
その場合は、引数に「engine="python"」を追加してください。するとエラーが出なくなります。
エラー自体は、ファイルのパス名（ファイル名かフォルダ）に日本語（たぶんマルチバイト文字）を含む場合に発生するようです。原因はよくわかりません。

```py
OSError: Initializing from file failed
```

## メソッドの説明
メソッド（read_csv）の引数でよく使用すると思われるものをピックアップしてメモっておきます。

### read_csv

|引数名|説明|デフォルト|
|:-----------|:------------|:------------|
|filepath_or_buffer|ファイルパスやreadメソッドをもったオブジェクトを指定します。|None|
|sep |区切り文字です。|','|
|delimiter| 区切り文字。sep の代わりに delimiterでも区切り文字を指定可能。|None|
|encoding|CSVファイルの文字コードを指定する。例）ms932, utf_8|None|
|escapechar|エスケープ用の文字列をしてします。読み込み時、escapechar はそれに引き続く文字の特別な意味を取り除きます。|None|
|quotechar|delimiter や quotechar といった特殊文字を含むか、改行文字を含むフィールドをクオートする際に用いられる 1 文字からなる文字|'"'|

## データの抽出方法
pandasを使用してCSVファイルを読み込んだ場合、DataFrameオブジェクトが返却されます。
DataFrameオブジェクトは、２次元の表データを表現しています。列方向の見出しを列ラベル、行方向の見出しを行ラベルと呼びます。
DataFrameオブジェクトには、データを抽出する様々な方法が準備されています。その中で便利だなと思う方法を紹介していきます。

### 基本
```py
import pandas as pd
csv_input = pd.read_csv(filepath_or_buffer="D:\株価情報CSV\TEST_STOCK.csv", encoding="ms932", sep=",")
# インプットの項目数（行数 * カラム数）を返却します。
print(csv_input.size)
# 指定したカラムだけ抽出したDataFrameオブジェクトを返却します。
print(csv_input[["コード", "銘柄名"]]) 
```
```text:実行結果
54
      コード     銘柄名
0  8111-T    Gウイン
1  8112-T   東スタイル
2  8113-T  ユニチャーム
3  8114-T    デサント
4  8126-J     三光薬
5  8127-T  ヤマトインタ
```

### value
```py
#値を二次元配列形式?で返却します。
#返却される型は、numpy.ndarray
print(csv_input.values)
#行インデックス、カラムインデックスの順番で指定して項目の値を取得できます。
print(csv_input.values[0, 1])
```

```text:実行結果
[['8111-T' 'Gウイン' '東証1部' 249.0 251.0 248.0 249.0 104000 25907000]
 ['8112-T' '東スタイル' '東証1部' 1299.0 1319.0 1292.0 1312.0 132000 172590000]
 ['8113-T' 'ユニチャーム' '東証1部' 7100.0 7150.0 7020.0 7040.0 163500 1159842000]
 ['8114-T' 'デサント' '東証1部' 604.0 611.0 604.0 610.0 47000 28620000]
 ['8126-J' '三光薬' 'JQ' 324.0 324.0 322.0 322.0 4000 1294000]
 ['8127-T' 'ヤマトインタ' '東証2部' 1001.0 1019.0 1001.0 1019.0 800 810000]]
Gウイン
```

### 先頭から、後ろから
```py
#頭から指定行数分取得
#返却される型は、pandas.core.frame.DataFrame
print(csv_input.head(3))

#後ろから指定行数分取得
#返却される型は、pandas.core.frame.DataFrame
print(csv_input.tail(3))
```

```text:実行結果
      コード     銘柄名    市場      始値      高値      安値      終値     出来高        売買代金
0  8111-T    Gウイン  東証1部   249.0   251.0   248.0   249.0  104000    25907000
1  8112-T   東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000   172590000
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000

      コード     銘柄名    市場      始値      高値      安値      終値    出来高      売買代金
3  8114-T    デサント  東証1部   604.0   611.0   604.0   610.0  47000  28620000
4  8126-J     三光薬    JQ   324.0   324.0   322.0   322.0   4000   1294000
5  8127-T  ヤマトインタ  東証2部  1001.0  1019.0  1001.0  1019.0    800    810000
```

### DataFrame情報
```py
#行数を確認
print(len(csv_input))

#カラム数を確認
print(len(csv_input.columns))

#次元の確認
print(csv_input.shape)
```

```text:実行結果
6
9
(6, 9)
```

### カラム情報
```py
#カラム情報
print(csv_input.columns)
print(csv_input.columns[3])
```

```text：実行結果
Index(['コード', '銘柄名', '市場', '始値', '高値', '安値', '終値', '出来高', '売買代金'], dtype='object')
始値
```

### データアクセスいろいろ
```py
#データアクセスの方法いろいろ
#loc[rows, columns]
#全行選択の場合、rowsは「:」を指定
print(csv_input.loc[:,["始値", "終値"]])
print(csv_input.loc[1:2,["始値", "終値"]]) #2行目3行目

#iloc[rows番号, columns番号]
#全行選択の場合、rowsは「:」を指定
#インデックスの指定方法に注意
print(csv_input.iloc[:, 3])　#3カラム目を全行
print(csv_input.iloc[0:3, 3:5]) #3,4カラム目だけを1行～3行目まで抽出

#ix
#カラム名、カラム番号のどちらでも使用可能
print(csv_input.ix[0:3, ["始値", "終値", "安値"]]) #1行目～4行目
print(csv_input.ix[0:3, 3:6]) #1行目～3行目
```

```text：実行結果
       始値      終値
0   249.0   249.0
1  1299.0  1312.0
2  7100.0  7040.0
3   604.0   610.0
4   324.0   322.0
5  1001.0  1019.0

始値      終値
1  1299.0  1312.0
2  7100.0  7040.0

0     249.0
1    1299.0
2    7100.0
3     604.0
4     324.0
5    1001.0

       始値      高値
0   249.0   251.0
1  1299.0  1319.0
2  7100.0  7150.0

       始値      終値      安値
0   249.0   249.0   248.0
1  1299.0  1312.0  1292.0
2  7100.0  7040.0  7020.0
3   604.0   610.0   604.0

　　始値      高値      安値
0   249.0   251.0   248.0
1  1299.0  1319.0  1292.0
2  7100.0  7150.0  7020.0
3   604.0   611.0   604.0
```

### データの抽出
```py
#指定した条件で抽出します
print(csv_input[csv_input["出来高"] > 100000])
#複数条件を組み合わせたい場合
#and条件は「&」を使用
print(csv_input[(csv_input["出来高"] > 100000) & (csv_input["終値"] >= csv_input["始値"])])
#or条件は「|」を使用
print(csv_input[(csv_input["出来高"] > 100000) | (csv_input["終値"] >= csv_input["始値"])])
#抽出条件には、以下のような指定方法もあります。
print(csv_input.query("出来高 > 100000"))
#複数の値を指定する
print(csv_input[(csv_input["銘柄名"].isin(["ユニチャーム", "デサント"]))])
```

```text:実行結果
      コード     銘柄名    市場      始値      高値      安値      終値     出来高        売買代金
0  8111-T    Gウイン  東証1部   249.0   251.0   248.0   249.0  104000    25907000
1  8112-T   東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000   172590000
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000

      コード    銘柄名    市場      始値      高値      安値      終値     出来高       売買代金
0  8111-T   Gウイン  東証1部   249.0   251.0   248.0   249.0  104000   25907000
1  8112-T  東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000  172590000

      コード    銘柄名    市場      始値      高値      安値      終値     出来高       売買代金
0  8111-T    Gウイン  東証1部   249.0   251.0   248.0   249.0  104000    25907000
1  8112-T   東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000   172590000
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000
3  8114-T    デサント  東証1部   604.0   611.0   604.0   610.0   47000    28620000
5  8127-T  ヤマトインタ  東証2部  1001.0  1019.0  1001.0  1019.0     800      810000

      コード     銘柄名    市場      始値      高値      安値      終値     出来高        売買代金
0  8111-T    Gウイン  東証1部   249.0   251.0   248.0   249.0  104000    25907000
1  8112-T   東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000   172590000
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000

      コード     銘柄名    市場      始値      高値      安値      終値     出来高        売買代金
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000
3  8114-T    デサント  東証1部   604.0   611.0   604.0   610.0   47000    28620000
```

### 列の追加
```py
csv_input["追加カラム"] = ["TEST1", "TEST2", "TEST3", "TEST4", "TEST5", "TEST6"]
print(csv_input)
```

```py
      コード     銘柄名    市場      始値      高値      安値      終値     出来高        売買代金  追加カラム  
0  8111-T    Gウイン  東証1部   249.0   251.0   248.0   249.0  104000    25907000   TEST1  
1  8112-T   東スタイル  東証1部  1299.0  1319.0  1292.0  1312.0  132000   172590000   TEST2  
2  8113-T  ユニチャーム  東証1部  7100.0  7150.0  7020.0  7040.0  163500  1159842000   TEST3  
3  8114-T    デサント  東証1部   604.0   611.0   604.0   610.0   47000    28620000   TEST4  
4  8126-J     三光薬    JQ   324.0   324.0   322.0   322.0    4000     1294000   TEST5  
5  8127-T  ヤマトインタ  東証2部  1001.0  1019.0  1001.0  1019.0     800      810000   TEST6  
```


以上。CSV読み込み以外のところにも結構触れましたが、私が忘れないためにも記述しておきます。