2016-10-19 1 views
4
import numpy as np 

data = np.array([ 
    [20, 0, 5, 1], 
    [20, 0, 5, 1], 
    [20, 0, 5, 0], 
    [20, 1, 5, 0], 
    [20, 1, 5, 0], 
    [20, 2, 5, 1], 
    [20, 3, 5, 0], 
    [20, 3, 5, 0], 
    [20, 3, 5, 1], 
    [20, 4, 5, 0], 
    [20, 4, 5, 0], 
    [20, 4, 5, 0] 
]) 

У меня есть следующий 2d массив. позволяет называть поля a, b, c, d в указанном порядке, где столбец b похож на id. Я хочу, чтобы удалить все клетки, которые не суммируются и не имеют atlist 1 появление числа «1» в колонке d для всех ячеек с тем же номером в столбце b (тот же идентификатор), поэтому после фильтрации я буду иметь следующие результаты:python filter 2d массив на кусок данных

[[20 0 5 1] 
[20 0 5 1] 
[20 0 5 0] 
[20 2 5 1] 
[20 3 5 0] 
[20 3 5 0] 
[20 3 5 1]] 

все строки с b = 1 и b = 4 были удалены из данных

подводить итоги, потому что я вижу, что ответы не приспосабливает. мы смотрим на куски данных по столбцу b. если полный фрагмент данных не имеет даже одного вида числа «1» в столбце d, мы удаляем все строки этого элемента b. в следующем примере мы можем увидеть фрагмент данных с b = 1 и b = 4 («id» = 1 и «id» = 4), которые имеют 0 номеров числа «1» в столбце d. вот почему он будет удален из данных

+0

Это список списков или массив numpy? Пробовал что-нибудь еще? –

+0

это работает как массив numpy. он был сгенерирован из этой команды: result = np.loadtxt ("name.csv", delimiter = ","). astype (int). строка в файле выглядит так: 5.0000,20090.0000,0.1854,1.0000 –

+0

Пожалуйста, внесите свой вопрос, чтобы включить код. Комментарии не предназначены для кода –

ответ

3

Общий подход: Вот подход, использующий np.unique и np.bincount решить для общего случая -

unq,tags = np.unique(data[:,1],return_inverse=1) 
goodIDs = np.flatnonzero(np.bincount(tags,data[:,3]==1)>=1) 
out = data[np.in1d(tags,goodIDs)] 

Пример запуска -

In [15]: data 
Out[15]: 
array([[20, 10, 5, 1], 
     [20, 73, 5, 0], 
     [20, 73, 5, 1], 
     [20, 31, 5, 0], 
     [20, 10, 5, 1], 
     [20, 10, 5, 0], 
     [20, 42, 5, 1], 
     [20, 54, 5, 0], 
     [20, 73, 5, 0], 
     [20, 54, 5, 0], 
     [20, 54, 5, 0], 
     [20, 31, 5, 0]]) 

In [16]: out 
Out[16]: 
array([[20, 10, 5, 1], 
     [20, 73, 5, 0], 
     [20, 73, 5, 1], 
     [20, 10, 5, 1], 
     [20, 10, 5, 0], 
     [20, 42, 5, 1], 
     [20, 73, 5, 0]]) 

Особый случай подход: Если данные второго столбца всегда сортируются и имеют порядковые номера, начиная с 0, мы можем использовать упрощенную версию, например, так -

goodIDs = np.flatnonzero(np.bincount(data[:,1],data[:,3]==1)>=1) 
out = data[np.in1d(data[:,1],goodIDs)] 

Sample пробег -

In [44]: data 
Out[44]: 
array([[20, 0, 5, 1], 
     [20, 0, 5, 1], 
     [20, 0, 5, 0], 
     [20, 1, 5, 0], 
     [20, 1, 5, 0], 
     [20, 2, 5, 1], 
     [20, 3, 5, 0], 
     [20, 3, 5, 0], 
     [20, 3, 5, 1], 
     [20, 4, 5, 0], 
     [20, 4, 5, 0], 
     [20, 4, 5, 0]]) 

In [45]: out 
Out[45]: 
array([[20, 0, 5, 1], 
     [20, 0, 5, 1], 
     [20, 0, 5, 0], 
     [20, 2, 5, 1], 
     [20, 3, 5, 0], 
     [20, 3, 5, 0], 
     [20, 3, 5, 1]]) 

Кроме того, если data[:,3] всегда есть единицы и нули, мы можем просто использовать data[:,3] вместо data[:,3]==1 в выше перечисленных кодов.


Бенчмаркинг

Давайте сравним производительность векторизованные подходы на конкретном случае для большего массива -

