前提
python 3.7.3
Anaconda Jupyter Notebook
実現したいこと
元データイメージ
加工後データイメージ
「2019から2020にかけてID1はElemがAからBに変わった」と読めるような横持ちのデータにしたい。
発生している問題・エラーメッセージ
エラーはありません
該当のソースコード
python
1import pandas as pd 2import numpy as np 3import itertools 4 5#元データ(上記元データイメージと同じもの) 6df = pd.DataFrame() 7df["Year"] = ["2019","2020","2021","2019","2020","2021","2019","2020","2021"] 8df["ID"] = [1,1,1,2,2,2,3,3,3] 9df["Elem"] = ["A","B","A","C","B","A","A","C","B"] 10 11#のちに結合する枠として、Yearの組み合わせをDataFrameの形で定義しておく 12year = df["Year"].drop_duplicates() 13year_list = year.sort_values().tolist() 14ptn = itertools.combinations(year_list, 2) #IDの2つの組み合わせを設定 15flame_df = pd.DataFrame([i for i in ptn], columns=["基準","比較"]) 16""" 17 基準 比較 180 2019 2020 191 2019 2021 202 2020 2021 21""" 22 23#一意のIDをリスト形式で保持 24ids = df["ID"].drop_duplicates() 25ids_list = ids.sort_values().tolist() 26 27#本処理 28output = pd.DataFrame() 29for i in ids_list: #idごとに処理を回す 30 tmp = flame_df.copy() 31 tmp["ID"] = i 32 #該当IDにおける基準年のElemをflame_dfにマージ 33 std_merged = pd.merge(tmp, 34 df[df["ID"]==i], 35 how='left', 36 left_on=['基準','ID'], 37 right_on=['Year','ID']).drop(columns='Year') 38 #該当IDにおける比較年のElemをflame_dfにマージ 39 both_merged = pd.merge(std_merged, 40 df[df["ID"]==i], 41 how='left', 42 left_on=['比較','ID'], 43 right_on=['Year','ID']).drop(columns='Year') 44 output = pd.concat([output, both_merged]) 45 46output.rename(columns={"Elem_x":"基準Elem", "Elem_y":"比較Elem"}, inplace=True) 47 48output 49 50""" 51 基準 比較 ID 基準Elem 比較Elem 520 2019 2020 1 A B 531 2019 2021 1 A A 542 2020 2021 1 B A 550 2019 2020 2 C B 561 2019 2021 2 C A 572 2020 2021 2 B A 580 2019 2020 3 A C 591 2019 2021 3 A B 602 2020 2021 3 C B 61"""
試したこと
縦持ちデータを横持にする際一般的にはpivot_tableを用いますが、
今回加工したい形に対応するaggfuncがないため、地道にやるしかないと思い、
上記のコードで実装してみました。
ただ実現はできたものの、IDの規模の規模が大きい場合、
IDごとに処理をループするこの書き方ではパフォーマンスに懸念があり・・・
より効率的な記述の作法がございましたらご意見をいただけますと幸いです。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。

回答2件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。
2022/09/01 00:05