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

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

新規登録して質問してみよう
ただいま回答率
85.39%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

461閲覧

【Pandas】一致したユーザとプロセス番号から状態(START, END)を横方向に時系列データを並べたい

sougen

総合スコア4

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

1クリップ

投稿2024/06/12 09:17

Pandasを勉強中の者です。
以下、困っているためご教授願います。

実現したいこと

対象となる基データ
※以下6行目、強制終了してしまうとプロセスの番号が残らず、1行だけ出力される

日時ユーザプロセス状態
2024/6/12 9:10:20AAA50START
2024/6/12 9:20:10AAA50END
2024/6/12 10:00:00AAA100START
2024/6/12 10:10:00AAA200START
2024/6/12 10:20:10AAA300START
2024/6/12 10:30:10AAANaNEND
2024/6/12 12:00:10AAA100START
2024/6/12 12:10:20AAA200START
2024/6/12 12:20:10AAA200END
2024/6/12 12:40:50AAA100END
2024/6/12 16:10:20BBB500START
2024/6/12 16:20:10BBB500START
2024/6/13 08:10:20CCC500START

期待するデータ

ユーザプロセスENDSTART
AAA1002024/6/12 10:30:102024/6/12 10:00:00
AAA2002024/6/12 10:30:102024/6/12 10:10:00
AAA3002024/6/12 10:30:102024/6/12 10:20:10
AAA502024/6/12 9:20:102024/6/12 9:10:20
BBB5002024/6/12 16:20:102024/6/12 16:10:20
CCC500NaN2024/6/13 8:10:20
AAA1002024/6/12 12:20:102024/6/12 12:00:10
AAA2002024/6/12 12:40:502024/6/12 12:10:20

該当のソースコード

python

1import pandas as pd 2import io 3 4csv_data = ''' 5日時,ユーザ,プロセス,状態 62024/06/12 9:10:20,AAA,50,START 72024/06/12 9:20:10,AAA,50,END 82024/06/12 10:00:00,AAA,100,START 92024/06/12 10:10:00,AAA,200,END 102024/06/12 10:20:10,AAA,300,START 112024/06/12 10:30:10,AAA,,END 122024/06/12 12:00:10,AAA,100,START 132024/06/12 12:10:20,AAA,200,START 142024/06/12 12:20:10,AAA,200,END 152024/06/12 12:40:50,AAA,100,END 162024/06/12 16:10:20,BBB,500,START 172024/06/12 16:20:10,BBB,500,START 182024/06/13 8:10:20,CCC,500,START 19''' 20 21df = pd.read_csv(io.StringIO(csv_data), dtype=str) 22df['日時'] = pd.to_datetime(df['日時']) 23print(df) 24 25df['キー'] = df.groupby(['状態', 'ユーザ', 'プロセス']).cumcount() 26df2 = df.pivot_table(index=['キー', 'ユーザ', 'プロセス'], columns='状態', values='日時').reset_index() 27df2 = df2.drop(columns=['キー']) 28print(df2)

試したこと

25行目のcumcount関数を使って累積和を求めても、プロセスが重複しているため、
以下の様になり、期待するデータのように出力ができません。(NaTは後で埋める予定)

ユーザプロセスENDSTART
AAA1002024/6/12 12:40:502024/6/12 10:00:00
AAA2002024/6/12 12:20:102024/6/12 10:10:00
AAA300NaN2024/6/12 10:20:10
AAA502024/6/12 9:20:102024/6/12 9:10:20
BBB5002024/6/12 16:20:102024/6/12 16:10:20
CCC5002024/6/13 8:10:20NaN
AAA100NaT2024/6/12 12:00:10
AAA200NaT2024/6/12 12:10:20

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

解決済みですが,御参考として以下の内容の記述例を下記に示します。

  • 「強制終了」(複数可)の前後でデータフレームを分けて各々を「縦横変換」してから再結合

  • 縦横変換に必要な 'START' 行と 'END' 行のペアリングのため,'END' 行から 'ユーザ''プロセス' が一致する最近の 'START' 行を前方探索して 'END' 行の 'キー''START' 行に一致させる

  • 縦横変換後の 'END' 列の強制終了による空白は,強制終了時の時刻データを充填

Python

1import pandas as pd 2 3pd.set_option('mode.copy_on_write', True) 4pd.set_option('display.unicode.east_asian_width', True) 5 6df = pd.read_csv('example.csv', dtype=str) 7df['日時'] = pd.to_datetime(df['日時']) 8print(df) 9# 日時 ユーザ プロセス 状態 10# 0 2024-06-12 09:10:20 AAA 50 START 11# 1 2024-06-12 09:20:10 AAA 50 END 12# 2 2024-06-12 10:00:00 AAA 100 START 13# 3 2024-06-12 10:10:00 AAA 200 START 14# 4 2024-06-12 10:20:10 AAA 300 START 15# 5 2024-06-12 10:30:10 AAA NaN END 16# 6 2024-06-12 12:00:10 AAA 100 START 17# 7 2024-06-12 12:10:20 AAA 200 START 18# 8 2024-06-12 12:20:10 AAA 200 END 19# 9 2024-06-12 12:40:50 AAA 100 END 20# 10 2024-06-12 16:10:20 BBB 500 START 21# 11 2024-06-12 16:20:10 BBB 500 END 22# 12 2024-06-13 08:10:20 CCC 500 START 23 24df1_lst, dt_lst, i = [], [], 0 25for j in df.loc[df['プロセス'].isna() & (df['状態'] == 'END')].index: 26 df1_lst.append(df.loc[i:(j - 1)]) # drop index=j 27 dt_lst.append(df.loc[j, '日時']) 28 i = j + 1 29df1_lst.append(df.iloc[i:]) 30dt_lst.append(None) 31 32df2_lst = [] 33for df1, dt in zip(df1_lst, dt_lst): 34 df1['キー'] = df1.index 35 for i in df1.loc[df1['状態'] == 'END'].index: 36 df1.loc[i, 'キー'] = df1.loc[ 37 (df1.index < i) 38 & (df1['ユーザ'] == df1.loc[i, 'ユーザ']) 39 & (df1['プロセス'] == df1.loc[i, 'プロセス']) 40 & (df1['状態'] == 'START'), 'キー' 41 ].iloc[-1] 42 df1 = df1.pivot(index=['キー', 'ユーザ', 'プロセス'], 43 columns='状態', values='日時') 44 if dt is not None: 45 df1.loc[df1['END'].isna(), 'END'] = dt 46 df2_lst.append(df1) 47 48df2 = pd.concat(df2_lst).reset_index() 49df2 = df2[['ユーザ', 'プロセス', 'START', 'END']] 50print(df2) 51# 状態 ユーザ プロセス START END 52# 0 AAA 50 2024-06-12 09:10:20 2024-06-12 09:20:10 53# 1 AAA 100 2024-06-12 10:00:00 2024-06-12 10:30:10 54# 2 AAA 200 2024-06-12 10:10:00 2024-06-12 10:30:10 55# 3 AAA 300 2024-06-12 10:20:10 2024-06-12 10:30:10 56# 4 AAA 100 2024-06-12 12:00:10 2024-06-12 12:40:50 57# 5 AAA 200 2024-06-12 12:10:20 2024-06-12 12:20:10 58# 6 BBB 500 2024-06-12 16:10:20 2024-06-12 16:20:10 59# 7 CCC 500 2024-06-13 08:10:20 NaT

(追記)

「期待する結果」に合わせて2番目の内容を以下のように見直した記述例を下記に示します。

  • 縦横変換に必要な 'START' 行と 'END' 行のペアリングのため,'START' 行から 'ユーザ''プロセス' が一致しかつ 'キー' が書き換えられていない最初の 'END' 行を後方探索して,存在すればその 'キー''START' 行に一致させる

Python

1import pandas as pd 2 3pd.set_option('mode.copy_on_write', True) 4pd.set_option('display.unicode.east_asian_width', True) 5 6df = pd.read_csv('example_2.csv', dtype=str) 7df['日時'] = pd.to_datetime(df['日時']) 8print(df) 9# 日時 ユーザ プロセス 状態 10# 0 2024-06-12 09:10:20 AAA 100 START 11# 1 2024-06-12 09:15:20 AAA 200 START 12# 2 2024-06-12 09:20:10 AAA 200 END 13# 3 2024-06-12 10:00:00 AAA 100 START 14# 4 2024-06-12 11:20:10 AAA 100 END 15# 5 2024-06-12 12:20:10 AAA 100 END 16# 6 2024-06-12 13:10:00 AAA 100 START 17# 7 2024-06-12 14:30:10 AAA NaN END 18# 8 2024-06-12 15:00:00 AAA 100 START 19# 9 2024-06-12 15:30:00 AAA 100 START 20# 10 2024-06-12 16:20:10 AAA 100 END 21# 11 2024-06-12 18:20:10 AAA 100 END 22 23df1_lst, dt_lst, i = [], [], 0 24for j in df.loc[df['プロセス'].isna() & (df['状態'] == 'END')].index: 25 df1_lst.append(df.loc[i:(j - 1)]) # drop index=j 26 dt_lst.append(df.loc[j, '日時']) 27 i = j + 1 28df1_lst.append(df.iloc[i:]) 29dt_lst.append(None) 30 31df2_lst = [] 32for df1, dt in zip(df1_lst, dt_lst): 33 df1['キー'] = df1.index 34 for i in df1.loc[df1['状態'] == 'START'].index: 35 end = df1.loc[(df1.index > i) 36 & (df1['キー'] > i) 37 & (df1['ユーザ'] == df1.loc[i, 'ユーザ']) 38 & (df1['プロセス'] == df1.loc[i, 'プロセス']) 39 & (df1['状態'] == 'END')].index 40 if len(end) > 0: 41 df1.loc[end[0], 'キー'] = df1.loc[i, 'キー'] 42 df1 = df1.pivot(index=['キー', 'ユーザ', 'プロセス'], 43 columns='状態', values='日時') 44 if dt is not None: 45 df1.loc[df1['END'].isna(), 'END'] = dt 46 df2_lst.append(df1) 47 48df2 = pd.concat(df2_lst).reset_index() 49df2 = df2[['ユーザ', 'プロセス', 'START', 'END']] 50print(df2) 51# 状態 ユーザ プロセス START END 52# 0 AAA 100 2024-06-12 09:10:20 2024-06-12 11:20:10 53# 1 AAA 200 2024-06-12 09:15:20 2024-06-12 09:20:10 54# 2 AAA 100 2024-06-12 10:00:00 2024-06-12 12:20:10 55# 3 AAA 100 2024-06-12 13:10:00 2024-06-12 14:30:10 56# 4 AAA 100 2024-06-12 15:00:00 2024-06-12 16:20:10 57# 5 AAA 100 2024-06-12 15:30:00 2024-06-12 18:20:10

投稿2024/06/13 15:07

編集2024/06/17 14:54
little_street

総合スコア396

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sougen

2024/06/16 23:58

この前はありがとうございます。 改めて以下のデータで確認したところ、期待通りに動作しませんでした。 ```python csv_data = ''' 日時,ユーザ,プロセス,状態 2024/06/12 9:10:20,AAA,100,START 2024/06/12 9:15:20,AAA,200,START 2024/06/12 9:20:10,AAA,200,END 2024/06/12 10:00:00,AAA,100,START 2024/06/12 11:20:10,AAA,100,END 2024/06/12 12:20:10,AAA,100,END 2024/06/12 13:10:00,AAA,100,START 2024/06/12 14:30:10,AAA,,END 2024/06/12 15:00:00,AAA,100,START 2024/06/12 15:30:00,AAA,100,START 2024/06/12 16:20:10,AAA,100,END 2024/06/12 18:20:10,AAA,100,END ''' ``` 出力結果 ValueError: Index contains duplicate entries, cannot reshape のエラーが発生しました。
little_street

2024/06/17 15:09 編集

「プロセス」という言葉の一般的な意味から「同一ユーザかつ同一プロセスのものは同一時刻にはふたつ存在しない」という前提で記述しましたので,「4行目」時点で想定外のデータになりました。 「期待する結果」に合わせて見直した記述例を回答に追記しました。
guest

0

ベストアンサー

改めて以下のデータで確認したところ、期待通りに動作しませんでした。

当初、プロセスの値が NULL であるデータの時刻以降にある"END"状態のデータも組み合わせの対象にするのかと思っていたのですが、NULL値のデータが出現するまでの範囲内で組み合わせるとのことなので、以下の様に書き換えました。

python

1import pandas as pd 2import io 3 4csv_data = ''' 5日時,ユーザ,プロセス,状態 62024/06/12 9:10:20,AAA,100,START 72024/06/12 9:15:20,AAA,200,START 82024/06/12 9:20:10,AAA,200,END 92024/06/12 10:00:00,AAA,,END 102024/06/12 11:20:10,AAA,100,START 112024/06/12 12:20:10,AAA,100,END 122024/06/12 13:10:00,AAA,100,START 132024/06/12 14:30:10,AAA,,END 142024/06/12 15:00:00,AAA,100,START 152024/06/12 15:30:00,AAA,,END 162024/06/12 16:20:10,AAA,100,START 172024/06/12 18:20:10,AAA,100,END 18''' 19 20df = pd.read_csv(io.StringIO(csv_data), dtype=str) 21df['日時'] = pd.to_datetime(df['日時']) 22print(df) 23 24# 25df2 = pd.DataFrame() 26for _, grp in df.groupby('ユーザ', as_index=False): 27 m = grp['プロセス'].isna() 28 idx = grp[m].index 29 for nth, g in grp[~m].groupby(m.cumsum()): 30 # pivot 31 key = g.groupby(['状態', 'プロセス']).cumcount() 32 dfx = g.pivot_table(index=[key, 'ユーザ', 'プロセス'], columns='状態', values='日時').reset_index() 33 if 'END' not in dfx.columns: dfx['END'] = pd.NaT 34 # NULL値を補完(最後のブロックは除く) 35 if nth < len(idx): 36 dfx.loc[dfx['END'].isna(), 'END'] = grp.loc[idx[nth], '日時'] 37 df2 = pd.concat([df2, dfx]) 38 39df2 = df2[['ユーザ', 'プロセス', 'START', 'END']].reset_index(drop=True) 40print(df2)
ユーザプロセスSTARTEND
AAA1002024-06-12 09:10:202024-06-12 10:00:00
AAA2002024-06-12 09:15:202024-06-12 09:20:10
AAA1002024-06-12 11:20:102024-06-12 12:20:10
AAA1002024-06-12 13:10:002024-06-12 14:30:10
AAA1002024-06-12 15:00:002024-06-12 15:30:00
AAA1002024-06-12 16:20:102024-06-12 18:20:10

