有没有办法让这个自定义函数更快地使用Pandas和/或numpy?

ykejflvf  于 2023-02-14  发布在  其他
关注(0)|答案(2)|浏览(106)

我有一个包含两列的 Dataframe 。每列都有用“/”符号分隔的小时:分钟值。它们对应于出发和到达时间。我想做的是计算每次到达和下一次出发之间的等待时间,如果任何等待时间大于8小时,我就输出。我已经写了一个函数来完成这个任务,但它非常慢。我的数据有超过200万个条目。下面是名为sample的示例 Dataframe :

segmentDepartureTimes   segmentArrivalTimes
0   20:10/07:45/10:05/17:05 22:00/09:00/11:10/19:05
1   07:20/11:25/13:10   08:55/12:15/14:40
2   20:50/11:25/13:10   22:25/12:15/14:40
3   16:50/21:15/19:00   18:10/22:05/20:40
4   15:50/21:15/19:00   17:10/22:05/20:40

因此,在第一行中,将是22:00和07:45、09:00和10:05、11:10和17:05之间的时差。

def long_layover(departureSegments, arrivalSegments):
    a = departureSegments.split("/")
    b = arrivalSegments.split("/")
    # we need to remove the first element from departures and last from arrivals
    aa = pd.Series(a[1:])
    bb = pd.Series(b[:-1])
    
    def time_difference_pandas(time1, time2):
        time1_dt = pd.to_datetime(time1, format="%H:%M").dt.time
        time2_dt = pd.to_datetime(time2, format="%H:%M").dt.time
        time1_str = [time.strftime("%H:%M") for time in time1_dt]
        time2_str = [time.strftime("%H:%M") for time in time2_dt]
        difference = abs((pd.to_datetime(time2_str, infer_datetime_format=True) - 
                          pd.to_datetime(time1_str, infer_datetime_format=True)).total_seconds() / 3600)
        return difference
    
    hours = time_difference_pandas(bb, aa)
    
    return (hours>8).any()

示例的输出为:

sample[["segmentDepartureTimes", "segmentArrivalTimes"]].apply(lambda x: long_layover(x[0], x[1]), axis = 1)

0       True
1      False
2       True
3      False
4      False

有什么方法可以使这个函数更有效吗?也许使用一些矢量化?谢谢你提前

2ic8powd

2ic8powd1#

对于包含1000个条目的 Dataframe ,您的版本需要1.71秒

%timeit df[["segmentDepartureTimes", "segmentArrivalTimes"]].apply(lambda x: long_layover(x[0], x[1]), axis = 1)

1.71 s ± 7.15 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

我写了以下代码的基础上,你给的数据,这给了我一个运行时间为3.83毫秒,系数446!

def faster(df):

    df.segmentDepartureTimes = df.segmentDepartureTimes.str[6:]
    df.segmentArrivalTimes = df.segmentArrivalTimes.str[:-6]
    
    deps = df.segmentDepartureTimes.str.split("/", expand=True).apply(pd.to_datetime, errors='coerce')
    arvs = df.segmentArrivalTimes.str.split("/", expand=True).apply(pd.to_datetime, errors='coerce')
    
    return ((arvs - deps) / np.timedelta64(1, 'h')).gt(8).any(axis=1)

统计数据:

%timeit faster(df)

3.83 ms ± 39.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

它之所以快是因为我没有一行一行的计算,而是利用Pandas的优势一次性完成计算。
编辑:200万个条目花了3.22秒。

axr492tv

axr492tv2#

a = (
    sample["segmentDepartureTimes"]
    .str.split("/", n=1, expand=True)[1]
    .str.split("/", expand=True)
    .apply(pd.to_datetime)
)
b = (
    sample["segmentArrivalTimes"]
    .str.rsplit("/", n=1, expand=True)[0]
    .str.split("/", expand=True)
    .apply(pd.to_datetime)
)
((b - a).abs() / pd.Timedelta(1, unit="h") > 8).any(axis=1)

相关问题