Pandas优化插值/计数算法



我有一堆数据(10M多条记录),这些数据分解为标识符、位置和日期。我想找出在整个日期集内,任何标识符从某个位置A移动到另一个位置B的次数。任何标识符都可能没有所有可能日期的位置。当标识符没有记录位置时,应将其视为该日期的实际"未知"位置。

这里有一些可复制的伪造数据。。。

import numpy as np
import pandas as pd
import datetime
base = datetime.date.today()
num_days = 50
dates = np.array([base - datetime.timedelta(days=x) for x in range(num_days-1, -1, -1)])
ids = np.arange(50)
mi = pd.MultiIndex.from_product([ids, dates])
locations = np.array([chr(x) for x in 97 + np.random.randint(26, size=len(mi))])
s = pd.Series(locations, index=mi)
mask = np.random.rand(len(mi)) > .5
s[mask] = np.nan
s = s.dropna()

我最初的想法是创建一个数据帧,并使用布尔掩码/矢量化操作来解决这个

df = s.unstack(0).fillna('unknown')

显然,我的数据很稀疏,足以导致MemoryError(来自于所有因拆堆而产生的额外条目)。

我目前的工作解决方案是以下

def series_fn(s):
    s = s.reindex(pd.date_range(s.index.levels[1].min(), s.index.levels[1].max()), level=-1).fillna('unknown')
    mask_prev = (s != s.shift(-1))[:-1]
    mask_next = (s != s.shift())[1:]
    s_prev = s[:-1][mask_prev]
    s_next = s[1:][mask_next]
    s_tup = pd.Series(list(zip(s_prev, s_next)))
    return s_tup.value_counts()
result_per_id = s.groupby(level=0).apply(series_fn)
result = result_per_id.sum(level=-1)

result看起来像

(a, b)    1
(a, c)    5
(a, e)    3
(a, f)    3
(a, g)    3
(a, h)    3
(a, i)    1
(a, j)    1
(a, k)    2
(a, l)    2
...

我的所有数据都需要大约5个小时。有人知道有什么更快的方法吗?谢谢

嗯,我想我应该把数据转置了。。。这是一个相对简单的解决方案。不使用groupby和apply

s = s.reorder_levels(['date', 'id'])
s = s.sortlevel(0)
results = []
for i in range(len(s.index.levels[0])-1):
    t = time.time()
    s0 = s.loc[s.index.levels[0][i]]
    s1 = s.loc[s.index.levels[0][i+1]]
    df = pd.concat((s0, s1), axis=1)
    # Note: this is slower than the line above
    # df = s.loc[s.index.levels[0][0:2], :].unstack(0)
    df = df.fillna('unknown')
    mi = pd.MultiIndex.from_arrays((df.iloc[:, 0], df.iloc[:, 1]))
    s2 = pd.Series(1, mi)
    res = s2.groupby(level=[0, 1]).apply(np.sum)
    results.append(res)
    print(time.time() - t)
results = pd.concat(results, axis=1)

仍然不清楚为什么注释掉的部分的长度大约是上面三行的三倍。

最新更新