逆引き DataFrameの入出力処理


さまざまなファイル形式に対する、DataFrameの読み込み/書き込み方法を紹介します。例によってこういうのでいいんだよ的なまとめなので、説明は少なめです。

サンプルコードでは`import pandas as pd`を省略しています。


# 逆引き用の分類

| ファイル形式           | 読み込み | 書き込み | 備考 |
|:----------------------|:-------------|:------------|:------------|
| **CSV**               | [pd.read_csv](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#csv%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)        | [pd.DataFrame.to_csv](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#csv%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF)         |
| **Excel (Pandas)**    | [pd.read_excel](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#excel%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BFpandas)      | [pd.DataFrame.to_excel](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#excel%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BFpandas)       |
| **Excel (xlwings)**   | [xw.Range.options(pd.DataFrame).value](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#excel%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BFxlwings)        | [xw.Range.options(pd.DataFrame).value](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#excel%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BFxlwings)        | [xlwingsとExcelのインストールが必要](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)|
| **MS Access**         | [pd.read_sql](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#ms-access%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)        | [pd.to_sql](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#ms-access%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF)           | [sqlalchemy、 sqlalchemy-access、 MS Accessのインストールが必要](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-1)|
| **Oracle**            | [pd.raad_sql](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#oracle%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)        | --       | [cx_Oracleのインストールが必要](https://qiita.com/k_maki/items/7e86b8314422cb4588f7#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-2) |



# CSVファイル
## CSVの読み込み

[pandas.read_csv](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)

一番基本的なもの。サンプルコードと主要な引数を説明します（以下同様）。

### シンタックス

**pandas.read_csv**(*filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression='infer', thousands=None, decimal='.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None*)


### サンプルコード

```python
df = pd.read_csv('data.csv', encoding='cp932')  # encoding=...としないと、Excelが出力したCSVファイルは文字化け
```

### 主な引数

よく使う引数は次のとおり（これ以外にももっとたくさんあります）。

| 引数 | 型 | 説明 |
|:-----------|:------------|:------------|
| **filepath_or_buffer**| *str, path object or file-like object* | ファイルパス。`Path`オブジェクトを使いましょう（解説は[こちら](https://note.nkmk.me/python-pathlib-usage/)）。|
| **header**     | *int, list of int, default ‘infer’* | デフォルトは、namesの指定がなければ1行目を、指定があればnamesを列名として使用。 数字で指定した場合、その行を列名にする。リスト([0,1,3]など)で指定すればマルチインデックスとなる。`skip_blank_lines=True`を指定した場合は空白行を飛ばして数える。|
| **names**      | *array-like, optional* | 列名のリスト。リスト要素の重複不可。ファイルにヘッダーが含まれる場合には`header`で指定すること。 |
| **index_col**  | *int, str, sequence of int / str, or False, default None* | インデックスとして使用する列名または列番号を指定。リストの場合、マルチインデックスになる。`index_cols=False`とすれば、最初の列をインデックスとしない。 |
| **usecols**    | *list-like or callable, optional* | 読み込みを一部の列に限定する際に使用。列名またはインデックスのリストで指定。列名を引数とする関数の場合は戻り値が`True`の列が読み込まれる（例： `lambda x: x.upper() in ['AAA', 'BBB', 'DDD']`）。 |
| **dtype**      | *Type name or dict of column -> type, optional* | 列のデータ型を指定。例：`{‘a’: np.float64, ‘b’: np.int32, ‘c’: ‘Int64’} `。`converters`の指定があれば無視される。 |
| **engine**     | *{‘c’, ‘python’}, optional* | パーサーのエンジン。**日本語のファイルを読み取る際は、** `engine='python`とすること。 |
| **converters** | *dict, optional* | 列の値に対する変換。列名または番号をキー、列の値を引数とする関数を値とする辞書で指定。 |
| **skiprows**   | *list-like, int or callable, optional* | 読み込み対象外とする行（0から数える） |
| **encoding**   | *str, optional* | 文字エンコード。Excelで開くなら`encoding='cp932`とすること。 |



## CSVの書き込み
[pandas.DataFrame.to_csv](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_csv.html)

### シンタックス

**DataFrame.to_csv**(*path_or_buf=None, sep=',', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, mode='w', encoding=None, compression='infer', quoting=None, quotechar='"', line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal='.', errors='strict'*)

### サンプルコード

```python
df.to_csv('data.csv', encoding='cp932') # encoding=...としないと、Excelが出力したCSVファイルは文字化け
```

### 主な引数

よく使う引数

| 引数 | 型 | 説明 |
|:-----------|:------------|:------------|
| **path_or_buf**  | *str or file handle, default None* | ファイルパス。`Path`オブジェクトを使いましょう（解説は[こちら](https://note.nkmk.me/python-pathlib-usage/)）。 |
| **header**       | *bool or list of str, default True* | ヘッダーの出力有無をboolで指定。文字列のリストの場合、そのリストが列名となる。 |
| **index**        | *bool, default True* | インデックスの出力有無をboolで指定。 |
| **encoding**     | *str, optional* | 文字エンコード。Excelで開くなら`encoding='cp932`とすること。 |


# Excelファイル（Pandasを使用）

## Excelの読み込み（Pandas）
[pandas.read_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html)


### シンタックス

**pandas.read_excel**(*io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, mangle_dupe_cols=True*)

### サンプルコード

1つのファイルから読み込むシートが複数の場合は`pd.ExcelFile`でファイルをまず読み込む。

```python
import xlwings as xw

# 1つのシートを読み込む場合
df = pd.read_excel('book.xlsx', 'Sheet1', header=0)

# 2つ以上のシートを読み込む場合
with pd.ExcelFile('book.xlsx') as xls:
    df1 = read_excel(xls, 'Sheet1', header=0)
    df2 = read_excel(xls, 'Sheet2', skiprows=1, header=0)
```

### 主な引数

| 引数 | 型 | 説明 |
|:-----------|:------------|:------------|
| **io** | *str, bytes, ExcelFile, xlrd.Book, path object, or file-like object* | ファイルパス。 `Path`オブジェクトを使いましょう（解説は[こちら](https://note.nkmk.me/python-pathlib-usage/)）。|
| **sheet_name** | *str, int, list, or None, default 0* | 読込対象シートを番号またはシート名（またはそれらのリスト）で指定。`None` はすべてのシートを取得。|
| **header** | *int, list of int, default 0* | デフォルトは0。数字で指定した場合、その行を列名にする。リスト([0,1,3]など)で指定すればマルチインデックスとなる。`skip_blank_lines=True`を指定した場合は空白行を飛ばして数える。|
| **names** | *array-like, default None* | 列名のリスト。リスト要素の重複不可。ファイルにヘッダーが含まれる場合には`header`で指定すること。 |
| **index_col** | *int, list of int, default None* | インデックスとして使用する列名または列番号を指定。リストの場合、マルチインデックスになる。`index_cols=False`とすれば、最初の列をインデックスとしない。 |
| **usecols** | *int, str, list-like, or callable default None* | 読み込みを一部の列に限定する際に使用。列名またはインデックスのリストで指定。列名を引数とする関数の場合は戻り値が`True`の列が読み込まれる（例： `lambda x: x.upper() in ['AAA', 'BBB', 'DDD']`）。 |
| **dtype** | *Type name or dict of column -> type, default None* | 列のデータ型を指定。例：`{‘a’: np.float64, ‘b’: np.int32, ‘c’: ‘Int64’} `。`converters`の指定があれば無視される。 |
| **converters** | *dict, default None* | 列の値に対する変換。列名または番号をキー、列の値を引数とする関数を値とする辞書で指定。 |
| **skip_rows** | *list-like* | 読み込み対象外とする行（0から数える） |


## Excelの書き込み（Pandas）
[pandas.DataFrame.to_excel](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_excel.html)

### シンタックス

**DataFrame.to_excel**(*excel_writer, sheet_name='Sheet1', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep='inf', verbose=True, freeze_panes=None*)

### サンプルコード

```python
import xlwings as xw

# 1つのファイルに1つのDataFrame
df2.to_excel('book2.xlsx','SHeet3', index=False, merge_cells=False)

# 1つのファイルに複数のDataFrame（ファイルは置き換え）
with pd.ExcelWriter('book3.xlsx') as writer:
    df1.to_excel(writer, 'Sheet1', index=False)
    df2.to_excel(writer, 'Sheet2', index=False)

# 1つのファイルに複数のDataFrame
# （公式に書いてあるmode='a'だとエラー「ValueError: Append mode is not supported with xlsxwriter!」）
with pd.ExcelWriter('book4.xlsx', mode='A') as writer:
    df1.to_excel(writer, 'Sheet1', index=False)
    df2.to_excel(writer, 'Sheet2', index=False)
```

### 主な引数

| 引数 | 型 | 説明 |
|:-----------|:------------|:------------|
| **sheet_name** | *str, default ‘Sheet1’* | 出力先シート。 |
| **columns** | *sequence or list of str, optional* | 出力対象列。 |
| **header** | *bool or list of str, default True* | ヘッダーの出力有無をboolで指定。文字列のリストの場合、そのリストが列名となる。 |
| **index** | *bool, default True* | インデックスの出力有無をboolで指定。 |
| **merge_cells** | *bool, default True* | マルチインデックス（行ラベルおよび列名）を結合セルで出力するかをboolで指定。 |

 

# Excelファイル（xlwingsを使用）

## インストール

以下をインストール

- Pythnパッケージ: [xlwings](https://pypi.org/project/xlwings/)
- その他アプリ: Excel （xlwingsはインストールが必須）

## Excelの読み込み（xlwings）
[xlwings Pandas DataFrameコンバーター](https://docs.xlwings.org/ja/latest/converters.html#pandas-dataframe-converter)

### シンタックス
- xw.Range : **xw.Range.options**(*pd.DataFrame, \*\*kwards*)**.value**
- UDFs     : **@xw.arg**(*'df', pd.DataFrame, \*\*kwards*)

### 主な引数

| 引数 | 型 | 説明 |
|:-----|:---|:-----|
| **index**  | *int or Boolean* | インデックスとする列の数を設定。 |
| **header** | *int or Boolean* | 列名の行数を設定。 |

### サンプルコード: セル範囲から
```python
import xlwings as xw

wb = xw.books.open('book.xlsx')
sh = wb.sheets('Sheet1')

# シート全体から取得
df = sh.used_range.options(pd.DataFrame, index=False).value
# アドレスを指定して取得
df = sh.range('A1:C4').options(pd.DataFrame, index=False).value
# 名前の定義も利用可
df = sh.range('named_range').options(pd.DataFrame, index=False).value
```

### サンプルコード: テーブル（ListObject）から
```python
import xlwings as xw

wb = xw.books.open('book.xlsx')
sh = wb.sheets('Sheet1')

# xlwings 0.21.0より前
df = sh.range(sh.api.ListObjects('テーブル1').Range.Address).options(pd.DataFrame, index=False).value
# xlwings 0.21.0以降
df = sh.tables('テーブル1').range.options(pd.DataFrame, index=False).value
```

### サンプルコード: UDFs

UDFsはPythonの関数をVBAから呼び出せるようにしたもの（説明は[こちら](https://qiita.com/k_maki/items/9efdb70f69d6f3b00f80)）。Windowsのみ利用可。Excelと連携する際は必須。まずはPython側でデコレーター付きの関数を定義。


```python
import xlwings as xw

@xw.func
@xw.arg('df', pd.DataFrame, index=False)
def my_xwfunc(df: pd.DataFrame) -> None:
    #ExcelのRangeを、PythonでDataFrameとして受け取れる
    ...
```

上記をExcelにインポート後、標準モジュールから使えるようになる。

```VB
Sub test()
    Call xlwings_udfs.my_xwfunc(Range("A1:B2")) 'セル範囲から
    Call xlwings_udfs.my_xwfunc(Worksheets("Sheet1").ListObjects("テーブル1").Range) 'テーブルから
End Sub
```



## Excelの書き込み（xlwings）
[xlwings Pandas DataFrameコンバーター](https://docs.xlwings.org/ja/latest/converters.html#pandas-dataframe-converter)

### シンタックス

- xw.Range : **xw.Range.options**(*pd.DataFrame, \*\*kwards*)**.value** = myvalue
- UDFs     : **@xw.ret**(pd.DataFrame, \*\*kwards*)

### 主な引数

| 引数 | 型 | 説明 |
|:-----|:---|:-----|
| **index**  | *int or Boolean* | インデックスの出力有無をboolで指定。 |
| **header** | *int or Boolean* | インデックスやシリーズの名前の有無を、 True か False かで設定します。 |

### サンプルコード: セル範囲、テーブル
```python
import xlwings as xw

wb = xw.books.open('book.xlsx')
sh = wb.sheets('Sheet1')

# アドレスを指定して出力
sh.range('A1').options(pd.DataFrame).value = df
# テーブルに出力（実用の際は一度テーブルのデータを消した方が安全）
sh.tables('テーブル2').data_body_range.options(pd.DataFrame, header=False, index=False).value = df
```

### サンプルコード: UDFs
これはあんまり使わないかな。

```python
import xlwings as xw

@xw.func
@xw.ret(pd.DaraFrame, index=False)
def my_xwfunc() -> pd.DataFrame:
    ....
    return df
```

上記をExcelにインポート後、標準モジュールから使えるようになる。

```VB
Sub test()
    Dim arryRet as Variant
    arryRet = xlwings_udfs.my_xwfunc()
    'PythonのDataFrameを、Excelの2次元配列として受け取れる
End Sub
```

# MS Access

## インストール

以下のインストールが必要になります。

- Pythonパッケージ: [sqlalchemy](https://pypi.org/project/SQLAlchemy/)、
[sqlalchemy-access](https://pypi.org/project/sqlalchemy-access/)
- アプリ: MS Access。PythonとExcelのビット数が異なる場合には
[Microsoft Access データベース エンジン 2016 再頒布可能コンポーネント](https://www.microsoft.com/ja-JP/download/details.aspx?id=54920)も必要になります。

## MS Access（読み込み）
[pd.read_sql](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_sql.html)

### シンタックス
**pandas.read_sql**(*sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None*)

### サンプルコード

まずはDBへの接続オブジェクトを作成する必要があります。　

```python
from pathlib import Path
import urllib
from sqlalchemy import create_engine

# DB接続
db_path = Path('db.accdb').absolute()
connection_string = (
    r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};'
    f'DBQ={db_path};'
    r'ExtendedAnsiSQL=1;'
)
connection_url = f"access+pyodbc:///?odbc_connect={urllib.parse.quote_plus(connection_string)}"
engine = create_engine(connection_url)

# 読み込み
sql = 'select * from テーブル1'
df_db = pd.read_sql(sql, engine)

# DB接続解除
engine.dispose()
```

### 主な引数

| 引数 | 型 | 説明 |
|:-----|:---|:-----|
| **sql** | *str or SQLAlchemy Selectable (select or text object)* | SQLまたはテーブル名。 |
| **con** | *SQLAlchemy connectable, str, or sqlite3 connection* | SQLAlchemy等の接続オブジェクト。 |


## MS Access（書き込み）

[pd.to_sql](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html)

### シンタックス
**DataFrame.to_sql**(*name, con, schema=None, if_exists='fail', index=True, index_label=None, chunksize=None, dtype=None, method=None*)

### サンプルコード

```python
from pathlib import Path
import urllib
import pandas as pd
from sqlalchemy import create_engine

# DB接続
db_path = Path('db.accdb').absolute()
connection_string = (
    r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};'
    f'DBQ={db_path};'
    r'ExtendedAnsiSQL=1;'
)
connection_url = f"access+pyodbc:///?odbc_connect={urllib.parse.quote_plus(connection_string)}"
engine = create_engine(connection_url)

# 書き込み
tbl_name = 'テーブル1'
df.to_sql(tbl_name, con=engine, if_exists='replace')

# DB接続解除
engine.dispose()
```

### 主な引数

| 引数 | 型 | 説明 |
|:-----|:---|:-----|
| **name**      | *str* | 出力先テーブル名。 |
| **con**       | *sqlalchemy.engine.(Engine or Connection) or sqlite3.Connection* | SQLAlchemy等の接続オブジェクト。 |
| **if_exists** | *{‘fail’, ‘replace’, ‘append’}, default ‘fail’* | テーブルが存在した場合の挙動。`fail`: ValueErrorとする。`replace`: テーブルの置き換え。`append`: 既存テーブルに追加。 |


# Oracle
[cx-Oracle](https://pypi.org/project/cx-Oracle/)

上記MS Accessのバリエーションです。接続オブジェクトの生成方法のみ異なります。

## インストール

- Pythonパッケージ: [cx-Oracle](https://pypi.org/project/cx-Oracle/)

## Oracle（読み込み）
```python
import cx_Oracle

user_name = '***'
password = '***'
db_name = '***'

# 文字化けが起きたらencodingの値を適当に設定する
conn = cx_Oracle.connect(user_name, password, db_name, encoding='utf-8')

sql = '***'
df = pd.read_sql(sql, conn)
conn.close()
```

# 参考

- [Pandasドキュメント IO tools (text, CSV, HDF5, …)](https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html)
- [xlwingsドキュメント コンバーター](https://docs.xlwings.org/ja/latest/converters.html#pandas-dataframe-converter)