203

我知道这是一个非常基本的问题,但由于某种原因我找不到答案。如何在 python pandas 中获取某个 Series 元素的索引?(第一次出现就足够了)

即,我想要类似的东西:

import pandas as pd
myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
print myseries.find(7) # should output 3

当然,可以用循环定义这样的方法:

def find(s, el):
    for i in s.index:
        if s[i] == el: 
            return i
    return None

print find(myseries, 7)

但我认为应该有更好的方法。在那儿?

4

11 回答 11

252
>>> myseries[myseries == 7]
3    7
dtype: int64
>>> myseries[myseries == 7].index[0]
3

虽然我承认应该有更好的方法来做到这一点,但这至少避免了迭代和循环对象并将其移动到 C 级别。

于 2013-08-20T05:52:43.623 回答
53

转换为索引,您可以使用get_loc

In [1]: myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])

In [3]: Index(myseries).get_loc(7)
Out[3]: 3

In [4]: Index(myseries).get_loc(10)
KeyError: 10

重复处理

In [5]: Index([1,1,2,2,3,4]).get_loc(2)
Out[5]: slice(2, 4, None)

如果非连续返回,将返回一个布尔数组

In [6]: Index([1,1,2,1,3,2,4]).get_loc(2)
Out[6]: array([False, False,  True, False, False,  True, False], dtype=bool)

在内部使用哈希表,速度非常快

In [7]: s = Series(randint(0,10,10000))

In [9]: %timeit s[s == 5]
1000 loops, best of 3: 203 µs per loop

In [12]: i = Index(s)

In [13]: %timeit i.get_loc(5)
1000 loops, best of 3: 226 µs per loop

