【Pythonのデータ読み込み】Excelのすゝめ

## 目次
- [はじめに](#はじめに)
- [なぜExcelか](#なぜexcelか)
- [モジュール紹介](#モジュール紹介)
- [Excelを読み込もう！](#excelを読み込もう)
- [実際の活用](#実際の活用)
   - [各行を取り出す](#各行を取り出す) 
   - [各列を取り出す](#各列を取り出す)
- [まとめ](#まとめ)
- [最後に](#最後に)

## はじめに
　Pythonのソースコード内に、リストでデータを書き込むのをやめたくらいの初心者は、次にテキストファイルから読み込むことを行うのではないでしょうか？もちろんこれは良いアプローチです。ソースコード内に、万里の長城のようなリストを鎮座させるよりも、遥かに優れています。しかし、単語帳ツールなどを制作している方は、現在進行形で実感しているかもしれませんが、英語用、日本語用など複数ファイルに跨る場合には、少し扱いづらいです。これを解決するために、一つのファイル内で区切り文字を増やす等している方も、いらっしゃるかも知れませんね（要はCSVファイルですが）。いずれにせよ、Excelを用いることで、より快適にデータの管理が行えるので、ここで共有したいと思います。

## なぜExcelか
　本題に入る前に、Excelを使うメリットについてお話します。Excelを使うメリットとしては、一つのファイルで管理が可能な点と、表形式になっている点が挙げられます。2つのテキストファイルで管理するのに比べて、データ入力のしやすさ、行の挿入や削除のしやすさが明確な強みと言えます。また、CSVファイルとの差別化としては、項目に文章が含まれる等、1行で収まらない場合の見易さが挙げられます。Excel独自の関数や機能を使うことができる点も、うれしいポイントです。あとは入力しなくても、空白のセルは```None```の扱いになってくれる点、```True```や```False```が扱える点も便利です。
 
## モジュール紹介
　標準ライブラリでExcelを扱うものはないので、```openpyxl```というモジュールを使います。```pip install openpyxl```でpipできたはずです。ちゃんとpipできたかは```pip list```で確認できます。
　＊この記事はデータの読み込みにフォーカスを当てているので、openpyxlの基本を網羅したものではありません。そういった内容はこちらの記事に詳しくまとまっていました。
 [pythonのopenpyxlの使い方メモ](https://qiita.com/sky_jokerxx/items/dc9d8827d946b467ba4b)
 
　このモジュールを使用する際の注意点なのですが、Excelファイルを開いたままプログラムを起動すると、```PermissionError: [Errno 13] Permission denied: 'example.xlsx'```と怒られます。ただ、大学のPCで同じプログラムを動かした際はエラーが出なかったので、何かトリガーがあるのかも知れません。
## Excelを読み込もう！
```python:test.py
from openpyxl import Workbook, load_workbook
my_list = []
wb = load_workbook('example.xlsx', read_only = True, data_only = True)
sheets = [i for i in wb]
for sheet in sheets:
    for row in sheet:
        for cell in row:
            my_list.append(cell)
```
　とりあえず、これでExcelから1つずつセルの中身を取ってくることはできます。forループのところを見てもらえれば分かると思いますが、シート、行、セルの三次元配列として、Excelを扱えるということですね。
　```data_only```を```True```にしておくと、Excel内で関数を使った際に、その結果を取ってきてくれるので、意図した結果が得られると思います。```read_only```に関してですが、今回は読み込むだけなので、```True```としています。必ずしもする必要はありません。次の項目で紹介するコードについても同様です。
 ## 実際の活用
　念のため書いておくと、行が横（数字）で、列が縦（アルファベット）です。
### 各行を取り出す
```python:test.py
from openpyxl import Workbook, load_workbook
my_list =[]
my_dict = {}
wb = load_workbook('example.xlsx', read_only = True, data_only = True)
sheets = [i for i in wb]
index = 0    #任意のインデックス
sheet = sheets[index]
for row in list(sheet)[1:]:    #シートの2行目から
    this_row = [cell.value for cell in row]
    my_list.append(this_row)
    my_dict.update({this_row[0]:this_row[1:]})#1列目をキーとする
```
　各シートの1行目は、なんの値を入れる列か見出しをつけるのに使うと思うので、スライス表記を用いて2行目から取り出しています。また、スライス表記を使うにあたって、```sheet```をリスト型に変換しています。スライス表記はめっちゃ便利なので、別途記事を書くかも知れません。話を戻すと、このコードでは、各行を2次元リストや辞書にしています。筆者は、RPG作成でExcelから辞書に変換するため、実際に使っています。その際、前回の記事で紹介した```namedtuple```も組み合わせているので、こちらの記事もぜひ読んでみて欲しいです！
[valueを複数持つ辞書を、より便利に作りたい](https://qiita.com/Prosamo/items/9afe1602cab1a5396ec2)
### 各列を取り出す
```python:test.py
from openpyxl import Workbook, load_workbook
wb = load_workbook('example.xlsx', read_only = True, data_only = True)
sheets = [i for i in wb]
index = 0    #任意のインデックス
sheet = sheets[index]
my_list = []
for column in range(0, sheet.max_column):        
    this_column = [row[column].value for row in list(sheet)[1:]]    #シートの二行目から
    my_list.append(this_column)
```
　これで1列ずつ読み込んで、任意の列の値をリストにすることができます。こちらも2行目から値を取得しているのと、そのためにスライス表記を使うにあたり、```sheet```をリスト型に変換しています。```sheet.max_column```で、シート内に何列存在するかが分かるので、その回数だけループを回しています。空白のセルはNoneの扱いになってくれるので、行ごとに列数が違っても、ループを回す回数は考慮しなくて良いです。

## まとめ
　Excelを使うことで、単にテキストファイルやCSVファイルを使うより、快適にデータ入力ができる。目的に応じて行を取り出したり、列を取り出したり、使い分けが容易である。

## 最後に
　長々と書きましたが、ここまで読んでくださりありがとうございました。RPGを作っていて思うのですが、やはり各テーブル同士で参照が多かったり、大規模なデータを扱う際は、データベース言語を使った方が良さそうですね。ただし、Excelは使いやすさと分かりやすさの点で優れていると思うので、特定の場面ではその性能を遺憾なく発揮してくれると感じました。