以下のようなpd.DataFrameがあるとします。
行いたい処理は各id毎にdateの差をとっていくことです。すでにid毎にdateは
sortされているものとします。
以下のコードで処理しようとしましたが、実際のデータは3000万行程(uniqueなidが30万ほど)あり、時間がかかりすぎだったので、途中で止めました。効率よくこの処理を行うにはどうすればよいでしょうか?
python
1#dateの差をとっていく、ただしidが変わるときは0とする(違うcard_id間で差を取らないように気をつける) 2for i in tqdm(range(len(df))): 3 if i == 0: 4 pass 5 elif df['id'][i] == df['id'][i-1]: 6 df['delta'][i] = df['date'][i] - df['date'][i-1] 7 else: 8 pass
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
can110さんのから改良。気持ちマシになると思いますが、そもそも遅い処理なのでどうだろうな面はあります。
python
1import pandas as pd 2 3df = pd.DataFrame({'id':['a','a','a','b','b','b'],'date':['2018/01/23','2018/01/24','2018/01/26','2018/01/23','2018/01/26','2018/01/30']}) 4df.loc[:,'date'] = pd.to_datetime(df['date']) 5 6grp = df.groupby('id') 7for grp_name, grp_idx in grp.groups.items(): 8 df.loc[grp_idx,'delta'] = df.loc[grp_idx,'date'].diff().fillna(0) 9 10print(df) 11""" 12 date id delta 130 2018-01-23 a 0 days 141 2018-01-24 a 1 days 152 2018-01-26 a 2 days 163 2018-01-23 b 0 days 174 2018-01-26 b 3 days 185 2018-01-30 b 4 days 19""" 20
毎回fillnaするオーバーヘッドを削減()したもの
python
1import pandas as pd 2 3df = pd.DataFrame({'id':['a','a','a','b','b','b'],'date':['2018/01/23','2018/01/24','2018/01/26','2018/01/23','2018/01/26','2018/01/30']}) 4df.loc[:,'date'] = pd.to_datetime(df['date']) 5 6grp = df.groupby('id') 7for grp_name, grp_idx in grp.groups.items(): 8 df.loc[grp_idx,'delta'] = df.loc[grp_idx,'date'].diff() 9 10df.fillna(0, inplace=True) 11print(df) 12""" 13 date id delta 140 2018-01-23 a 0 days 151 2018-01-24 a 1 days 162 2018-01-26 a 2 days 173 2018-01-23 b 0 days 184 2018-01-26 b 3 days 195 2018-01-30 b 4 days 20""" 21
別のアイデア
これでも良い気がします。速くはなるはずなんだけど、idごとに計測するのは無理かも。あと、上のループでどれくらい時間を食うかが懸念。
python
1import pandas as pd 2 3df = pd.DataFrame({'id':['a','a','a','b','b','b'],'date':['2018/01/23','2018/01/24','2018/01/26','2018/01/23','2018/01/26','2018/01/30']}) 4df.loc[:,'date'] = pd.to_datetime(df['date']) 5 6before_id = None 7zero_points = [] 8for i, id_ in df["id"].iteritems(): 9 if id_ != before_id: 10 zero_points.append(i) 11 before_id = id_ 12 13df.loc[:,"delta"] = df.loc[:,"date"].diff() 14df.loc[zero_points,"delta"] = pd.Timedelta(0) 15print(df) 16 17""" 18 date id delta 190 2018-01-23 a 0 days 201 2018-01-24 a 1 days 212 2018-01-26 a 2 days 223 2018-01-23 b 0 days 234 2018-01-26 b 3 days 245 2018-01-30 b 4 days 25"""
投稿2018/12/24 03:54
編集2018/12/24 05:37総合スコア30935
0
以下のような感じでできそうです。
id
でグループ化してid
毎にdiff
を適用します。
先頭行はNaN
になるのでfillna(0)
で0で埋めています。
Python
1import pandas as pd 2 3df = pd.DataFrame({'id':['a','a','a','b','b','b'],'date':['2018/01/23','2018/01/24','2018/01/26','2018/01/23','2018/01/26','2018/01/30']}) 4df.loc[:,'date'] = pd.to_datetime(df['date']) 5 6grp = df.groupby('id') 7for id in grp.groups: 8 df.loc[df['id'] == id,'delta'] = df.loc[df['id'] == id,'date'].diff().fillna(0) 9 10print(df) 11""" 12 date id delta 130 2018-01-23 a 0 days 141 2018-01-24 a 1 days 152 2018-01-26 a 2 days 163 2018-01-23 b 0 days 174 2018-01-26 b 3 days 185 2018-01-30 b 4 days 19"""
別解:先頭から舐める版
ユニークidが多く、各id毎の行数が少ない場合は、以下のように先頭から舐めて計算する方が速いかもしれません。
Python
1import pandas as pd 2 3df = pd.DataFrame({'id':['a','a','a','b','b','b'],'date':['2018/01/23','2018/01/24','2018/01/26','2018/01/23','2018/01/26','2018/01/30']}, 4 columns = ['id','date']) 5df.loc[:,'date'] = pd.to_datetime(df['date']) 6df['delta'] = 0 7 8prev_id,prev_date = df.loc[0,'id'], df.loc[0,'date'] 9for idx,row in df.iterrows(): 10 cur_id = row['id'] 11 cur_date = row['date'] 12 if prev_id != cur_id: 13 pass 14 else: 15 df.loc[idx,'delta'] = cur_date - prev_date 16 prev_id = cur_id 17 prev_date = cur_date 18 19print(df) 20""" 21 id date delta 220 a 2018-01-23 0 days 00:00:00 231 a 2018-01-24 1 days 00:00:00 242 a 2018-01-26 2 days 00:00:00 253 b 2018-01-23 0 264 b 2018-01-26 3 days 00:00:00 275 b 2018-01-30 4 days 00:00:00 28"""
投稿2018/12/24 02:44
編集2018/12/24 04:27総合スコア38343
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/24 03:36
2018/12/24 03:44 編集
2018/12/24 03:42
2018/12/24 03:54 編集
2018/12/24 03:48
2018/12/24 03:53
2018/12/24 03:57
2018/12/24 04:02
2018/12/24 04:06
2018/12/24 04:31
2018/12/24 05:23
2018/12/24 05:25
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/24 04:03
2018/12/24 04:05
2018/12/24 04:07
2018/12/24 04:07
2018/12/24 04:10 編集
2018/12/24 04:11
2018/12/24 04:14 編集
2018/12/24 04:34
2018/12/24 04:36
2018/12/24 05:11
2018/12/24 05:16 編集
2018/12/24 05:23
2018/12/24 05:28
2018/12/24 05:36 編集
2018/12/24 05:44