Удалите элементы из массива Numpy, пока у y не будет равнозначных элементов в каждом значении - PullRequest
2 голосов
/ 24 января 2020

У меня есть массив y, состоящий из 0 и 1, но с другой частотой.

Например:

y = np.array([0, 0, 1, 1, 1, 1, 0])

И у меня есть массив x одинаковой длины.

x = np.array([0, 1, 2, 3, 4, 5, 6])

Идея состоит в том, чтобы отфильтровать элементы, пока не будет одинаковое количество 0 и 1.

. удалить индекс 5:

x = np.array([0, 1, 2, 3, 4, 6])
y = np.array([0, 0, 1, 1, 1, 0])

Наивный метод, о котором я могу подумать, - это получить разницу между частотой значений y (в данном случае 4-3=1), создать маску для y == 1 и переключить случайные элементы. от True до False до разницы 0. Затем создайте маску для y == 0, сделайте между ними OR и примените ее как к x, так и к y.

Это не кажется лучшим способом "python / numpy" "делать это хотя.

Есть предложения? Что-то вроде случайного выбора n элементов из наибольшего числа, где n - это число самого низкого значения.

Если это проще с pandas, то это будет работать и для меня.

Наивный алгоритм, предполагающий 1> 0:

mask_pos = y == 1
mask_neg = y == 0

pos = len(y[mask_pos])
neg = len(y[mask_neg])

diff = pos-neg

while diff > 0:
    rand = np.random.randint(0, len(y))

    if mask_pos[rand] == True:
        mask_pos[rand] = False
        diff -= 1

mask_final = mask_pos | mask_neg

y_new = y[mask_final]
x_new = x[mask_final]

Этот наивный алгоритм действительно медленный

1 Ответ

0 голосов
/ 24 января 2020

Один из способов сделать это с NumPy заключается в следующем:

import numpy as np

# Makes a mask to balance ones and zeros
def balance_binary_mask(binary_array):
    binary_array = np.asarray(binary_array).ravel()
    # Count number of ones
    z = np.count_nonzero(binary_array)
    # If there are less ones than zeros
    if z <= len(binary_array) // 2:
        # Invert the array
        binary_array = ~binary_array
    # Find ones
    idx = np.nonzero(binary_array)[0]
    # Number of elements to remove
    rem = 2 * len(idx) - len(binary_array)
    # Pick random indices to remove
    rem_idx = np.random.choice(idx, size=rem, replace=False)
    # Make mask
    mask = np.ones_like(binary_array, dtype=bool)
    # Mask elements to remove
    mask[rem_idx] = False
    return mask

# Test
np.random.seed(0)
y = np.array([0, 0, 1, 1, 1, 1, 0])
x = np.array([0, 1, 2, 3, 4, 5, 6])
m = balance_binary_mask(y)
print(m)
# [ True  True  True  True False  True  True]
y = y[m]
x = x[m]
print(y)
# [0 0 1 1 1 0]
print(x)
# [0 1 2 3 5 6]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...