python - Pandas `isin` 函数的更快替代方案

标签 python numpy pandas

我有一个非常大的数据框 df,看起来像:

ID       Value1    Value2
1345      3.2      332
1355      2.2      32
2346      1.0      11
3456      8.9      322

我有一个包含 ID ID_list 子集的列表。对于 ID_list 中包含的 ID,我需要有一个 df 的子集。

目前,我正在使用 df_sub=df[df.ID.isin(ID_list)] 来做这件事。但这需要很多时间。 ID_list 中包含的ID 没有任何规律,因此不在一定范围内。 (而且我需要对许多类似的数据帧应用相同的操作。我想知道是否有更快的方法来做到这一点。如果将 ID 作为索引会有很大帮助吗?

谢谢!

最佳答案

编辑 2:这是对各种 pandas 操作性能的最新研究的链接,尽管它似乎不包括迄今为止的合并和连接。

https://github.com/mm-mansour/Fast-Pandas

编辑 1:这些基准测试适用于相当旧的 pandas 版本,可能仍然不相关。请参阅下面 Mike 关于 merge 的评论。

这取决于数据的大小,但对于大型数据集 DataFrame.join似乎是要走的路。这要求您的 DataFrame 索引是您的“ID”,而您要加入的系列或 DataFrame 的索引是您的“ID_list”。该系列还必须有一个 name 才能与 join 一起使用,它会作为一个名为 name 的新字段被引入。您还需要指定一个内部联接以获得类似 isin 的内容,因为 join 默认为左联接。查询 in 语法似乎具有与大型数据集的 isin 相同的速度特性。

如果您处理的是小型数据集,您会得到不同的行为,实际上使用列表推导或应用字典比使用 isin 更快。​​

否则,您可以尝试使用 Cython 获得更快的速度.

# I'm ignoring that the index is defaulting to a sequential number. You
# would need to explicitly assign your IDs to the index here, e.g.:
# >>> l_series.index = ID_list
mil = range(1000000)
l = mil
l_series = pd.Series(l)

df = pd.DataFrame(l_series, columns=['ID'])


In [247]: %timeit df[df.index.isin(l)]
1 loops, best of 3: 1.12 s per loop

In [248]: %timeit df[df.index.isin(l_series)]
1 loops, best of 3: 549 ms per loop

# index vs column doesn't make a difference here
In [304]: %timeit df[df.ID.isin(l_series)]
1 loops, best of 3: 541 ms per loop

In [305]: %timeit df[df.index.isin(l_series)]
1 loops, best of 3: 529 ms per loop

# query 'in' syntax has the same performance as 'isin'
In [249]: %timeit df.query('index in @l')
1 loops, best of 3: 1.14 s per loop

In [250]: %timeit df.query('index in @l_series')
1 loops, best of 3: 564 ms per loop

# ID must be the index for DataFrame.join and l_series must have a name.
# join defaults to a left join so we need to specify inner for existence.
In [251]: %timeit df.join(l_series, how='inner')
10 loops, best of 3: 93.3 ms per loop

# Smaller datasets.
df = pd.DataFrame([1,2,3,4], columns=['ID'])
l = range(10000)
l_dict = dict(zip(l, l))
l_series = pd.Series(l)
l_series.name = 'ID_list'


In [363]: %timeit df.join(l_series, how='inner')
1000 loops, best of 3: 733 µs per loop

In [291]: %timeit df[df.ID.isin(l_dict)]
1000 loops, best of 3: 742 µs per loop

In [292]: %timeit df[df.ID.isin(l)]
1000 loops, best of 3: 771 µs per loop

In [294]: %timeit df[df.ID.isin(l_series)]
100 loops, best of 3: 2 ms per loop

# It's actually faster to use apply or a list comprehension for these small cases.
In [296]: %timeit df[[x in l_dict for x in df.ID]]
1000 loops, best of 3: 203 µs per loop

In [299]: %timeit df[df.ID.apply(lambda x: x in l_dict)]
1000 loops, best of 3: 297 µs per loop

关于python - Pandas `isin` 函数的更快替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23945493/

相关文章:

python - 将 numpy 字符串数组转换为日期时间

python - 如何在pandas中处理这个逻辑

python - 删除 Python 中的特定字符/字符串/字符序列

python - Pandas - 在包含间隔的 MultiIndex 上建立索引

python - 如何在 webdriver (Python) 中打开新窗口或标签?

python - psutil:获取所有进程的cpu

python - 如何有效地在具有不同维度的多维 numpy 数组中添加列?

python - 协方差矩阵的对角元素不是 1 pandas/numpy

python - 如何模拟Python中的模块但不是所有方法

python - 导入错误: No module named 'rasterio.vrt'