Python 如何查找熊猫系列中与输入编号最接近的值?

Python 如何查找熊猫系列中与输入编号最接近的值?,python,pandas,dataframe,ranking,Python,Pandas,Dataframe,Ranking,我看到: 这些与香草蟒蛇有关,而不是熊猫 如果我有这个系列: ix num 0 1 1 6 2 4 3 5 4 2 我输入3,如何(有效地)查找 如果在序列中找到,则索引为3 如果在序列中找不到低于或高于3的值的索引 也就是说,通过上面的序列{1,6,4,5,2},输入3,我应该得到带有索引(2,4)的值(4,2)。您可以像这样使用argsort() 比如说,input=3 In [198]: input = 3 In [199]: df.ilo

我看到:

这些与香草蟒蛇有关,而不是熊猫

如果我有这个系列:

ix   num  
0    1
1    6
2    4
3    5
4    2
我输入3,如何(有效地)查找

  • 如果在序列中找到,则索引为3
  • 如果在序列中找不到低于或高于3的值的索引

  • 也就是说,通过上面的序列{1,6,4,5,2},输入3,我应该得到带有索引(2,4)的值(4,2)。

    您可以像这样使用
    argsort()

    比如说,
    input=3

    In [198]: input = 3
    
    In [199]: df.iloc[(df['num']-input).abs().argsort()[:2]]
    Out[199]:
       num
    2    4
    4    2
    
    df_sort
    是具有两个最接近值的数据帧

    In [200]: df_sort = df.iloc[(df['num']-input).abs().argsort()[:2]]
    
    对于索引

    In [201]: df_sort.index.tolist()
    Out[201]: [2, 4]
    
    对于价值观

    In [202]: df_sort['num'].tolist()
    Out[202]: [4, 2]
    

    上述解决方案的详细信息
    df

    In [197]: df
    Out[197]:
       num
    0    1
    1    6
    2    4
    3    5
    4    2
    

    除了John Galt的答案之外,我建议使用
    iloc
    ,因为这甚至适用于未排序的整数索引,因为它首先查看索引标签

    df.iloc[(df['num']-input).abs().argsort()[:2]]
    

    如果您的序列已经排序,您可以使用类似这样的内容

    def closest(df, col, val, direction):
        n = len(df[df[col] <= val])
        if(direction < 0):
            n -= 1
        if(n < 0 or n >= len(df)):
            print('err - value outside range')
            return None
        return df.ix[n, col]    
    
    df = pd.DataFrame(pd.Series(range(0,10,2)), columns=['num'])
    for find in range(-1, 2):
        lc = closest(df, 'num', find, -1)
        hc = closest(df, 'num', find, 1)
        print('Closest to {} is {}, lower and {}, higher.'.format(find, lc, hc))
    
    
    df:     num
        0   0
        1   2
        2   4
        3   6
        4   8
    err - value outside range
    Closest to -1 is None, lower and 0, higher.
    Closest to 0 is 0, lower and 2, higher.
    Closest to 1 is 0, lower and 2, higher.
    
    def最近距离(df、col、val、方向):
    n=len(df[df[col]=len(df)):
    打印('错误-值超出范围')
    一无所获
    返回df.ix[n,col]
    df=pd.DataFrame(pd.Series(范围(0,10,2)),列=['num']
    对于范围内的查找(-1,2):
    lc=最近(df,'num',find,-1)
    hc=最近(df,‘num’,find,1)
    print('最接近{}的是{},较低和{},较高。'.format(find,lc,hc))
    df:num
    0   0
    1   2
    2   4
    3   6
    4   8
    err-值超出范围
    最接近-1的值为无,较低,0,较高。
    最接近0的是0,更低,2,更高。
    最接近1的值为0,较低;最接近2的值为2,较高。
    
    除了没有完全回答这个问题之外,这里讨论的其他算法的另一个缺点是它们必须对整个列表进行排序。这导致复杂性~N log(N)

    但是,在~N中也可以获得相同的结果。这种方法将数据帧分为两个子集,一个子集比所需值小,一个子集比所需值大。较小数据帧中的下邻居比最大值小,反之亦然

    这将提供以下代码段:

    def find_邻居(值、df、colname):
    exactmatch=df[df[colname]==value]
    如果不是exactmatch.empty:
    返回exactmatch.index
    其他:
    lowerneighbour_ind=df[df[colname]value][colname].idxmin()
    返回[lowerneighbour\u ind,Upper Neighbour\u ind]
    
    这种方法类似于使用,在处理大型数据集时非常有用,复杂性成为一个问题


    比较这两种策略表明,对于大N,分区策略确实更快。对于小N,排序策略将更有效,因为它是在一个更低的级别实现的。它也是一个单行程序,可能会增加代码可读性。

    复制此图的代码如下所示:

    from matplotlib import pyplot as plt
    import pandas
    import numpy
    import timeit
    
    value=3
    sizes=numpy.logspace(2, 5, num=50, dtype=int)
    
    sort_results, partition_results=[],[]
    for size in sizes:
        df=pandas.DataFrame({"num":100*numpy.random.random(size)})
        
        sort_results.append(timeit.Timer("df.iloc[(df['num']-value).abs().argsort()[:2]].index",
                                             globals={'find_neighbours':find_neighbours, 'df':df,'value':value}).autorange())
        partition_results.append(timeit.Timer('find_neighbours(df,value)',
                                              globals={'find_neighbours':find_neighbours, 'df':df,'value':value}).autorange())
        
    sort_time=[time/amount for amount,time in sort_results]
    partition_time=[time/amount for amount,time in partition_results]
    
    plt.plot(sizes, sort_time)
    plt.plot(sizes, partition_time)
    plt.legend(['Sorting','Partitioning'])
    plt.title('Comparison of strategies')
    plt.xlabel('Size of Dataframe')
    plt.ylabel('Time in s')
    plt.savefig('speed_comparison.png')
    

    如果序列已经排序,则使用函数是查找索引的有效方法。 例如:

    idx = bisect_left(df['num'].values, 3)
    
    让我们考虑数据帧
    df
    的列
    col
    已排序

    • 在值
      val
      位于列中的情况下,
      bisect\u left
      将返回列表中值的精确索引,并
      bisect_right
      将返回下一个位置的索引
    • 如果该值不在列表中,则两个
      bisect\u left
      bisect\u right
      将返回相同的索引:指向 插入值以保持列表排序
    因此,为了回答这个问题,下面的代码给出了
    col
    val
    的索引(如果找到了),以及最接近的值的索引(否则)。即使列表中的值不是唯一的,此解决方案也能起作用

    从对分导入左对分,右对分
    
    def get_closests(df、col、val):
    下切分=左切分(df[col]。值,val)
    较高的idx=右二等分(df[col]。值,val)
    如果较高的_idx==较低的_idx:#val不在列表中
    返回下_idx-1,下_idx
    其他:#瓦尔在列表中
    返回下箭头idx
    

    对分算法对于在数据帧列“col”中查找特定值“val”的索引非常有效,或其最近的邻居,但它需要对列表进行排序。

    您可以使用
    numpy.searchsorted
    。如果您的搜索列尚未排序,您可以创建一个已排序的数据框,并使用
    pandas.argsort
    记住它们之间的映射。(如果计划多次查找最接近的值,则此方法优于上述方法。)

    排序后,为输入查找最接近的值,如下所示:

    indLeft=np.searchsorted(df['column'],input,side='left')
    indRight=np.searchsorted(df['column'],input,side='right')
    valLeft=df['column'][indLeft]
    valRight=df['column'][indRight]
    
    这里有很多答案,其中很多都很好。没有一个答案被接受,@Zero的答案目前被评为最高级别。另一个答案指出,当索引尚未排序时,它不起作用,但他/她推荐了一个似乎不推荐的解决方案

    我发现我可以通过以下方式对值本身使用numpy版本的
    argsort()
    ,即使索引未排序也可以:

    df.iloc[(df['num']-input).abs()..values.argsort()[:2]]
    

    请参阅Zero的答案了解上下文。

    我发现解决这类问题最直观的方法是使用@ivo merchiers建议的分区方法,但使用nsmallest和nlargest。除了处理未排序的序列外,这种方法的一个好处是,通过将k_匹配设置为数字g,可以轻松获得几个接近的值大于1

    import pandas as pd
    source = pd.Series([1,6,4,5,2])
    target = 3
    
    def find_closest_values(target, source, k_matches=1):
        k_above = source[source >= target].nsmallest(k_matches)
        k_below = source[source < target].nlargest(k_matches)
        k_all = pd.concat([k_below, k_above]).sort_values()
        return k_all
    
    find_closest_values(target, source, k_matches=1)
    

    这是在最下面和最上面找到的,还是仅仅
    4    2
    2    4
    dtype: int64