正如 Viktor 指出的那样,创建索引有一次性的创建开销(当您实际对索引执行某些操作时会产生开销,is_unique例如

In [2]: s = Series(randint(0,10,10000))

In [3]: %timeit Index(s)
100000 loops, best of 3: 9.6 µs per loop

In [4]: %timeit Index(s).is_unique
10000 loops, best of 3: 140 µs per loop
于 2013-08-20T11:37:59.547 回答
20

我对这里的所有答案印象深刻。这不是一个新的答案,只是试图总结所有这些方法的时间安排。我考虑了具有 25 个元素的系列的情况,并假设索引可以包含任何值的一般情况,并且您希望索引值对应于接近系列末尾的搜索值。

以下是在 Python 3.9.10 和 Pandas 版本 1.4.0 中对 2012 Mac Mini 进行的速度测试。

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: data = [406400, 203200, 101600, 76100, 50800, 25400, 19050, 12700, 950
   ...: 0, 6700, 4750, 3350, 2360, 1700, 1180, 850, 600, 425, 300, 212, 150, 1
   ...: 06, 75, 53, 38]

In [4]: myseries = pd.Series(data, index=range(1,26))

In [5]: assert(myseries[21] == 150)

In [6]: %timeit myseries[myseries == 150].index[0]
179 µs ± 891 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [7]: %timeit myseries[myseries == 150].first_valid_index()
205 µs ± 3.67 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [8]: %timeit myseries.where(myseries == 150).first_valid_index()
597 µs ± 4.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [9]: %timeit myseries.index[np.where(myseries == 150)[0][0]]
110 µs ± 872 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [10]: %timeit pd.Series(myseries.index, index=myseries)[150]
125 µs ± 2.56 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [11]: %timeit myseries.index[pd.Index(myseries).get_loc(150)]
49.5 µs ± 814 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [12]: %timeit myseries.index[list(myseries).index(150)]
7.75 µs ± 36.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [13]: %timeit myseries.index[myseries.tolist().index(150)]
2.55 µs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [14]: %timeit dict(zip(myseries.values, myseries.index))[150]
9.89 µs ± 79.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [15]: %timeit {v: k for k, v in myseries.items()}[150]
9.99 µs ± 67 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

@Jeff 的答案似乎是最快的——尽管它不处理重复项。

更正:对不起,我错过了一个,@Alex Spangher 使用列表索引方法的解决方案是迄今为止最快的。

更新:添加了@EliadL 的答案。

希望这可以帮助。

令人惊讶的是,如此简单的操作需要如此复杂的解决方案,而且许多解决方案如此缓慢。在某些情况下超过半毫秒才能找到一系列 25 中的值。

2022-02-18 更新

使用最新的 Pandas 版本和 Python 3.9 更新了所有时间。即使在较旧的计算机上,与之前的测试(版本 0.25.3)相比,所有时间都显着减少(10% 到 70%)。

加:增加了两个使用字典的方法。

于 2019-08-31T22:13:30.923 回答
15
In [92]: (myseries==7).argmax()
Out[92]: 3

如果您提前知道 7 存在,则此方法有效。您可以使用 (myseries==7).any() 进行检查

另一种方法(与第一个答案非常相似)也解释了多个 7(或没有)是

In [122]: myseries = pd.Series([1,7,0,7,5], index=['a','b','c','d','e'])
In [123]: list(myseries[myseries==7].index)
Out[123]: ['b', 'd']
于 2015-04-08T08:12:33.503 回答
7

另一种方法是:

s = pd.Series([1,3,0,7,5],index=[0,1,2,3,4])

list(s).index(7)

回报:3

使用我正在使用的当前数据集进行准时测试(认为它是随机的):

[64]:    %timeit pd.Index(article_reference_df.asset_id).get_loc('100000003003614')
10000 loops, best of 3: 60.1 µs per loop

In [66]: %timeit article_reference_df.asset_id[article_reference_df.asset_id == '100000003003614'].index[0]
1000 loops, best of 3: 255 µs per loop


In [65]: %timeit list(article_reference_df.asset_id).index('100000003003614')
100000 loops, best of 3: 14.5 µs per loop
于 2014-09-17T20:09:24.307 回答
6

如果你使用 numpy,你可以得到一个包含你的值的 indecies 的数组:

import numpy as np
import pandas as pd
myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
np.where(myseries == 7)

这将返回一个包含 indecies 数组的单元素元组,其中 7 是 myseries 中的值:

(array([3], dtype=int64),)
于 2016-09-05T00:01:51.813 回答
5

你可以使用 Series.idxmax()

>>> import pandas as pd
>>> myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
>>> myseries.idxmax()
3
>>> 
于 2017-03-25T05:15:59.523 回答
4

这是我能找到的最原生和可扩展的方法:

>>> myindex = pd.Series(myseries.index, index=myseries)

>>> myindex[7]
3

>>> myindex[[7, 5, 7]]
7    3
5    4
7    3
dtype: int64
于 2020-01-01T13:09:29.067 回答
2

另一种尚未提及的方法是 tolist 方法:

myseries.tolist().index(7)

应该返回正确的索引,假设该值存在于系列中。

于 2019-10-29T22:02:43.323 回答
1

您的价值通常出现在多个指数上:

>>> myseries = pd.Series([0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1])
>>> myseries.index[myseries == 1]
Int64Index([3, 4, 5, 6, 10, 11], dtype='int64')
于 2018-08-21T09:49:15.757 回答
1

Pandas 有一个内置类Index,其中包含一个名为get_loc. 这个函数要么返回

index(元素索引)
slice(如果指定的数字在序列中)
数组(如果数字在多个索引处,则为布尔数组)

例子:

import pandas as pd

>>> mySer = pd.Series([1, 3, 8, 10, 13])
>>> pd.Index(mySer).get_loc(10)  # Returns index
3  # Index of 10 in series

>>> mySer = pd.Series([1, 3, 8, 10, 10, 10, 13])
>>> pd.Index(mySer).get_loc(10)  # Returns slice
slice(3, 6, None)  # 10 occurs at index 3 (included) to 6 (not included)


# If the data is not in sequence then it would return an array of bool's.
>>> mySer = pd.Series([1, 10, 3, 8, 10, 10, 10, 13, 10])
>>> pd.Index(mySer).get_loc(10)
array([False, True, False, False, True, True, False, True])

还有很多其他选择,但我发现它对我来说非常简单。

于 2021-07-10T06:23:06.760 回答