为了这个问题,我简化了示例,但归结为以下内容:
我有一个包含已记录项目的 Pandas DataFrame。索引是每个特定项目的 ID,并且有两列 when(该项目何时被记录)和 logger_id(谁记录了该项目)。我想创建一个新表,为每个唯一的记录器定义每个记录项目之间的时间段。
所以新表会得到一个带有新 id 的索引,并且会有两列。与周期开始时 log_item 的 id 匹配的列 item_start,以及与周期结束时 log_item id 匹配的列,item_finish。< /p>
下面的代码有效,但我不喜欢嵌套的 for 循环。我知道 Pandas 有很多内置功能可以避免使用 for 循环,但我无法找到适合这种情况的功能。
import uuid
from datetime import datetime
import pandas as pd
df = pd.DataFrame({
"log_item_id": [str(uuid.uuid4()) for _ in range(6)],
"when": [datetime(2021, 4, d, 12) for d in [1, 8, 15]] * 2,
"logger_id": [str(uuid.uuid4()), str(uuid.uuid4())] * 3,
}).set_index("log_item_id")
periods = pd.DataFrame(columns = ["item_start", "item_finish"])
for logger_id in df.logger_id.unique(): # loop one
filtered_df = df[df.logger_id == logger_id]
for ix, log_id in enumerate(filtered_df.index[1::]): # loop two
previous = filtered_df.index[ix]
index = str(uuid.uuid4())
periods.loc[index, "item_start"] = previous
periods.loc[index, "item_finish"] = log_id
答案 0 :(得分:1)
如果我理解正确,您可以groupby()
logger_id
和shift()
log_item_id
。然后只需对列/名称/索引进行一些清理:
df = df.reset_index()
df['item_finish'] = df.groupby('logger_id').log_item_id.shift(-1)
# cleanup
df = df.dropna().rename(columns={'log_item_id': 'item_start'}).sort_values(by='logger_id').drop(columns=['logger_id', 'when'])
df.index = [uuid.uuid4() for _ in range(len(df))]
输入:
log_item_id when logger_id
4c6175fd-0258-492f-bc40-f6a02c5a8103 2021-04-01 12:00:00 f3534047-ee63-40ef-982a-27ca22d36ac0
1433966c-5643-44f3-ba11-ca91cc9867ee 2021-04-08 12:00:00 83399790-394b-4b63-b129-99f7fdb77353
d4848bdf-7e4a-4596-808f-ee5758b71bdd 2021-04-15 12:00:00 f3534047-ee63-40ef-982a-27ca22d36ac0
d9a6ecd6-9a5c-4d4b-9af8-db7bef262ee2 2021-04-01 12:00:00 83399790-394b-4b63-b129-99f7fdb77353
8eb1b911-0cad-42ad-a1f5-a7b46fc03b91 2021-04-08 12:00:00 f3534047-ee63-40ef-982a-27ca22d36ac0
291e333a-c01a-4210-961f-c2ea4c1ef0b9 2021-04-15 12:00:00 83399790-394b-4b63-b129-99f7fdb77353
输出:
item_start item_finish
8ce599d0-4d03-489a-84e3-f417e908b9ab 1433966c-5643-44f3-ba11-ca91cc9867ee d9a6ecd6-9a5c-4d4b-9af8-db7bef262ee2
805020e8-39ab-4113-8b3b-8c74997eb108 d9a6ecd6-9a5c-4d4b-9af8-db7bef262ee2 291e333a-c01a-4210-961f-c2ea4c1ef0b9
a7f8b527-268f-4de6-ba8a-23f9671046c4 4c6175fd-0258-492f-bc40-f6a02c5a8103 d4848bdf-7e4a-4596-808f-ee5758b71bdd
a0a7a765-1f41-4eca-80fd-8d79f32058c7 d4848bdf-7e4a-4596-808f-ee5758b71bdd 8eb1b911-0cad-42ad-a1f5-a7b46fc03b91
>>> df = pd.concat([df] * 1000) # 6000 rows
>>> %timeit groupby_shift(df)
35.2 ms ± 764 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>> %timeit double_loop(df)
5.26 s ± 441 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)