techno_memo

個人用の技術メモ。python・ROS・AI系のソフトウェア・ツールなどの情報を記載

データマージ方法① 複数ファイルに記載された集計データに対するマージ

やりたいこと

 複数ファイルに記載された集計データのマージ   * 各種の集計結果 (アンケート、帳票など)

* 時系列データ (タイムスタンプの処理)については別記事で記載予定

複数ファイルに記載された集計データのマージ

 一般的によく使われそうなケースを想定して場合分けして考える

①複数グループのデータのマージ

  • 重複する対象がない複数グループに対して同じ項目の計測をしたデータ

(下記では複数のチームに対する身体測定結果の例でイメージを記載)

[f:id:sd08419ttic:20190224192344p:plain]

実装

pandasのconcat関数を適用する

pandasのデータフレームリスト(以前記載した方法で取得)を引数とすると下記の処理でマージできる。

    def merge_data_simlpe(self,input_pd_list):
        '''
        最もシンプルなデータのマージ (pandas concatを使った縦方向の結合)
        '''
        result = input_pd_list[0]
        for dnameindx in range(len(input_pd_list)-1) :
            result = pd.concat([result,input_pd_list[dnameindx+1]])

        result = result.reset_index(drop=True)    #インデックスを振りなおす

        return result

②同一対象を含むデータのマージ

  • 重複する対象を含む複数ファイルのデータ (同じ対象を別の時間で計測した結果など)

(下記では同じ組織に対する年度毎の身体測定結果の例でイメージを記載)

f:id:sd08419ttic:20190224204859p:plain

実装①

各dataframeに新しい列を追加し、ファイル名の情報を追加する

追加したdfをpandasのconcat関数を適用して結合する

    def merge_data_with_filenamecol(self,input_pd_list,fname_list):
        '''
        ファイル名を新しい列として追加するマージ
        '''
        result = input_pd_list[0]

        fname, ext = os.path.splitext( os.path.basename(fname_list[0]) )    #ファイル名/拡張子の取得
        result["file_name"] = fname
        for dnameindx in range(len(input_pd_list)-1) :
            fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) )    #ファイル名/拡張子の取得
            temp_df = input_pd_list[dnameindx+1]
            temp_df["file_name"] = fname
            result = pd.concat([result,temp_df])

        result = result.reset_index(drop=True)    #インデックスを振りなおす

        return result
実装②

各dataframeの列にファイル名を添え字として保存する (下記の例)

f:id:sd08419ttic:20190224220712p:plain

上図において全て存在しているものを残す場合と、存在しない場合はでNanとする場合の2つの実装を考慮する。

(この2つはデータの種類によってどちらの形式を選択するか考慮したほうが良いと考えたため)

    def merge_data_with_merge_only_common(self,input_pd_list,fname_list):
        '''
        一番左の列の要素をキーとして各ファイルのデータを添え字付きでマージする処理 (全てのファイルにキーが存在する行のみ表示)
        '''
        result = input_pd_list[0]
        fname, ext = os.path.splitext( os.path.basename(fname_list[0]) )    #ファイル名/拡張子の取得
        ori_columns = result.columns.tolist()
        for colindx in range(len(ori_columns)-1):
            ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname   #列名に添え字を追加
        result.columns = ori_columns
        key_name = result.columns[0]    #一番左の列をキーとする

        for dnameindx in range(len(input_pd_list)-1) :
            fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) )    #ファイル名/拡張子の取得
            temp_df = input_pd_list[dnameindx+1]
            ori_columns = temp_df.columns.tolist()
            for colindx in range(len(ori_columns)-1):
                ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname   #列名に添え字を追加
            temp_df.columns = ori_columns
            result = pd.merge(result,temp_df,on=key_name)
        result = result.reset_index(drop=True)    #インデックスを振りなおす

        return result

    def merge_data_with_merge_all_data(self,input_pd_list,fname_list):
        '''
        一番左の列の要素をキーとして各ファイルのデータを添え字付きでマージする処理 (キーが不在の場合はNanで表示)
        '''
        result = input_pd_list[0]
        fname, ext = os.path.splitext( os.path.basename(fname_list[0]) )    #ファイル名/拡張子の取得
        ori_columns = result.columns.tolist()
        for colindx in range(len(ori_columns)-1):
            ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname   #列名に添え字を追加
        result.columns = ori_columns
        key_name = result.columns[0]    #一番左の列をキーとする

        for dnameindx in range(len(input_pd_list)-1) :
            fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) )    #ファイル名/拡張子の取得
            temp_df = input_pd_list[dnameindx+1]
            ori_columns = temp_df.columns.tolist()
            for colindx in range(len(ori_columns)-1):
                ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname   #列名に添え字を追加
            temp_df.columns = ori_columns
            result = pd.merge(result,temp_df,on=key_name, how='outer')
            print(result)

        result = result.reset_index(drop=True)    #インデックスを振りなおす

        return result

実装結果は下記に記載

github.com

その他集約するファイル名の命名ルールで判定する、データ種別で結合可能か判定するなどのアプローチがあるが長くなりそうなので別記事で記載する。