pandas DataFrameの中間行に別のDataFrameを挿入する方法

## 要件
* データ形式
    * pandas DataFrame形式のデータ
    * インデックス番号はシーケンシャル
    * 列名は固定
    * 任意の行数がある
* 挿入される対象
    * データ形式
        * 上記のデータ形式
    * 挿入先
        * 任意の行インデックスのすぐ上
* 挿入する対象
    * データ形式
        * 上記のデータ形式

## 結論

上記の要件を満たすため、私の場合、以下のように自前の関数を作りました。

```python:insert_df_middle_row
def insert_df_middle_row( idx, df_original, df_insert ):
  return df_original.iloc[ :idx, ] \
            .append( df_insert ) \
            .append( df_original.iloc[ idx:, ] ) \
            .reset_index( drop = True )
```

#### 仕様
* 引数
    * idx : 挿入先インデックス番号。この番号の行のすぐ上に挿入
    * df_original ： 挿入されるDataFrame
    * df_insert ： 挿入するDataFrame
* 戻り値
    * 挿入後のDataFrame
        * インデックス番号は`reset_index()`メソッドにより振り直されます

#### 説明

* `df_original.iloc[ :idx, ]`
    * 挿入前DataFrame`df_original`のインデックス番号`idx`よりも上の（前の）行全て
        * インデックス番号`idx`は含みません
* `df_original.iloc[ idx:, ]`
    * 挿入前DataFrame`df_original`のインデックス番号`idx`よりも下の（後ろの）行全て
        * インデックス番号`idx`を含みます
#### その他の方法

コメント欄で教えていただいた、以下の方法は`concat()`メソッドを使うものです。`append()`メソッドを2回使う私のほい方より、こちらの方が良さげですね・・・💦

```python:コメント欄で教えていただいた実装
def insert_df_middle_row(idx, df_original, df_insert):
    return pd.concat([df_original[:idx], df_insert, df_original[idx:]])\
        .reset_index(drop=True)
``` 

## 自前関数を作った理由
* pandasの正式ドキュメントを見ても上記の要件の関数がなかった
    * DataFrameの最終行に付加する`append()`メソッドがありますが、中間行には挿入出来ないようです。
* 関数にした方が可読性が良く、メンテナンスしやすい

他にもっと良い方法があるかも知れません。もし、ご存知でしたら、ご教示くださいませ。

## お試し

以下のようなコードで上手くいくかを試してみました。

### 実装コード

```python:insert_df_middle_row.py 
import pandas as pd

def insert_df_middle_row( idx, df_original, df_insert ):
  return df_original.iloc[ :idx, ] \
            .append( df_insert ) \
            .append( df_original.iloc[ idx:, ] ) \
            .reset_index( drop = True )

df_original = pd.DataFrame(
    {
        'A': [ 'O_A0', 'O_A1', 'O_A2', 'O_A3' ] ,
        'B': [ 'O_B0', 'O_B1', 'O_B2', 'O_B3' ] ,
        'C': [ 'O_C0', 'O_C1', 'O_C2', 'O_C3' ] ,
        'D': [ 'O_D0', 'O_D1', 'O_D2', 'O_D3' ] ,
        'E': [ 'O_E0', 'O_E1', 'O_E2', 'O_E3' ]
    }
)

print( "[ Before ]\n{}\n".format( df_original ) )

df_insert = pd.DataFrame(
    {
        'A': [ 'I_A0', 'I_A1', ] ,
        'B': [ 'I_B0', 'I_B1', ] ,
        'C': [ 'I_C0', 'I_C1', ] ,
        'D': [ 'I_D0', 'I_D1', ] ,
        'E': [ 'I_E0', 'I_E1', ]
    }
)

print( "[ Insert ]\n{}\n".format( df_original ) )

df_original = insert_df_middle_row( 2, df_original, df_insert )

print( "[ After ]\n{}\n".format( df_original )  )
```
### 実行コマンド

```terminal
$ python insert_df_middle_row.py
``` 

### 実行結果

上手くいったようです。

#### ターミナル上

```terminal
[ Before ]
      A     B     C     D     E
0  O_A0  O_B0  O_C0  O_D0  O_E0
1  O_A1  O_B1  O_C1  O_D1  O_E1
2  O_A2  O_B2  O_C2  O_D2  O_E2
3  O_A3  O_B3  O_C3  O_D3  O_E3

[ Insert ]
      A     B     C     D     E
0  O_A0  O_B0  O_C0  O_D0  O_E0
1  O_A1  O_B1  O_C1  O_D1  O_E1
2  O_A2  O_B2  O_C2  O_D2  O_E2
3  O_A3  O_B3  O_C3  O_D3  O_E3

[ After ]
      A     B     C     D     E
0  O_A0  O_B0  O_C0  O_D0  O_E0
1  O_A1  O_B1  O_C1  O_D1  O_E1
2  I_A0  I_B0  I_C0  I_D0  I_E0
3  I_A1  I_B1  I_C1  I_D1  I_E1
4  O_A2  O_B2  O_C2  O_D2  O_E2
5  O_A3  O_B3  O_C3  O_D3  O_E3
```

#### Jupyter Notebook上

<img width="459" alt="スクリーンショット 2020-02-16 12.09.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124810/51d42b60-ea87-d476-a8f9-f4be4ab2b666.png">
<img width="370" alt="スクリーンショット 2020-02-16 12.10.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124810/65c89e7f-3a27-22d8-fd62-6f9440941099.png">
<img width="512" alt="スクリーンショット 2020-02-16 12.07.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124810/e0178108-0b25-a6ed-ccef-6a8c3c508fe6.png">