Как вы создаете код переменной в Python? - PullRequest
1 голос
/ 23 января 2020

Представьте, что у вас есть структурированный массив, например, такой:

import numpy as np


a = np.array(
    [tuple([np.random.randint(100) for _ in range(3)]) for _ in range(100)], 
    dtype=[('var1', 'i4'), ('var2', 'i4'), ('var3', 'i4')]
)

Теперь я хочу получить доступ только к определенному c подмножеству / срезу этого массива. Например, вот так:

interval = (10, 30)
b = a[
    (a['var1'] >= interval[0]) & (a['var1'] <= interval[1])
]

Пока все хорошо. Но что, если у меня есть переменное число интервалов, соответствующих различным переменным? Например, как это:

intervals = [('var1', 10, 30), ('var2', 20, 50)]

Я не могу жестко закодировать его, потому что количество интервалов изменяется во время работы программы. но то, что я хотел бы, это что-то вроде этого для произвольного числа интервалов:

b = a[
    ((a[intervals[0][0]] >= intervals[0][1]) & (a[intervals[0][0]] <= intervals[0][2])) |
    ((a[intervals[1][0]] >= intervals[1][1]) & (a[intervals[1][0]] <= intervals[1][2]))
]

Единственная идея, которая у меня была до сих пор, это использование for loop до go через интервалы и создание Строка, которая может быть освобождена с помощью eval, но мне это не очень нравится. Есть ли лучшее решение?

string = 'a[((a[intervals[0][0]] >= intervals[0][1]) & (a[intervals[0][0]] ' \
         '<= intervals[0][2]))'
for i in range(len(intervals[1:])):
    string += f' | \n((a[intervals[{i+1}][0]] >= intervals[{i+1}][1]) & ' \
              f'(a[intervals[{i+1}][0]] <= intervals[{i+1}][2]))'
string += ']'

b = eval(string)

Ответы [ 2 ]

2 голосов
/ 23 января 2020

Вам не нужно генерировать код для этой проблемы. Используйте functools.reduce, чтобы применить оператор | к неизвестной серии масок.

import operator
from functools import reduce

mask = reduce(
    operator.__or__,  # the `|` operator
    (
        ((a[var] >= lower) & (a[var] <= upper))
        for var, lower, upper in intervals  # arbitrary number of intervals
    )
)

b = a[mask]
1 голос
/ 23 января 2020

Я бы поместил условия в список кортежей и связал их, используя функцию и map, то есть:

def fmask(tup):
  ix, low, up = tup
  return (a[ix] > low) & (a[ix] < up)

conds = [('var1', 10, 80), ('var2', 30, 40)]

a[np.logical_and(*map(fmask))]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...