In [69]: def logical_or_based(data): #@ Eric's soln 
    ...:  b_vals = data[:,1] 
    ...:  d_vals = data[:,3] 
    ...:  is_ok = np.zeros(np.max(b_vals) + 1, dtype=np.bool_) 
    ...:  np.logical_or.at(is_ok, b_vals, d_vals) 
    ...:  return is_ok[b_vals] 
    ...: 
    ...: def in1d_based(data): 
    ...:  goodIDs = np.flatnonzero(np.bincount(data[:,1],data[:,3])!=0) 
    ...:  out = np.in1d(data[:,1],goodIDs) 
    ...:  return out 
    ...: 

In [70]: # Setup input 
    ...: data = np.random.randint(0,100,(10000,4)) 
    ...: data[:,1] = np.sort(np.random.randint(0,100,(10000))) 
    ...: data[:,3] = np.random.randint(0,2,(10000)) 
    ...: 

In [71]: %timeit logical_or_based(data) #@ Eric's soln 
1000 loops, best of 3: 1.44 ms per loop 

In [72]: %timeit in1d_based(data) 
1000 loops, best of 3: 528 µs per loop 
+0

В теории это должно быть немного медленнее, чем мой ответ, не так ли? Так как это «O (max (b) * N)», и я думаю, что мой «O (N)»? Или я не понимаю сложность 'np.in1d'? – Eric

+0

@ Eric Well 'np.in1d' не выполняет точно такую ​​же задачу, как' np.logical_or.at', поэтому я не могу комментировать производительность. Конечно, после индексирования с 'is_ok [b_vals]' он попадает в один и тот же логический массив, поэтому, похоже, с 'np.logical_or.at', нам также нужно индексировать. Добавил некоторый тест времени выполнения вовремя самим подходам, если вы это искали. – Divakar

1

код:

import numpy as np 

my_list = [[20,0,5,1], 
    [20,0,5,1], 
    [20,0,5,0], 
    [20,1,5,0], 
    [20,1,5,0], 
    [20,2,5,1], 
    [20,3,5,0], 
    [20,3,5,0], 
    [20,3,5,1], 
    [20,4,5,0], 
    [20,4,5,0], 
    [20,4,5,0]] 

all_ids = np.array(my_list)[:,1] 
unique_ids = np.unique(all_ids) 
indices = [np.where(all_ids==ui)[0][0] for ui in unique_ids ] 

final = [] 
for id in unique_ids: 
    try: 
     tmp_group = my_list[indices[id]:indices[id+1]] 
    except: 
     tmp_group = my_list[indices[id]:] 
    if 1 in np.array(tmp_group)[:,3]: 
     final.extend(tmp_group) 

print np.array(final) 

результат:

[[20 0 5 1] 
[20 0 5 1] 
[20 0 5 0] 
[20 2 5 1] 
[20 3 5 0] 
[20 3 5 0] 
[20 3 5 1]] 
+0

Я не хочу явно удалять строки, где my_list [1] == 1. Я хочу удалить эти строки, только если все строки, где my_list [1] = i также являются 0 в my_list [3] –

+0

@EranMoshe Я вижу, дайте мне секунду, я исправляю его – Yugi

+0

Я построил другой пример, и я могу проверить его сейчас –

1

Это избавляется от всех строк с 1 во втором положении:

[sublist for sublist in list_ if sublist[1] != 1] 

Этот get избавляется от всех строк с 1 во второй позиции, если четвертая позиция также не равна 1:

[sublist for sublist in list_ if not (sublist[1] == 1 and sublist[3] != 1) ] 
+0

Фактическое требование - избавиться от любых строк, для которых значение во втором столбце umn никогда не совпадает с 1 в последнем столбце в любой из строк. – Eric

1

Давайте предположим следующее:

  • b >= 0
  • b представляет собой целое
  • b довольно плотные, т.е. max(b) ~= len(unique(b))

Вот решение, использующее np.ufunc.at:

# unpack for clarity - this costs nothing in numpy 
b_vals = data[:,1] 
d_vals = data[:,3] 

# build an array indexed by b values 
is_ok = np.zeros(np.max(b_vals) + 1, dtype=np.bool_) 
np.logical_or.at(is_ok, b_vals, d_vals) 
# is_ok == array([ True, False, True, True, False], dtype=bool) 

# take the rows which have a b value that was deemed OK 
result = data[is_ok[b_vals]] 

np.logical_or.at(is_ok, b_vals, d_vals) является более эффективной версией:

for idx, val in zip(b_vals, d_vals): 
    is_ok[idx] = np.logical_or(is_ok[idx], val) 
1

Не проиндексирован, так как в спешке, но это должно работать:

import numpy_indexed as npi 
g = npi.group_by(data[:, 1]) 
ids, valid = g.any(data[:, 3]) 
result = data[valid[g.inverse]] 
Смежные вопросы