投稿2024/06/12 13:42

編集2024/06/17 06:20
melian

総合スコア20530

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sougen

2024/06/12 22:13

ありがとうございます。大変助かりました。
sougen

2024/06/16 23:56

この前はありがとうございます。 改めて以下のデータで確認したところ、期待通りに動作しませんでした。 ```python csv_data = ''' 日時,ユーザ,プロセス,状態 2024/06/12 9:10:20,AAA,100,START 2024/06/12 9:15:20,AAA,200,START 2024/06/12 9:20:10,AAA,200,END 2024/06/12 10:00:00,AAA,100,START 2024/06/12 11:20:10,AAA,100,END 2024/06/12 12:20:10,AAA,100,END 2024/06/12 13:10:00,AAA,100,START 2024/06/12 14:30:10,AAA,,END 2024/06/12 15:00:00,AAA,100,START 2024/06/12 15:30:00,AAA,100,START 2024/06/12 16:20:10,AAA,100,END 2024/06/12 18:20:10,AAA,100,END ''' ``` 出力結果 |ユーザ|プロセス|START|END| |:--|:--:|--:|--:| |AAA|100|2024-06-12 09:10:20|2024-06-12 11:20:10| |AAA|200|2024-06-12 09:15:20|2024-06-12 09:20:10| |AAA|100|2024-06-12 10:00:00|2024-06-12 12:20:10| |AAA|100|2024-06-12 13:10:00|2024-06-12 14:30:10| |AAA|100|2024-06-12 15:00:00|2024-06-12 14:30:10| |AAA|100|2024-06-12 15:30:00|2024-06-12 16:20:10| |AAA|100||NaT|2024-06-12 18:20:10| 期待する結果 |ユーザ|プロセス|START|END| |:--|:--:|--:|--:| |AAA|100|2024-06-12 09:10:20|2024-06-12 11:20:10| |AAA|200|2024-06-12 09:15:20|2024-06-12 09:20:10| |AAA|100|2024-06-12 10:00:00|2024-06-12 12:20:10| |AAA|100|2024-06-12 13:10:00|2024-06-12 14:30:10| |AAA|100|2024-06-12 15:00:00|2024-06-12 16:20:10| |AAA|100|2024-06-12 15:30:10|2024-06-12 18:20:10|
melian

2024/06/17 04:03

回答を書き換えました。質問にあるデータで実行すると行の順序が変わりますが、内容は同一になります。
sougen

2024/06/17 05:45

迅速なご回答ありがとうございます。 大変助かりました。 少しデータを変えてみたのですが、8と10行目プロセスがNaNのとき、『KeyError: "['END'] not in index"』エラーとなってしまう場合がありますが、どのように修正すればよいでしょうか? 度々の質問で申し訳ありません。 csv_data2 = ''' 日時,ユーザ,プロセス,状態 2024/06/12 9:10:20,AAA,100,START 2024/06/12 9:15:20,AAA,200,START 2024/06/12 9:20:10,AAA,200,END 2024/06/12 10:00:00,AAA,,END 2024/06/12 11:20:10,AAA,100,START 2024/06/12 12:20:10,AAA,100,END 2024/06/12 13:10:00,AAA,100,START 2024/06/12 14:30:10,AAA,,END 2024/06/12 15:00:00,AAA,100,START 2024/06/12 15:30:00,AAA,,END 2024/06/12 16:20:10,AAA,100,START 2024/06/12 18:20:10,AAA,100,END '''
melian

2024/06/17 06:21

もう一点、勘違いをしていた部分があって、KeyError を含め修正しました。
sougen

2024/06/17 23:02

ありがとうございます。完璧に動作しました。大変助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問