пост, не стесняйтесь редактировать :)

тот интересный API называетсяIntervalindex новый в 0.20, который позволяет вам создавать индекс интервалов.

Даны некоторые примеры данных:

data = [(893.1516130000001, 903.9187099999999),
 (882.384516, 893.1516130000001),
 (817.781935, 828.549032)]

Вы можете создать индекс следующим образом:

idx = pd.IntervalIndex.from_tuples(data)

print(idx)
IntervalIndex([(893.151613, 903.91871], (882.384516, 893.151613], (817.781935, 828.549032]]
              closed='right',
              dtype='interval[float64]')

Интересное свойствоIntervalЭто то, что вы можете выполнять интервальные проверки сin:

print(y[-1])
Interval(817.78193499999998, 828.54903200000001, closed='right')

print(820 in y[-1])
True

print(1000 in y[-1])
False

Я хотел бы знать, как применить эту операцию ко всему индексу. Например, учитывая некоторое число900Как я могу получить булеву маску интервалов, для которых подходит это число?

Я могу думать о:

m = [900 in y for y in idx]
print(m)
[True, False, False]

Есть ли лучшие способы сделать это?

 Zero22 сент. 2017 г., 14:35
Я не в курсе, что-то не так с тобой?
 coldspeed22 сент. 2017 г., 14:37
@ Zero Кажется, что это полезная функция, поэтому я подумал, что что-то в этом роде. Единственное, что не так с пониманием списка - это цикл; - /
 coldspeed22 сент. 2017 г., 15:40
@Bharathshetty Я нуб. Я не знаю, что хорошо, а что плохо!
 Dark30 окт. 2017 г., 14:29
@ cᴏʟᴅsᴘᴇᴇᴅ, почему get_loc не работает с datetime
 coldspeed30 окт. 2017 г., 21:44
@Bharath Это должно ... Я не достаточно опытен с этим API, чтобы сказать вам, почему :(

Ответы на вопрос(3)

вы можете использовать левую и правую часть idx, т.е. получить нижнюю границу и верхнюю границу из диапазона, а затем проверить, находится ли число между границами, т.е.

list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))

Или же

[(900 > idx.left) & (900 <= idx.right)]
[True, False, False]

Для небольших данных

%%timeit
list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))
100000 loops, best of 3: 11.26 µs per loop

%%timeit
[900 in y for y in idx]
100000 loops, best of 3: 9.26 µs per loop

Для больших данных

idx = pd.IntervalIndex.from_tuples(data*10000)

%%timeit
list(lower <= 900 <= upper for (lower, upper) in zip(idx.left,idx.right))
10 loops, best of 3: 29.2 ms per loop

%%timeit
[900 in y for y in idx]
10 loops, best of 3: 64.6 ms per loop

Этот метод превосходит ваше решение для больших данных.

 coldspeed22 сент. 2017 г., 16:05
Как это работает?idx.left а такжеidx.right?
 Dark22 сент. 2017 г., 16:10
Я думаю, что они еще не задокументированы, но вы можете увидеть кодgithub.com/pandas-dev/pandas/blob/v0.20.3/pandas/core/indexes/...
 coldspeed23 сент. 2017 г., 15:35
Джефф является одним из основных разработчиков панд. Его слово - закон ... буквально ... но спасибо за понимание :-)

Вы можете использоватьmap:

idx.map(lambda x: 900 in x)
#Index([True, False, False], dtype='object')

Тайминги:

%timeit [900 in y for y in idx]
#100000 loops, best of 3: 3.76 µs per loop

%timeit idx.map(lambda x: 900 in x)
#10000 loops, best of 3: 48.7 µs per loop

%timeit map(lambda x: 900 in x, idx)
#100000 loops, best of 3: 4.95 µs per loop

Очевидно, что понимание является самым быстрым, но встроеннымmap не слишком отстает

Результаты выровняются, когда мы вводим больше данных, а точнее в 10 тысяч раз больше данных:

%timeit [900 in y for y in idx]
#10 loops, best of 3: 26.8 ms per loop

%timeit idx.map(lambda x: 900 in x)
#10 loops, best of 3: 30 ms per loop

%timeit map(lambda x: 900 in x, idx)
#10 loops, best of 3: 29.5 ms per loop

Как видим, встроенныйmap подходит очень близко к.map() Итак - давайте посмотрим, что происходит с 10 раз даже больше данных:

%timeit [900 in y for y in idx]
#1 loop, best of 3: 270 ms per loop

%timeit idx.map(lambda x: 900 in x)
#1 loop, best of 3: 299 ms per loop

%timeit map(lambda x: 900 in x, idx)
#1 loop, best of 3: 291 ms per loop

Заключение:

Понимание является победителем, но не настолько отчетливым при больших объемах данных.

 zipa22 сент. 2017 г., 14:54
понимание быстрее :)
 zipa22 сент. 2017 г., 15:11
Мой первыйtimeit пост, не стесняйтесь редактировать :)
 coldspeed22 сент. 2017 г., 14:56
Очень обидно. Мне понравился твой ответ. Тем не менее, я хотел бы увидеть время.
 coldspeed22 сент. 2017 г., 14:50
Спасибо за ответ, но можете ли вы доказать мне, что карта лучше, чем понимание списка? Я хотел бы увидеть время на этом, если вы не возражаете! С некоторыми большими данными тоже.
Решение Вопроса

IntervalIndex оптимизирован для поиска. с помощью.get_loc или же.get_indexer использует внутреннее IntervalTree (например, двоичное дерево), которое создается при первом использовании.

In [29]: idx = pd.IntervalIndex.from_tuples(data*10000)

In [30]: %timeit -n 1 -r 1 idx.map(lambda x: 900 in x)
92.8 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

In [40]: %timeit -n 1 -r 1 idx.map(lambda x: 900 in x)
42.7 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# construct tree and search
In [31]: %timeit -n 1 -r 1 idx.get_loc(900)
4.55 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# subsequently
In [32]: %timeit -n 1 -r 1 idx.get_loc(900)
137 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# for a single indexer you can do even better (note that this is
# dipping into the impl a bit
In [27]: %timeit np.arange(len(idx))[(900 > idx.left) & (900 <= idx.right)]
203 µs ± 1.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Обратите внимание, что .get_loc () возвращает индексатор (который на самом деле более полезен, чем логический массив, но они могут быть преобразованы друг в друга).

In [38]: idx.map(lambda x: 900 in x)
    ...: 
Out[38]: 
Index([ True, False, False,  True, False, False,  True, False, False,  True,
       ...
       False,  True, False, False,  True, False, False,  True, False, False], dtype='object', length=30000)

In [39]: idx.get_loc(900)
    ...: 
Out[39]: array([29997,  9987, 10008, ..., 19992, 19989,     0])

Возвращаемый логический массив преобразуется в массив индексаторов

In [5]: np.arange(len(idx))[idx.map(lambda x: 900 in x).values.astype(bool)]
Out[5]: array([    0,     3,     6, ..., 29991, 29994, 29997])

Вот что возвращают .get_loc () и .get_indexer ():

In [6]: np.sort(idx.get_loc(900))
Out[6]: array([    0,     3,     6, ..., 29991, 29994, 29997])
 coldspeed23 сент. 2017 г., 01:44
Спасибо! Это просто потрясающе. Итак, как я понял, get_loc создает дерево, которое внутренне кэшируется для более быстрого поиска позже?
 coldspeed23 сент. 2017 г., 01:46
Также вы упомянули, что они конвертируемы друг в друга. Как именно второй выход отображается на первый?
 Jeff23 сент. 2017 г., 01:53
да, IntervalTree создается внутри, это способ индексации; мы обычно создаем хеш-таблицу для других типов индексов для поиска, однако эта структура дает здесь много преимуществ. Обновлено с тем, как конвертировать между индексаторами.

Ваш ответ на вопрос