หากต้องโทรซ้ำ ๆ (สำหรับขอบเขตที่แตกต่างกันและ) งานจำนวนมากจะถูกทำซ้ำโดยไม่จำเป็น ในกรณีนี้มันเป็นประโยชน์ในการจัดเรียงกรอบ / ซีรีส์ครั้งเดียวแล้วใช้ ฉันวัดความเร็วได้สูงสุด 25x ดูด้านล่างpd.Series.between(l,r)
l
r
pd.Series.searchsorted()
def between_indices(x, lower, upper, inclusive=True):
"""
Returns smallest and largest index i for which holds
lower <= x[i] <= upper, under the assumption that x is sorted.
"""
i = x.searchsorted(lower, side="left" if inclusive else "right")
j = x.searchsorted(upper, side="right" if inclusive else "left")
return i, j
x = x.sort_values().reset_index(drop=True)
ret1 = between_indices(x, lower=0.1, upper=0.9)
ret2 = between_indices(x, lower=0.2, upper=0.8)
ret3 = ...
เกณฑ์มาตรฐาน
การวัดประเมินผลซ้ำ ( n_reps=100
) ของpd.Series.between()
เช่นเดียวกับวิธีการที่อยู่บนพื้นฐานpd.Series.searchsorted()
สำหรับข้อโต้แย้งที่แตกต่างกันและlower
upper
ใน MacBook Pro 2015 ของฉันที่มี Python v3.8.0 และ Pandas v1.0.3 โค้ดด้านล่างส่งผลให้เกิดผลลัพธ์ดังต่อไปนี้
import numpy as np
import pandas as pd
def between_indices(x, lower, upper, inclusive=True):
i = x.searchsorted(lower, side="left" if inclusive else "right")
j = x.searchsorted(upper, side="right" if inclusive else "left")
return i, j
def between_fast(x, lower, upper, inclusive=True):
"""
Equivalent to pd.Series.between() under the assumption that x is sorted.
"""
i, j = between_indices(x, lower, upper, inclusive)
if True:
return x.iloc[i:j]
else:
mask = np.zeros_like(x, dtype=bool)
mask[i:j] = True
mask = pd.Series(mask, index=x.index)
return x[mask]
def between(x, lower, upper, inclusive=True):
mask = x.between(lower, upper, inclusive=inclusive)
return x[mask]
def between_expr(x, lower, upper, inclusive=True):
if inclusive:
mask = (x>=lower) & (x<=upper)
else:
mask = (x>lower) & (x<upper)
return x[mask]
def benchmark(func, x, lowers, uppers):
for l,u in zip(lowers, uppers):
func(x,lower=l,upper=u)
n_samples = 1000
n_reps = 100
x = pd.Series(np.random.randn(n_samples))
x = x.sort_values().reset_index(drop=True)
assert(between_fast(x, 0, 1, True ).equals(between(x, 0, 1, True)))
assert(between_expr(x, 0, 1, True ).equals(between(x, 0, 1, True)))
assert(between_fast(x, 0, 1, False).equals(between(x, 0, 1, False)))
assert(between_expr(x, 0, 1, False).equals(between(x, 0, 1, False)))
uppers = np.linspace(0, 3, n_reps)
lowers = -uppers
%timeit benchmark(between_fast, x, lowers, uppers)
%timeit benchmark(between, x, lowers, uppers)
%timeit benchmark(between_expr, x, lowers, uppers)