gpt4 book ai didi

python - 如果日期在另一个数据帧的日期范围内且项目相等,则在一个数据帧中分配值

转载 作者:行者123 更新时间:2023-12-01 06:59:35 25 4
gpt4 key购买 nike

我有两个数据框。其中包含时间戳和项目的一种。另一个有日期范围、项目和期限,必须映射到日期范围内的相应项目。

我的问题是similar to this question ,但是提供的答案非常慢,并且我有一个额外的条件需要满足。对于初学者来说,我的两个数据框看起来像这样:

In:
import pandas as pd
df_a = pd.DataFrame({'time': ('06.05.2015 16:15:16', '22.06.2015 08:52:05', '28.05.2015 18:20:21','28.06.2015 16:19:21'),
'project': ('project1', 'project2', 'project2', 'project1')})

df_b = pd.DataFrame({'start-date': ('02.05.2015 00:00:00', '26.06.2015 00:00:00', '16.05.2015 00:00:00', '30.05.2015 00:00:00'),
'end-date':('24.06.2015 00:00:00', '27.07.2015 00:00:00', '27.05.2015 00:00:00', '27.06.2015 00:00:00'),
'project': ('project1','project1','project2','project2'),
'maturity': ('one','two', 'one','two')})

我的代码如下所示:


for i in df_a.project.unique():
for j in df_b.project.unique():
if i == j:
for index_df_a, row_df_a in df_a.iterrows():
for index_df_b, row_df_b in df_b.iterrows():
if (row_df_a['time'] >= row_df_b['start-date']) & (row_df_a['time'] <= row_df_b['end-date']):
df_a.loc[index_df_a, 'maturity'] = row_df_b.loc['maturity']
break


Out:
time project maturity
0 06.05.2015 16:15:16 project1 one
1 22.06.2015 08:52:05 project2 one
2 28.05.2015 18:20:21 project2 NaN
3 28.06.2015 16:19:21 project1 NaN

预期结果:

                   time   project maturity
0 06.05.2015 16:15:16 project1 one
1 22.06.2015 08:52:05 project2 one
2 28.05.2015 18:20:21 project2 two
3 28.06.2015 16:19:21 project1 two

  1. 我在类似问题的帮助下编写的代码非常慢。当我将其应用到我的数据帧时(df_a 有约 900k 行,df_b 有约 1.7k 成熟度来映射),即使处理一千行也需要很长时间。有没有办法加快这个过程?
  2. 我认为我的 if i==j: 语句是错误的。从结果第 4 行可以看出:即使项目映射到 project1 并且时间戳 28.06.2015 16:19:21 范围内开始:26.06.2015 00:00:00 | end: 27.07.2015 00:00:00 成熟度为 NaN 而不是 two
  3. 最后,是否可以创建一个条件,即使时间戳不在给定的日期范围内,也会映射每个项目的下一个提供的成熟度(第 3 行)?因此,如果 28.05.2015 18:20:21 不在任何日期范围内,则下一个日期范围提供到期日。在本例中两个

请原谅我一次问得太多。我知道最好的做法是通过提出简单的问题并逐步获得结果来得出答案,但是我的经验还不够,无法将问题分成更小的部分。

最佳答案

  • 这应该比当前的实现快得多
  • 如果您发现自己正在迭代数据框,那么您可能做错了
  • pd.date_rangestart-dateend-date 结合使用,将 d_range 列添加到 df_b,则可以使用.isind_range内的df_a查找时间
    • d_range 将是开始和结束之间的日期列表。
    • 如果 time 格式不正确,它将与 d_range 内的日期不匹配。
  • 该实现将清理每个数据帧中的时间列
    • 将列设置为日期时间格式
    • 我们只关心日期,而不关心时间
    • 如前所述,日期时间格式是不可或缺的。如果列的格式不正确,则在 d_time 中将找不到 time

更新两个数据帧:

import pandas as pd

