Masa-Kawa
@Masa-Kawa (Masa Kawaguchi)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[Pandas 重複処理] 記録されているデータの条件で行うことができますか

解決したいこと

手元に紙運用で行っていた業務記録があり、作業単位でレコードがあります。
フォーマットはファイルメーカーを用いて作成し印刷していました。この複数年の記録をcsvファイルにまとめて分析したいと考えています。
ところが、手入力で複数の人が関わっているため、重複入力があり未完入力と完了入力が混ざっています。特に、年ごとにファイルを作ってあるため年末年始で乱れが多く生じ、必ずしも時系列の入力ではありません。

例)

作業ID 着手日付 経過 終了日付 判断
作業1 4/1
作業2 4/5 経過良好 4/14 完了
作業3 4/10 必要条件を満たさず 4/20 中断
作業3 4/10 必要条件を満たさず
作業1 4/1 トラブルあるも改善 5/1 完了

このデータを未完成データによる重複を排除したデータにしたいです。

試してみたこと

まず、上記csvファイルをdfにとりこみ、duplicated,drop_duplicatesなどで処理する。

import pandas as pd
df = pd.read_csv('hyou.csv')

df.drop_duplicates(subset='作業ID', keep='first')

ところが、機械的なkeep='first'や'last'では未完成の入力データも混在して取り込んでしまいます。
重複のキー以外でのデータの条件をもとに有用なレコードのみを残すように一括処理できないでしょうか。

空白が少ないほうが正しいデータが入っているとの考えで、

# 新たに各行の空欄を数えた列を作る。
df['space']=df.isna().sum(axis=1)

としてみましたが、ここから先が進めなくなってしまいました。
ソートやdrop_duplicatesを組み合わせてできそうな気もしますが、アドバイスいただければ幸いです。
よろしくおねがいします。

背景情報

Python, Pandasの初心者です。独学でデータ管理に挑戦しています。
Python 3.8.3
pandas 1.2.1

0

2Answer

作業IDごとに「space」の少ない順にランク付けを行い、ランクが0のところだけを取得する形で実現できると思います。

最後、必要な列は「判断」までなのでilocを使用して、追加した列を削除した形で取得しています。
また、見やすいように「作業ID」でソートしています。

df['space']=df.isna().sum(axis=1)
df['rank'] = df.sort_values(['space']).groupby(['作業ID']).cumcount()
df = df[df['rank'] == 0].iloc[:,:4].sort_values('作業ID')

image.png

参考:

1Like

Comments

  1. @Masa-Kawa

    Questioner

    ありがとうございます。
    まさに希望通りの解答です。実際にはもっとデータ項目があるので'space'でソートしランク付けをした上でデータを抜き出せるのは素晴らしいです。

    ポイントのdf['rank'] の行の理解を深めたいと思います

    ちなみに作業IDがユニークな値でなく、作業ID+開始日の2列で固有値としたい場合は同様にできますでしょうか。groupbyの働きが良くわかっておらずすいません。
    よろしくおねがいします。
  2. @Masa-Kawa

    Questioner

    暫定的に、作業ID+着手日で新しい列を作り、アドバイスに従って処理することにしました。ありがとうございました。
  3. @Masa-Kawa

    Questioner

    最終的な方法です。

    df['tmpid']=df['着手日'].astype(str)+'ID'+df['作業ID'].astype(str)

    df['space']=df.isna().sum(axis=1)
    df['rank'] = df.sort_values(['space']).groupby(['tmpid']).cumcount()
    df = df[df['rank'] == 0].iloc[:,:-4].sort_values('tmpid')

    YottyPGさんの前に新たな'tmpid'列を作り、最後に:-4で'tmpid','space','rank'を消すことでどうにか解決しました。

    ありがとうございました。
  4. 解決したようでよかったです!

すみません、返信遅くなりました。
たしかに「作業ID+着手日」で新しい列を作っても実装できると思いますが、単純にgroup byするキーに着手日を追加するだけでうまくいくと思います。

df['rank'] = df.sort_values(['space']).groupby(['作業ID', '着手日付']).cumcount()

image.png

1Like

Comments

  1. @Masa-Kawa

    Questioner

    なるほど、重ね重ねありがとうございました。
    奥が深いですね。勉強します。

Your answer might help someone💌