2016-12-22 3 views
2

У меня есть сортируются серия, как это:Пандас/NumPy: сжато маркировать первые N значения соответствия маски

[2, 4, 5, 6, 8, 9] 

Я хочу, чтобы произвести другую серию или ndarray тех же длины, где первые две нечетных чисел и первые два четных числа обозначены последовательно:

[0, 1, 2, _, _, 3] 

The _ значения я не очень заботятся о. Они могут быть равны нулю.

Теперь я делаю это так:

src = pd.Series([2, 4, 5, 6, 8, 9]) 
odd = src % 2 != 0 
where = np.hstack((np.where(odd)[0][:2], np.where(~odd)[0][:2])) 
where.sort() # maintain ordering - thanks to @hpaulj 
res = np.zeros(len(src), int) 
res[where] = np.arange(len(where)) 

Вы можете сделать это более сжато? Вход никогда не будет пустым, но не может быть никаких шансов или нет эвенов (в этом случае результат может иметь длину 1, 2 или 3 вместо 4).

+0

ли заказ дело? В вашем примере 2 evens происходят до любых шансов, но '[1,4,5,7,8,9]' производит '[2, 0, 3, 0, 1, 0]'. 'res [np.sort (where)] = ...' - простое исправление. Или создание промежуточной булевой маски. – hpaulj

+0

@hpaulj: Хороший вопрос. Я действительно предпочитаю его сортировать. Я добавлю 'where.sort()' в мое примерное решение (сделав его еще менее кратким!). –

ответ

1

Большая проблема! Я все еще изучаю и изучаю.

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

выводы
До сих пор, я метался много, и не улучшилось.

мой ответ
быстро

odd = src.values % 2 
even = 1 - odd 
res = ((odd.cumsum() * odd) < 3) * ((even.cumsum() * even) < 3) 
(res.cumsum() - 1) * res 

альтернатива 1
довольно быстро

a = src.values 
odd = (a % 2).astype(bool) 
rng = np.arange(len(a)) 

# same reason these are 2, we have 4 below 
where = np.append(rng[~odd][:2], rng[odd][:2]) 
res = np.zeros(len(a), int) 

# nature of the problem necessitates that this is 4 
res[where] = np.arange(4) 

альтернатива 2
не так быстро, но творческий

a = src.values 
odd = a % 2 
res = np.zeros(len(src), int) 
b = np.arange(2) 
c = b[:, None] == odd 
res[(c.cumsum(1) * c <= 2).all(0)] = np.arange(4) 

альтернатива 3
еще медленно

odd = src.values % 2 
a = (odd[:, None] == [0, 1]) 
b = ((a.cumsum(0) * a) <= 2).all(1) 
(b.cumsum() - 1) * b 

времени код

def pir3(src): 
    odd = src.values % 2 
    a = (odd[:, None] == [0, 1]) 
    b = ((a.cumsum(0) * a) <= 2).all(1) 
    return (b.cumsum() - 1) * b 

def pir0(src): 
    odd = src.values % 2 
    even = 1 - odd 
    res = ((odd.cumsum() * odd) < 3) * ((even.cumsum() * even) < 3) 
    return (res.cumsum() - 1) * res 

def pir2(src): 
    a = src.values 
    odd = a % 2 
    res = np.zeros(len(src), int) 
    c = b[:, None] == odd 
    res[(c.cumsum(1) * c <= 2).all(0)] = np.arange(4) 
    return res 

def pir1(src): 
    a = src.values 
    odd = (a % 2).astype(bool) 
    rng = np.arange(len(a)) 
    where = np.append(rng[~odd][:2], rng[odd][:2]) 
    res = np.zeros(len(a), int) 
    res[where] = np.arange(4) 
    return res 

def john0(src): 
    odd = src % 2 == 0 
    where = np.hstack((np.where(odd)[0][:2], np.where(~odd)[0][:2])) 
    res = np.zeros(len(src), int) 
    res[where] = np.arange(len(where)) 
    return res 

def john1(src): 
    odd = src.values % 2 == 0 
    where = np.hstack((np.where(odd)[0][:2], np.where(~odd)[0][:2])) 
    res = np.zeros(len(src), int) 
    res[where] = np.arange(len(where)) 
    return res 

src = pd.Series([2, 4, 5, 6, 8, 9])
enter image description here

src = pd.Series([2, 4, 5, 6, 8, 9] * 10000)
enter image description here

Смежные вопросы