# create dataframes from your test set and clean-up the datetime columns
df_a['time'] = (pd.to_datetime(df_a['time'], format='%d.%m.%Y %H:%M:%S')).dt.date
df_b['start-date'] = pd.to_datetime(df_b['start-date'], format='%d.%m.%Y %H:%M:%S').dt.date
df_b['end-date'] = pd.to_datetime(df_b['end-date'], format='%d.%m.%Y %H:%M:%S').dt.date

# df_a view

time project
2015-05-06 project1
2015-06-22 project2
2015-05-28 project2
2015-06-28 project1

# df_b view

start-date end-date project maturity
2015-05-02 2015-06-24 project1 one
2015-06-26 2015-07-27 project1 two
2015-05-16 2015-05-27 project2 one
2015-05-30 2015-06-27 project2 two

# add d_range to df_b
df_b['d_range'] = df_b[['start-date', 'end-date']].apply(lambda x: pd.date_range(x[0], x[1]), axis=1)

成熟度 添加到 df_a

  • mask 是从 df_a 中搜索 df_b 日期的结果
    • mask 与任何项目的日期匹配
  • 仅返回匹配项目的结果
def date_query(x):
mask = df_b[['project', 'maturity']][df_b['d_range'].apply(lambda y: y.isin([x[0]]).any())].reset_index(drop=True)
result = mask['maturity'][mask['project'] == x[1]].reset_index(drop=True)
return result

# call function
df_a['maturity'] = df_a.apply(lambda x: date_query(x), axis=1)

# df_a updated

time project maturity
2015-05-06 project1 one
2015-06-22 project2 two
2015-05-28 project2 NaN
2015-06-28 project1 two

项目 3:

  • result from def date_query 是一个 pandas.Series,如果没有匹配的日期范围,则为空,可以是使用 .empty
  • 检查
  • 更新 def date_query 以检查 result 是否为空。如果 result 为空,则调用 def check_min_timedelta
  • 如果有多个匹配的最小值,.idxmin 将返回第一个出现的
def check_min_timedelta(x):
"""
Create a timedelta between time and end-date
Return maturity for the row with the minimum time date
"""
end_diff = abs(df_b['end-date'][df_b['project'] == x[1]] - x[0]).idxmin()
return df_b['maturity'].loc[end_diff]

# update def date_query
def date_query(x):
mask = df_b[['project', 'maturity']][df_b['d_range'].apply(lambda y: y.isin([x[0]]).any())].reset_index(drop=True)
result = mask['maturity'][mask['project'] == x[1]].reset_index(drop=True)
if result.empty:
result = check_min_timedelta(x)
return result

# call function
df_a['maturity'] = df_a.apply(lambda x: date_query(x), axis=1)

# final df_a:

time project maturity
2015-05-06 project1 one
2015-06-22 project2 two
2015-05-28 project2 one
2015-06-28 project1 two

替代方法:

  • 这类似于使用不等式将时间开始日期结束日期进行比较的原始方法
  • 此方法不依赖于创建日期范围列表列
  • def date_query(x): 已更新,.dt.date 已删除。
df_a['time'] = pd.to_datetime(df_a['time'], format='%d.%m.%Y %H:%M:%S')
df_b['start-date'] = pd.to_datetime(df_b['start-date'], format='%d.%m.%Y %H:%M:%S')
df_b['end-date'] = pd.to_datetime(df_b['end-date'], format='%d.%m.%Y %H:%M:%S')

def check_min_timedelta(x):
"""
Create a timedelta between time and end-date
Return maturity for the row with the minimum time date
"""
end_diff = abs(df_b['end-date'][df_b['project'] == x[1]] - x[0]).idxmin()
return df_b['maturity'].loc[end_diff]

# update def date_query
def date_query(x):
mask = df_b[['project', 'maturity']][df_b[['start-date', 'end-date']].apply(lambda y: ((x[0] >= y[0]) & (x[0] <= y[1])), axis=1)].reset_index(drop=True)
result = mask['maturity'][mask['project'] == x[1]].reset_index(drop=True)
if result.empty:
result = check_min_timedelta(x)
return result

# call function
df_a['maturity'] = df_a.apply(lambda x: date_query(x), axis=1)

关于python - 如果日期在另一个数据帧的日期范围内且项目相等,则在一个数据帧中分配值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58698491/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com