質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Python 3.x

    5877questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pythonで、2つのexcelファイルの差分(要素レベル)を抽出したい。

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 254

H.Kazuyuki

score 12

解決したいこと:
下記のような、2つのexcelファイルの差分を要素レベルで抽出し、変更の行、列を
{行数、列数}のような形でリストかデータフレームに格納したい
(あとで変更した要素の個所をopenpyxlなどで色を塗るため)

テーブル:
変更前excel例:
フェーズ    作業項目    担当者    計画工数    計画開始日    計画終了日    進捗率
要件定義    顧客A打合せ    tanaka    3    2018/5/30    2018/6/1    100
基本設計    A機能基本設計    satou    15    2018/6/1    2018/6/4    20
基本設計    B機能基本、設計    yamada    12    2018/6/2    2018/6/8    30

変更後excel例:
フェーズ    作業項目    担当者    計画工数    計画開始日    計画終了日    進捗率
要件定義    顧客A打合せ    tanaka    3    2018/5/30    2018/6/1    100
基本設計    A機能基本設計    satou    15    2018/6/1    2018/6/4    100
基本設計    C機能基本設計    yamada    18    2018/6/5    2018/6/12    10

やってみたこと:
下記のようなコードを描くと、行単位での抽出は可能でした。

import pandas as pd

df1 = pd.read_excel("before.xlsx")
df2 = pd.read_excel("after.xlsx")

df1['比較用の列'] = df1[['フェーズ', '作業項目', '担当者', '計画工数', '計画開始日', '計画終了日', '進捗率']].apply(lambda x: '{}_{}_{}_{}_{}_{}_{}'.format(x[0], x[1], x[2], x[3], x[4], x[5], x[6]), axis=1)
df2['比較用の列'] = df2[['フェーズ', '作業項目', '担当者', '計画工数', '計画開始日', '計画終了日', '進捗率']].apply(lambda x: '{}_{}_{}_{}_{}_{}_{}'.format(x[0], x[1], x[2], x[3], x[4], x[5], x[6]), axis=1)

df2[~df2['比較用の列'].isin(df1['比較用の列'])]

しかし、これだと変更後をベースにした行単位での差異は抽出可能ですが、
出来れば要素単位で抽出したいです。。
基本的な質問かもしれなくて申し訳ありませんが、ご教示いただけないでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

df1とdf2から比較したい行を抽出して比較演算をすると、全要素の比較結果がTrue,Falseの形式で返ってきます。

df1.iloc[抽出したい行番号,:]==df2.iloc[対応する行番号,:]

df1とdf2が完全に対応関係が一致しているのであれば、単純にdf1==df2とすると比較結果のDataFrameが得られるので、これを使ったほうが便利かもしれません

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/09 15:52

    ご回答ありがとうございます。言葉足らずで申し訳ありません。
    例えば、
    [1,2,3
    4,5,6
    7,8,9]と
    [2,2,3,
    4,5,6,
    1,1,1,
    7,9,9,]
    を比較した場合,
    変更後ベースで1->2に、8->9に変更され、1,1,1が追加されたことを
    わかるようにしたいなあという目的があります。難しいでしょうか

    キャンセル

  • 2018/06/09 18:26

    1,1,1の追加というのは、行の追加を意味しているのでしょうか?つまり、質問文の例示でいうと、変更後のexcelには4行目が追加になっているということでしょうか?

    とりあえず、上記の仮定が正しいのであれば、双方の列に共通するkeyが付与されているのであれば、このkeyの比較によって追加になった行を識別できると思います。仮にkeyがないようだと、行と行の間に追加になった場合はムリかと思います。
    追加になった行が特定できれば、その行を除いて上記のようにDataFrame間を比較すれば、全ての要素の比較ができるようになります。

    キャンセル

  • 2018/06/09 20:21

    なるほど、keyとなる列がないのであればやっぱり難しいですか…。ありがとうございます。
    keyとなる列を追加してもらえそうなので、そちらのほうを、依頼者に相談するかもしれません。
    いろいろご相談に乗っていただきましたので、ベストアンサーとさせていただきます。
    助かります。

    キャンセル

