Можно ли использовать 2D-список в качестве индекса границы? - PullRequest
0 голосов
/ 24 июня 2019

Мой предыдущий код предоставляет мне для каждой записи границ списка ссылок интересующего региона с индексами другого списка. Так, например, у меня есть listA, который должен быть назначен значениям в другом listB. Для каждой записи должна быть возможность получить индексы, так что это действительно:

listA[:]-d/2 <= listB[indices to find] <= listA[:]+d/2

Я решил проблему с пониманием списка и использовал встроенный метод python range () с индексами границ в качестве аргумента, чтобы получить все необходимые значения. Поэтому я перебираю свой список границ и создаю список со всеми индексами. Так, например: borders[0,:] = [1,4] становится indices[0] = [1,2,3].

arr = [values[range(borders[i,0], borders[i,1])] for i in range(borders.shape[0])]

Это работает, но это слишком медленно для больших наборов данных. Я нашел список понимания, чтобы быть проблемой. Есть ли метод numpy / pandas / ..., который я могу использовать, чтобы он представлял собой матричную операцию?

Набор данных похож на следующее:

    no_points = 10000
    no_groups = 3
    meas_duration = 60
    df_AT = pd.DataFrame(np.transpose([np.sort(np.random.rand(no_points)*meas_duration) for _ in range(no_groups)]), columns = ['AT {}'.format(i+1) for i in range(no_groups)])
    df_TT = pd.DataFrame(np.transpose([np.random.rand(no_points) for _ in range(no_groups)]), columns = ['TT {}'.format(i+1) for i in range(no_groups)])
    df = pd.concat([df_AT, df_TT], axis=1)
    filterCoincidence(df, window=1e-3)

\\ edit К сожалению, я все еще работаю над этим. Я просто скопирую часть своего кода:

        # process coincidence
        borders = [list() for _ in range(len(AT_cols)-1)]
        test = np.empty((AT_df.shape[0],3), dtype=object)
        test[:,0] = np.arange(AT_df.shape[0])
        for i, [AT, TT] in enumerate(zip(AT_cols[np.where(AT_cols != AT_cols[used_ref])], TT_cols[np.where(AT_cols != AT_cols[used_ref])])):
            AT_ix = np.argwhere(AT_cols == AT).flatten()[0]
            neighbors_lower = np.searchsorted(AT_df[AT].values, AT_df[AT_cols[used_ref]]-window, side='left')
            neighbors_upper = np.searchsorted(AT_df[AT].values, AT_df[AT_cols[used_ref]]+window, side='left')

            borders[i] = np.transpose([neighbors_lower, neighbors_upper])
            coinc_ix = np.where(np.diff(borders[i], axis=1).flatten() != 0)[0]

            test[coinc_ix,i+1]=np.asarray([np.arange(borders[i][j][0], borders[i][j][1], dtype=int) for j in coinc_ix])

        test = test[~np.any(pd.isnull(test), axis=1)]

Так что теперь эта часть достаточно быстра для моей цели. С подсказкой от Дрекера и Накора это все же немного быстрее. Проблема в том, что у меня есть кандидаты на мои образцы, но мне все еще нужно выполнить следующую задачу:

  • Заказ образцов по первому критерию: какой из них наиболее похож? Поэтому я должен сравнить время прохождения и время прибытия (две колонки AT и TT). Я мог бы сделать это с sorted(key=my_fun), но это действительно отнимает много времени
  • Проверьте, все ли образцы находятся во временном окне. Это выполняется по сравнению с эталонными данными, но находятся ли измерения в двух не эталонных группах также во временном окне? Я мог бы упростить задачу, используя только + - window / 2 в коде, но это действительно сильное предположение, потому что эталонные измерения всегда должны быть в середине временного окна. Поэтому я использовал scipy.spatial.distance.cdist() и проверил расстояния

Ответы [ 2 ]

1 голос
/ 24 июня 2019

Используйте прямые ломтики:

arr = [values[border_pair[0]:border_pair[1]] for border_pair in borders]

Если values - массив numpy, это может быть как минимум несколько быстрее.

Тем не менее, это просто простая копия ваших данных, и если это занимает слишком много времени (я думаю), вы не так уж много можете с этим сделать. Но если это действительно узкое место, может быть, вам не нужно копировать все эти данные, но вы можете использовать только для чтения внутри массива values? Трудно сказать, потому что вы не упоминаете, что вы делаете с ними в вопросе.

0 голосов
/ 24 июня 2019

В дополнение к комментарию Дрекера, я провел несколько тестов на своей машине, и это примерно в 10 раз быстрее на матрице 10 000x10 000, если values является массивом:

# Generate random data
import numpy as np

N=10000
values = np.random.randint(0,100,[N,N]).astype(int)
borders = []
for _ in range(N):
    inf = np.random.randint(0,99)
    sup = np.random.randint(inf,100)
    borders.append([inf,sup])
borders = np.array(borders)

In [1]: %time arr = [values[range(borders[i,0], borders[i,1])] for i in range(borders.shape[0])]
CPU times: user 7.97 s, sys: 7.27 s, total: 15.2 s
Wall time: 17.5 s

In [2]: %time arr=[values[borders[i,0]: borders[i,1]] for i in range(borders.shape[0])]
CPU times: user 30.7 ms, sys: 1.4 s, total: 1.43 s
Wall time: 1.43 s


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