著者:パンダスのデータ処理スペシャリストであるリトルミンは、無数のデータ実践者がデータ処理の問題を解決するのを支援することに尽力しています。
ニーズの声明
ユーザーのツアーログのデータは次の形式になっています(以下の表をコピーした後、次のコードを実行しても同じ結果が表示されます)。
import pandas as pd
df = pd.read_clipboard()
df
結果:
uid | 開始 | 終わり | |
---|---|---|---|
0 | A | 1 | 2 |
1 | A | 4 | 7 |
2 | A | 3 | 6 |
3 | A | 8 | 9 |
4 | B | 2 | 3 |
5 | B | 4 | 7 |
6 | B | 10 | 11 |
7 | B | 6 | 8 |
8 | B | 12 | 15 |
9 | C | 14 | 15 |
このうち、uidは各ユーザー、startはツアーの開始時刻、endはツアーの終了時刻を表します。上の表から、ツアー時間の重複があることがわかります。たとえば、ユーザーAのツアー時間は3-6と4-7に重複しています。ツアー時間は3〜7時間と考えられます。
ここでやらなければならないのは、各ユーザーの重複するツアー時間をマージし、最終的に時系列で表示することです。
注:3-4と4-6も重複する時間であり、3-6に組み合わせることができます。
最初にユーザーの時間をマージして並べ替えます
テスト操作のためにユーザーのデータを取り出します。
tmp = df.groupby("uid").get_group('B')
tmp
結果:
uid | 開始 | 終わり | |
---|---|---|---|
4 | B | 2 | 3 |
5 | B | 4 | 7 |
6 | B | 10 | 11 |
7 | B | 6 | 8 |
8 | B | 12 | 15 |
観察により、この問題を解決するには、最初に開始時間に従ってデータをソートする必要があることがわかりました。
ソート後:
tmp = tmp.sort_values('start')
tmp
結果:
uid | 開始 | 終わり | |
---|---|---|---|
4 | B | 2 | 3 |
5 | B | 4 | 7 |
7 | B | 6 | 8 |
6 | B | 10 | 11 |
8 | B | 12 | 15 |
ソートされたデータを観察することにより、マージのルールをすばやく観察できます。
現在のツアーレコードの開始時間が前のレコードの終了時間以下の場合、それはマージされます。これは非常に簡単です。
result = []
for uid, start, end in tmp.values:
# 如果结果集中还没有数据或者当前记录的起始时间大于上一条记录的结束时间
# 就可以直接将当前记录加入到结果集
if not result or start > result[-1][2]:
result.append([uid, start, end])
else:
# 否则,说明可以将当前记录与上一条记录合并
# 合并方法是如果当前记录的结束时间大于上一条记录的结束时间,
# 则上一条记录的结束时间修改为当前记录的结束时间
result[-1][2] = max(result[-1][2], end)
tmp = pd.DataFrame(result, columns=["uid", "start", "end"])
tmp
結果:
uid | 開始 | 終わり | |
---|---|---|---|
0 | B | 2 | 3 |
1 | B | 4 | 8 |
2 | B | 10 | 11 |
3 | B | 12 | 15 |
完全なコード
次に、完全な処理コードを整理します。
result = []
for uid, tmp in df.groupby("uid"):
tmp = tmp[["start", "end"]].sort_values('start')
rows = []
for start, end in tmp.values:
if not rows or start > rows[-1][2]:
rows.append([uid, start, end])
else:
rows[-1][2] = max(rows[-1][2], end)
tmp = pd.DataFrame(rows, columns=["uid", "start", "end"])
result.append(tmp)
result = pd.concat(result)
result
結果:
uid | 開始 | 終わり | |
---|---|---|---|
0 | A | 1 | 2 |
1 | A | 3 | 7 |
2 | A | 8 | 9 |
0 | B | 2 | 3 |
1 | B | 4 | 8 |
2 | B | 10 | 11 |
3 | B | 12 | 15 |
0 | C | 14 | 15 |
さて、それは終わった、花を振りかける!