【问题标题】:Pandas - for loop and find index that has the nearest valuePandas - for 循环并查找具有最接近值的索引
【发布时间】:2018-11-14 00:27:59
【问题描述】:

我基本上是在尝试遍历已分组的数据框并找到与输入参数具有最接近值的索引。

例如,给定下面的数据帧,对于由global_id 定义的每个组,我想分组以获取间隔至少 10 帧的帧。例如,如果我有一个帧列表 [1,2,3,4,14,20,30,31],输出将是 [1,14,30] 因为

  • 我将通过将第 1 帧作为第一帧进行初始化
  • 至少相隔 10 帧的下一帧将是第 14 帧
  • 距第 14 帧至少 10 帧的后续帧为 30

因此,数据帧前后的结果应如下所示

之前

       seq_name     label pedestrian_id  frame_no  global_id
0          0001  crossing          0001  0001         1
1          0001  crossing          0001  0002         1
2          0001  crossing          0001  0003         1
3          0001  crossing          0001  0004         1
4          0001  crossing          0001  0005         1
5          0001  crossing          0001  0006         1
6          0001  crossing          0001  0007         1
7          0001  crossing          0001  0008         1
8          0001  crossing          0001  0009         1
9          0001  crossing          0001  0010         1
10         0001  crossing          0002  0001         2
11         0001  crossing          0002  0012         2
12         0001  crossing          0002  0013         2
13         0001  crossing          0002  0014         2
14         0001  crossing          0002  0015         2
15         0001  crossing          0002  0029         2
16         0001  crossing          0002  0030         2
17         0001  crossing          0002  0031         2
18         0001  crossing          0002  0032         2
19         0001  crossing          0002  0033         2
20         0002  crossing          0001  0034         3
21         0002  crossing          0001  0035         3
22         0002  crossing          0001  0036         3
23         0002  crossing          0001  0037         3
24         0002  crossing          0001  0038         3
25         0002  crossing          0001  0039         3
26         0002  crossing          0001  0049         3
27         0002  crossing          0001  0050         3
28         0002  crossing          0001  0051         3
29         0002  crossing          0001  0052         3

过滤后

       seq_name     label pedestrian_id  frame_no  global_id
0          0001  crossing          0001  0001         1
10         0001  crossing          0002  0001         2
11         0001  crossing          0002  0012         2
15         0001  crossing          0002  0029         2
25         0002  crossing          0001  0039         3
26         0002  crossing          0001  0049         3

以下是我所拥有的。一旦我有了索引,我就可以通过从旧的索引来创建一个新的数据框。我还是 Pandas 的新手,它看起来非常麻烦,所以我希望有一个更优雅的解决方案。我已经阅读了关于 groupby 的文档和其他一些 SO 帖子,但仍然无法弄清楚。这不是家庭作业。只是想通过用 Pandas 替换所有内容来清理我的数据处理管道。

ind = []
for j in df["global_id"].unique():
    df_temp = df[df["global_id"] == j][["frame_no"]]
    df_temp["frame_no"] = pd.to_numeric(df["frame_no"]) 
    start_frame = df_temp["frame_no"].min()
    end_frame = df_temp["frame_no"].max()
    i = start_frame-1
    while i < end_frame:
        ind.append(np.min(df_temp[(df_temp["frame_no"] > i) & (df_temp["frame_no"] < i+10)].index.tolist()))
        i+=10

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    这是使用groupby 的一种方法,但首先您需要定义一个函数来执行您在每个组中查找的内容。为了解释这个想法,让我们考虑一个简单的数据框dfs = pd.DataFrame({'a':[1,2,3,4,14,20,30,31]})

    我一直在寻找解决这类问题一段时间,试图避免循环,这似乎很复杂。这是我最终的想法。在 numpy 中,您可以使用 substract 结合 outer 来一对一地获取每个元素之间的所有差异

    print (np.subtract.outer(dfs.a, dfs.a))
    array([[  0,  -1,  -2,  -3, -13, -19, -29, -30],
           [  1,   0,  -1,  -2, -12, -18, -28, -29],
           [  2,   1,   0,  -1, -11, -17, -27, -28],
           [  3,   2,   1,   0, -10, -16, -26, -27],
           [ 13,  12,  11,  10,   0,  -6, -16, -17],
           [ 19,  18,  17,  16,   6,   0, -10, -11],
           [ 29,  28,  27,  26,  16,  10,   0,  -1],
           [ 30,  29,  28,  27,  17,  11,   1,   0]], dtype=int64)
    

    现在,例如,在 column 0 中,您可以看到差异 &gt;10row 4 开始,然后转到 column 4,差异 &gt;10row 6 开始并转到 column 6 你不要得到足够大的差异。因此过滤将保留第 0、4 和 6 行,即要查找的值 [1,14,30]。要获得这些数字,您可以将 np.substract.outer 与 10 和 sumaxis=0 进行比较,例如:

    arr = (np.subtract.outer(dfs.a, dfs.a) <=10).sum(0)
    print (arr)
    array([4, 4, 4, 5, 6, 7, 8, 8])
    

    现在你看到了,arr[0] = 4,然后是arr[4] = 6,然后arr[6]=8 在这个例子中超出了范围,所以停止。捕获这些数字的一种方法是使用while(如果有人有numpy 解决方案可以做到这一点,我很感兴趣)

    list_ind = [0] # initialize list of index to keep with 0
    arr = (np.subtract.outer(dfs.a, dfs.a) <=10).sum(0)
    i = arr[0]
    while i < len(arr):
        list_ind.append(i)
        i = arr[i]
    
    print (list_ind)
    [0, 4, 6]
    
    print (dfs.iloc[list_ind])
        a
    0   1
    4  14
    6  30
    

    现在有了整个问题和groupby,你可以这样做:

    # it seems you need to convert the column frame_no to integer
    df['frame_int'] = pd.to_numeric(df['frame_no'])
    df = df.sort_values('frame_int') #ensure data to be sorted by frame_int, whatever the global_id
    
    #define the function looking for the ind
    def find_ind (df_g):
        list_ind = [0]
        arr = (np.subtract.outer(df_g.frame_int, df_g.frame_int) <= 10).sum(0)
        i = arr[0]
        while i <len(arr):
            list_ind.append(i)
            i = arr[i]
        return df_g.iloc[list_ind]
    
    #create the filtered dataframe
    df_filtered = (df.groupby('global_id').apply(find_ind)
                     .drop('frame_int',axis=1).reset_index(drop=True))
    
    print (df_filtered)
       seq_name     label  pedestrian_id  frame_no  global_id
    0         1  crossing              1         1          1
    1         1  crossing              2         1          2
    2         1  crossing              2        12          2
    3         1  crossing              2        29          2
    4         2  crossing              1        34          3
    5         2  crossing              1        49          3
    

    如果要保留原始行的索引,可以在reset_index中添加level=0,例如reset_index(level=0,drop=True)

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 2014-08-18
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 2012-02-13
      • 2013-03-29
      • 2017-03-15
      • 1970-01-01
      相关资源
      最近更新 更多