+1

import pandas as pd


df01=pd.read_excel('before.xlsx',header=None)
df02=pd.read_excel('before.xlsx',header=None)

l=df01.values.tolist()
r=df01.T.values.tolist()


from pprint import pprint
pprint(l),print()
pprint(r)

間違えました。
データフレームだと、

import pandas as pd

df01=pd.read_excel('before.xlsx',header=None)
df02=pd.read_excel('before.xlsx',header=None)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/09 15:41

    ご回答ありがとうございます。

    l=df01.values.tolist()
    r=df01.T.values.tolist()
    とされているのは、rにdf01を転置したものをリスト化して、
    どうされようとしているのでしょうか。
    両方ともbefore.xlsxを読んできているので、afterとの差分がとられていないように思うのですが気のせいでしょうか。

    キャンセル

  • 2018/06/09 18:14

    勘違いでした。
    一度、単純にリスト化して後で書き込めば良い思ってました。

    キャンセル

  • 2018/06/09 20:18

    わかりにくくて申し訳ありません^^
    ご回答ありがとうございましたー。

    キャンセル

+1

書いてみました。

import io
import pandas as pd

# 読み込み処理
data1 = """
フェーズ    作業項目    担当者    計画工数    計画開始日    計画終了日    進捗率
要件定義    顧客A打合せ    tanaka    3    2018/5/30    2018/6/1    100
基本設計    A機能基本設計    satou    15    2018/6/1    2018/6/4    20
基本設計    B機能基本、設計    yamada    12    2018/6/2    2018/6/8    30
"""

data2 = """
フェーズ    作業項目    担当者    計画工数    計画開始日    計画終了日    進捗率
要件定義    顧客A打合せ    tanaka    3    2018/5/30    2018/6/1    100
基本設計    A機能基本設計    satou    15    2018/6/1    2018/6/4    100
基本設計    C機能基本設計    yamada    18    2018/6/5    2018/6/12    10
"""

df1 = pd.read_table(io.StringIO(data1), sep="\s+")
df2 = pd.read_table(io.StringIO(data2), sep="\s+")

print(df1)
print(df2)
""" =>
   フェーズ      作業項目     担当者  計画工数      計画開始日     計画終了日  進捗率
0  要件定義    顧客A打合せ  tanaka     3  2018/5/30  2018/6/1  100
1  基本設計   A機能基本設計   satou    15   2018/6/1  2018/6/4   20
2  基本設計  B機能基本、設計  yamada    12   2018/6/2  2018/6/8   30
   フェーズ     作業項目     担当者  計画工数      計画開始日      計画終了日  進捗率
0  要件定義   顧客A打合せ  tanaka     3  2018/5/30   2018/6/1  100
1  基本設計  A機能基本設計   satou    15   2018/6/1   2018/6/4  100
2  基本設計  C機能基本設計  yamada    18   2018/6/5  2018/6/12   10
"""

# 違う場所のTFのdfを作る
change_tf_df = df1 != df2
print(change_tf_df)
""" =>
0  False  False  False  False  False  False  False
1  False  False  False  False  False  False   True
2  False   True  False   True   True   True   True
"""

# とりあえず愚直にfor(他にいいやり方があったら誰か教えてくだい・・・)
lst = []
for i, row in change_tf_df.iterrows():
    for j, (_, v) in enumerate(row.iteritems()):
        if v:
            lst.append((i,j))
print(lst)
""" =>
[(1, 6), (2, 1), (2, 3), (2, 4), (2, 5), (2, 6)]
"""

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/09 16:02

    ありゃ、R.Shigemoriさんの回答のコメントを見たら、これじゃ駄目じゃん

    キャンセル

  • 2018/06/09 20:20

    ご回答ありがとうございました^^
    ちょっと問題設定が悪かったっぽいですね💦
    なんとかこねくり回してみますー。
    皆さんの意見をもとに工夫したら何とかできそうです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    5877questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。