Python の DataFrame を利用してデータ抽出変換をしてみました （１レコード → 複数レコード）


## 概要
１レコードに複数（MAX：10）存在する類似データを、その類似データ毎のレコードとして新たに生成し、ローカルファイルに保存する Python プログラムです。(イメージは以下、、、、)

```
## 元データ
3001,WS1,中野　一郎,79,1630000,WS2,上野　二郎,104,1000000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2021/7/27,
3002,PS1,下野　三郎,32,800000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2021/6/29,
3003,ST1,中川　四郎,100,1656000,ST2,前川　五郎,64,1104000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2021/8/30,

    ↓↓↓

## 抽出変換データ
3001,WS1,中野　一郎,79,1630000,2021/7/27
3001,WS2,上野　二郎,104,1000000,2021/7/27
3002,PS1,下野　三郎,32,800000,2021/6/29
3003,ST1,中川　四郎,100,1656000,2021/8/30
3003,ST2,前川　五郎,64,1104000,2021/8/30
```

### 実行環境
macOS Big Sur 11.1 
python 3.8.3

### 実行プログラム

```python:SE_Cost_1.py
import time
import json
import argparse
from tabulate import tabulate
from datetime import datetime
import pandas as pd


# １レコードに存在する複数分の類似データをその類似毎のレコードとして新たに生成
def DataSpilit():

    # csv型式のデータファイルをDataFrameとして読取る
    df = pd.read_csv(filepath_or_buffer="./Operation_SE_Cost01.csv", encoding="ms932", sep=",")
    
    # データの「NaN」値判断（True or False）のための変換
    df1 = df.notnull()

    # 類似データあたりの登録項目数
    n = 4

    # 取得コストの キーと値
    row_key = ['Snum', 'Dept', 'J_Name', 'W_Time', 'UP_Cost', 'Fix_Date']
    row_value = []

    # 計上データの登録件数分の処理
    for i in range(df.shape[0]) :
        
        # 作業完了日が記入済み？
        if df1.iloc[i, 41] :

            # MAX10名のSEでの対応
            se = []
            for j in range(1,11) :

                # 配分済みSEのみ対象でデータ生成
                se.clear()
                if df1.iloc[i, j*n] and df1.iloc[i, (j*n)-1] :
                    se.append([df.iloc[i, 0], df.iloc[i, (j*n)-3], df.iloc[i, (j*n)-2], df.iloc[i, (j*n)-1], int(df.iloc[i, j*n]), df.iloc[i, 41]])
                    row_value.extend(se)

    # json形式への変換
    rows = [dict(zip(row_key,item)) for item in row_value]
    print(tabulate(rows, headers='keys'))

    # ローカルファイルへの保存
    cnt = DataToLocalFile(rows, row_key)

    return i+1, cnt


# 編集データのローカルファイルへの保存
def DataToLocalFile(rows, row_key):

    # データを DataFrame化
    dfl=pd.DataFrame(rows)

    print('\nDataFrameの各列のデータ型を確認 :\n', dfl.dtypes)

    # DataFrameの各列のデータ型をobject型に変換
    # （object型でないと Jsonファイルで保存できない）
    dfl=dfl.astype(({"Snum": object}))
    dfl=dfl.astype(({"W_Time": object}))
    dfl=dfl.astype(({"UP_Cost": object}))

    print('\nDataFrameの各列のデータ型を確認 :\n', dfl.dtypes)

    # json形式へ再変換
    rows = [dict(zip(row_key,item)) for item in dfl.values]

    # 保存するファイル名の生成
    now = datetime.now()
    filename = './output/SESpilitCost_' + now.strftime('%Y%m%d_%H%M%S') + '.json'
    print(filename)

    # json.dump関数でファイルに書き込む
    fw = open(filename,'w')
    json.dump(rows, fw, indent=4)
    fw.close()

    return dfl.shape[0]


if __name__ == '__main__':    
    parser = argparse.ArgumentParser(description='１レコードに存在する複数分の類似データをその類似毎のレコードとして新たに生成し、ローカルファイルに保存')
    args = parser.parse_args()

    start = time.time()
    cnt0, cnt1 = DataSpilit()
    generate_time = time.time() - start

    print("")
    print("　元データ件数 : " + str(cnt0))
    print("　新データ件数 : " + str(cnt1))
    print("  取得時間:{0}".format(generate_time) + " [sec] \n")
```

### プログラムの実行
 
```
## 実行状況
$ python SE_Cost_1.py                                          

  Snum  Dept    J_Name            W_Time    UP_Cost  Fix_Date
------  ------  --------------  --------  ---------  ----------
  3001  WS1     中野　一郎         79       1630000  2021/7/27
  3001  WS2     上野　二郎        104       1000000  2021/7/27
  3002  PS1     下野　三郎         32        800000  2021/6/29
  3003  ST1     中川　四郎        100       1656000  2021/8/30
  3003  ST2     前川　五郎         64       1104000  2021/8/30
     ：
    省略
     ：

DataFrameの各列のデータ型を確認 :
 Snum          int64
Dept         object
J_Name       object
W_Time      float64
UP_Cost       int64
Fix_Date     object
dtype: object

DataFrameの各列のデータ型を確認 :
 Snum        object
Dept        object
J_Name      object
W_Time      object
UP_Cost     object
Fix_Date    object
dtype: object
./output/SESpilitCost_20211112_142646.json

　元データ件数 : 255
　新データ件数 : 324
  取得時間:0.06269383430480957 [sec] 


## 実行結果
$ tree -a ./output
./output
└── SESpilitCost_20211112_142646.json

0 directories, 1 files


## jsonファイル（SESpilitCost_20211112_142646.json）の中身
[
    {
        "Snum": 3001,
        "Dept": "WS1",
        "J_Name": "中野　一郎",
        "W_Time": 79.0,
        "UP_Cost": 1630000,
        "Fix_Date": "2021/7/27"
    },
    {
        "Snum": 3001,
        "Dept": "WS2",
        "J_Name": "上野　二郎",
        "W_Time": 104.0,
        "UP_Cost": 1000000,
        "Fix_Date": "2021/7/27"
    },
    {
        "Snum": 3002,
        "Dept": "PS1",
        "J_Name": "下野　三郎",
        "W_Time": 32.0,
        "UP_Cost": 800000,
        "Fix_Date": "2021/6/29"
    },
    {
        "Snum": 3003,
        "Dept": "ST1",
        "J_Name": "中川　四郎",
        "W_Time": 100.0,
        "UP_Cost": 1656000,
        "Fix_Date": "2021/8/30"
    },
    {
        "Snum": 3003,
        "Dept": "ST2",
        "J_Name": "前川　五郎",
        "W_Time": 64.0,
        "UP_Cost": 1104000,
        "Fix_Date": "2021/8/30"
    },
     ：
     ：
    省略
     ：
]
```

### まとめ

この方法がベターかどうか自信はないですが、とりあえずやりたいことができているので OK かなぁ、、、、