从 pandas 数据框指定的间隔内的列表中提取值

extract values from a list that falls in intervals specified by pandas dataframe

我有一个长度为 103237 的巨大列表。我有一个形状为 (8173,6) 的数据框。我想从 pandas 数据框中的两列 (1 AND 2) 指定的值之间的列表中提取这些值。例如:


lst = [182,73,137,1,938]

###dataframe

0       1     2      3    4
John   150   183    NY    US
Peter   30   50     SE    US
Stef   900   969    NY    US

预期输出列表:

lst = [182,938]

由于 182 位于数据帧第一行的 150 和 183 之间,而 938 位于第 3 行的 900 和 969 之间,因此我希望新列表包含原始列表中的 182 和 938。为了解决这个问题,我将数据框转换为 numpy 数组:


nn = df.values()

new_list = []
for item in lst:
    for i in range(nn.shape[0]):
        if item >= nn[i][1] and item <= nn[i][2]:
            new_list.append(item)

但上面提到的代码自 O(n^2) 以来花费了很长时间,而且它不能很好地扩展到我的列表,它有 103237 个项目。如何更有效地做到这一点?

您可以迭代列表并将每个元素与第 1 列和第 2 列的所有对进行比较,看看是否有任何对包含该元素。

[e for e in lst if (df['1'].lt(e) & df['2'].gt(e)).any()]

我用列表中的 110000 个元素和数据框中的 9000 行进行了测试,代码在 macbook pro 上 运行 需要 32 秒。

考虑以下问题:假设您有一个值 item,您可以通过以下行询问是否在任何区间内

((df[1] <= item) & (df[2] >= item)).any()

语句 (df[1] <= item)(df[2] >= item) return true/false 的布尔数组。 '&' 将 return 一个布尔数组,无论 item 是否在特定区间内。如果布尔数组中有任何 True 值,则在最后 return 添加 any() 为 true,也就是如果有一个间隔为“True”(数字在间隔内)。

所以对于单个项目,您可以通过上面的行得到答案。

要扫描所有项目,您可以执行以下操作:

new_list = []
for item in lst:
    if ((df[1] <= item) & (df[2] >= item)).any():
        new_list.append(item)

或列表理解:

new_list = [item for item in lst if ((df[1] <= item) & (df[2] >= item)).any()]

编辑:如果此代码太慢,您可以使用 numba 进一步加速,但我相信使用 pandas 矢量化(又名使用 df[1]<=item 就足够了)