Панды - для цикла и найти индекс, который имеет ближайшее значение - PullRequest
0 голосов
/ 13 ноября 2018

Я в основном пытаюсь пройтись по циклу данных, который был сгруппирован, и найти индекс, который имеет ближайшее значение к входному аргументу.

Например, учитывая приведенный ниже кадр данных, для каждой группы, определенной с помощью global_id, я хочу сгруппировать, чтобы взять кадры, которые разнесены как минимум на 10 кадров друг от друга.Например, если у меня есть список кадров [1,2,3,4,14,20,30,31], результат будет [1,14,30], потому что

  • я быинициализировать, взяв кадр 1 в качестве первого кадра
  • Следующий кадр, который находится на расстоянии не менее 10 кадров, будет иметь номер кадра 14
  • Следующий кадр, который находится на расстоянии не менее 10 кадров от 14, равен 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, и это выглядит чрезвычайно громоздко, поэтому я надеюсь, что есть более элегантное решение.Я прочитал документы по групповым и некоторым другим сообщениям 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

1 Ответ

0 голосов
/ 13 ноября 2018

Вот один из способов использования 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 вы можете видеть, что разница >10 начинается с row 4, затем идет к column 4, разница >10 начинается с row 6 и продолжается до column 6 вас. не получить разницу достаточно большой. Таким образом, фильтрация будет хранить строки 0, 4 и 6, что соответствует значениям [1,14,30]. Чтобы получить эти числа, вы можете сравнить np.substract.outer с 10 и sum с axis=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

Если вы хотите сохранить индекс исходных строк, вместо него вы можете добавить level=0 в reset_index, например reset_index(level=0,drop=True).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...