Usually, we seek a tradeoff between elegant and efficient solutions.
The pandas.Series.str.startswith is faster than the numpy.char.startswith for this test case and both are quite elegant but slower than the numerical approach proposed by @mozway.
Here we have the three solutions:
import numpy as np
import pandas as pd
def pandas_solution(arr, num):
return pd.Series(arr).str.startswith(str(num)).values
def mozway_solution(arr, num):
n = int(np.ceil(np.log10(arr + 1)))
n2 = np.ceil(np.log10(arr + 1)).astype(int)
out = arr // 10 ** np.clip((n2 - n), 0, np.inf) == num
return out
def numpy_solution(arr, num):
return np.char.startswith(arr, str(num))
And here is our test:
import random
import time
import matplotlib.pyplot as plt
labels = ["Pandas", "Mozway", "Numpy Char"]
sizes = [1000, 10000, 10000, 1000000]
fig, axs = plt.subplots(1, 4, figsize=(20, 3))
for counter, ax in zip(sizes, axs):
pandas_time = []
mozway_time = []
numpy_time = []
arr_int = np.array([random.randint(0, 1000) for _ in range(counter)])
arr_str = np.array(arr_int, dtype="str")
for trial in range(10):
start = time.time()
pandas_solution(arr_str, 42)
end = time.time()
pandas_time.append(end - start)
start = time.time()
mozway_solution(arr_int, 42)
end = time.time()
mozway_time.append(end - start)
start = time.time()
numpy_solution(arr_str, 42)
end = time.time()
numpy_time.append(end - start)
ax.set_title("Size of array: " + str(counter))
ax.boxplot([pandas_time, mozway_time, numpy_time], labels=labels)
With the following results:
