gpt4 book ai didi

python - 有效检查数据帧是否具有范围内的日期,并返回计数

转载 作者:行者123 更新时间:2023-12-02 14:53:12 24 4
gpt4 key购买 nike

假设我们有一个数据框 df,其中包含按日期按时间顺序排列的日期列表。

目标是获取给定日期内包含给定日期的日期范围的人数。

df = pd.DataFrame(data={'date': [datetime.date(2007, 12, 1), 
datetime.date(2007, 12, 2),
datetime.date(2007, 12, 3)],
'num_people_on_day': [0,0,0]})

dg = pd.DataFrame(data={'person': ['Alice', 'Bob', 'Chuck'],
'start': [datetime.date(2007, 11, 5),
datetime.date(2007, 12, 8),
datetime.date(2007, 1, 5)],
'end': [datetime.date(2007, 12, 6),
datetime.date(2008, 1, 3),
datetime.date(2007, 11, 30)]})

enter image description here

那么对于df中的每个日期,如何有效地检查所有dg,然后计算返回的数字并将其放入df .

我什至不确定这里是否需要合并(也试图节省内存),并且我真的想尽可能快地编写它。

编辑:好吧,我想出了一种不同的方法来做到这一点,但我讨厌使用 apply。有没有办法在不使用 .apply 的情况下实现这种新方式?

import pandas as pd
import datetime

df = pd.DataFrame(data={'date': [datetime.date(2007, 12, 1),
datetime.date(2007, 12, 2),
datetime.date(2007, 12, 3)]})

dg = pd.DataFrame(data={'person': ['Alice', 'Bob', 'Chuck', 'Dave'],
'start': [datetime.date(2007, 11, 5),
datetime.date(2007, 12, 8),
datetime.date(2007, 1, 5),
datetime.date(2007, 11, 6)],
'end': [datetime.date(2007, 12, 1),
datetime.date(2008, 1, 3),
datetime.date(2007, 11, 30),
datetime.date(2007, 12, 2)]})

def get_num_persons(date, vec_starts, vec_ends):
"""
Helper function for .apply to get number of persons.
For each given date, if start and end date is
between the given date, then both results are True.
The bitwise AND then only sums these True and True values.
"""
return (((vec_starts <= date) & (vec_ends >= date)).sum())

def num_of_persons(persons, dates_df):
"""
Obtains the number of persons for each day.
"""
dates_df['num_persons'] = dates_df['date'].apply(lambda row:
get_num_persons(row,
persons['start'],
persons['end']))
return dates_df

num_of_persons(dg, df.copy())

最佳答案

有了足够的内存,合并,然后计算介于两者之间的日期。 .reindex 确保我们得到 0。

#df['date'] = pd.to_datetime(df.date)
#dg['start'] = pd.to_datetime(dg.start)
#dg['end'] = pd.to_datetime(dg.end)

m = df[['date']].assign(k=1).merge(dg.assign(k=1))

(m[m.date.between(m.start, m.end)].groupby('date').size()
.reindex(df.date).fillna(0)
.rename('num_people_on_day').reset_index())

date num_people_on_day
0 2007-12-01 1
1 2007-12-02 1
2 2007-12-03 1
<小时/>

另一个选项是使用 apply。这是一个循环,因此随着 df 的增长,性能会受到影响。

def get_len(x, dg):
try:
return len(dg.iloc[dg.index.get_loc(x)])
except KeyError: # Deal with dates that have 0
return 0

dg.index = pd.IntervalIndex.from_arrays(dg['start'], dg['end'], closed='both')
df['num_people_on_day'] = df['date'].apply(get_len, dg=dg)
<小时/>

为了说明时序,请查看您的小集合,然后查看更大的 df

%%timeit 
m = df[['date']].assign(k=1).merge(dg.assign(k=1))
(m[m.date.between(m.start, m.end)].groupby('date').size()
.reindex(df.date).fillna(0)
.rename('num_people_on_day').reset_index())
#9.39 ms ± 52 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
dg.index = pd.IntervalIndex.from_arrays(dg['start'], dg['end'], closed='both')
df['num_people_on_day'] = df['date'].apply(get_len, dg=dg)
#4.06 ms ± 27.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

但是一旦 df 更长(即使只有 90 行),差异就会变得明显。

df = pd.DataFrame({'date': pd.date_range('2007-01-01', '2007-03-31')})

%%timeit merge
#9.78 ms ± 75.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit IntervalIndex
#65.5 ms ± 418 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

关于python - 有效检查数据帧是否具有范围内的日期,并返回计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56688364/

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