2016-01-03 4 views
2

При выполнении:автоматически обрезает Numpy массивы

import numpy as np 
a = np.array([1,2,3]) 
b = np.array([4,5,6,7]) 
print a+b 

конечно, есть ошибка:

ValueError: operands could not be broadcast together with shapes (3,) (4,)

Можно ли сделать что Numpy массивы автоматически обрезает до самого маленького размера, когда два массива разных размеров добавляются или умножаются?

Пример: здесь a имеет длину 3 и b имеет длину 4, поэтому мы автоматически обрезает b до длины 3, прежде чем делать добавления. Желаемый результат для a+b:

[5 7 9] 

Можно ли это сделать с помощью подклассов np.array?

Примечание: Я хотел бы избежать придется вручную срезанным все массивы себя с a[:3] + b[:3]. Я хочу писать только a+b.

+0

Являются ли массивы всегда 1D? –

+0

@ajcr yes always 1D – Basj

ответ

3

Итак, для начала: то, что вы хотите сделать, это плохая форма. Переопределение простых операций часто вызывает всевозможные головные боли. Подклассификация np.array для чего-то вроде этого кажется ужасной идеей.

С учетом этого можно сделать. Вот наивный способ сделать это:

import numpy as np 

class truncarray(np.ndarray): 
    def __new__(cls, array): 
     obj = np.asarray(array).view(cls) 
     return obj 
    def __add__(a, b): 
     s = slice(0, min(len(a),len(b))) 
     return np.add(a[s],b[s]) 
    __radd__ = __add__ 

a = truncarray([1,2,3]) 
b = truncarray([4,5,6,7]) 
a_array = np.array([1,2,3]) 
b_array = np.array([4,5,6,7]) 

Теперь давайте посмотрим, насколько это испортило все:

Добавление обрезает, как вы бы предпочли:

In [17]: a+b 
Out[17]: truncarray([5, 7, 9]) 

Добавление номера не больше не работает:

In [18]: a_array+1 
Out[18]: array([2, 3, 4]) 

In [19]: a+1 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-19-fdcaab9110f2> in <module>() 
----> 1 a+1 

<ipython-input-2-3651dc87cb0e> in __add__(a, b) 
     4     return obj 
     5   def __add__(a, b): 
----> 6     s = slice(0, min(len(a),len(b))) 
     7     return np.add(a[s],b[s]) 
     8   __radd__ = __add__ 

TypeError: object of type 'int' has no len() 

При рассмотрении смеси truncarrays и массивов, добавление больше не транзитивно:

In [20]: a+b_array+a_array 
Out[20]: truncarray([ 6, 9, 12]) 

In [21]: b_array+a+a_array 
Out[21]: truncarray([ 6, 9, 12]) 

In [22]: b_array+a_array+a 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-22-bcd145daa775> in <module>() 
----> 1 b_array+a_array+a 

ValueError: operands could not be broadcast together with shapes (4,) (3,) 

На самом деле, это даже не ассоциативный (!):

In [23]: a+(b_array+a_array) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-23-413ce83f55c2> in <module>() 
----> 1 a+(b_array+a_array) 

ValueError: operands could not be broadcast together with shapes (4,) (3,) 

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

2

Вы можете нарезать как массивы меньшего одного, а затем добавить их:

min_size = min(a.size, b.size) 
c = a[:min_size] + b[:min_size] 
print(c) 
array([5, 7, 9]) 

EDIT

Если вы не хотите делать это вручную, вы могли бы написать функцию:

def add_func(*args): 
    to_trunc = min(map(len, args)) 
    return np.sum([arg[:to_trunc] for arg in args], axis=0) 

print(add_func(a,b)) 
[5 7 9] 
+1

Конечно, это работает, но (я должен был упомянуть об этом). Я хочу сделать это * без * необходимости ** вручную ** усекать все массивы. (в моем коде у меня много массивов, и я хотел бы избежать необходимости обрезать вручную, как вы предлагаете) – Basj

+0

@Basj попробовал отредактированную версию. –

+1

Извините, но я хочу, чтобы * переопределить * оператор '+', который автоматически обрезается и позволяет использовать 'a + b'. (Таким образом, может потребоваться подкласс «np.array») – Basj