8

I have two lists, looking like this:

a= [[1,2,3,4], [2,3,4,5],[3,4,5,6,7]], b= [[5,6,7,8], [9,1,2,3], [4,5,6,7,8]]

which I want to subtract from each other element by element for an Output like this:

a-b= [[-4,-4,-4,-4],[7,2,2,2],[-1,-1,-1,-1,-1]]

In order to do so I convert each of a and b to arrays and subtract them I use:

np.array(a)-np.array(b)

The Output just gives me the error:

Unsupported Operand type for-: 'list' and 'list'

What am I doing wrong? Shouldn't the np.array command ensure the conversion to the array?

Mazdak
  • 105,000
  • 18
  • 159
  • 188

7 Answers7

5

Here is a Numpythonic way:

>>> y = map(len, a)  
>>> a = np.hstack(np.array(a))
>>> b = np.hstack(np.array(b))
>>> np.split(a-b, np.cumsum(y))
[array([-4, -4, -4, -4]), array([-7,  2,  2,  2]), array([-1, -1, -1, -1, -1]), array([], dtype=float64)]
>>> 

Since you cannot subtract the arrays with different shapes, you can flatten your arrays using np.hstack() then subtract your flattened arrays then reshape based on the previous shape.

Mazdak
  • 105,000
  • 18
  • 159
  • 188
1

The dimensions of your two arrays don't match, i.e. the first two sublists of a have 4 elements, but the third has 5 and ditto with b. If you convert the lists to numpy arrays, numpy silently gives you something like this:

In [346]: aa = np.array(a)
In [347]: bb = np.array(b)
In [348]: aa
Out[348]: array([[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6, 7]], dtype=object)
In [349]: bb
Out[349]: array([[5, 6, 7, 8], [9, 1, 2, 3], [4, 5, 6, 7, 8]], dtype=object)

You need to make sure that all your sublists have the same number of elements, then your code will work:

In [350]: a = [[1,2,3,4], [2,3,4,5],[3,4,5,6]]; b = [[5,6,7,8], [9,1,2,3], [4,5,6,7]] # I removed the last element of third sublist in a and b
In [351]: np.array(a) - np.array(b)
Out[351]: 
array([[-4, -4, -4, -4],
       [-7,  2,  2,  2],
       [-1, -1, -1, -1]])
tttthomasssss
  • 5,852
  • 3
  • 32
  • 41
  • thanks, this is already helpful. unfortunately this is what my data Looks like.. Is there no Routine that can handle also a list like this? – umpalumpa__ Aug 11 '16 at 11:01
  • You will need to handle that manually, for example by padding the shorter sublists with 0s or something if you want to use `numpy` for your use case. – tttthomasssss Aug 11 '16 at 11:04
1

You can try:

>>> a= [[1,2,3,4], [2,3,4,5],[3,4,5,6,7]]
>>> b= [[5,6,7,8], [9,1,2,3], [4,5,6,7,8]]
>>> 
>>> c =[]
>>> for i in range(len(a)):
    c.append([A - B for A, B in zip(a[i], b[i])])


>>> print c
[[-4, -4, -4, -4], [-7, 2, 2, 2], [-1, -1, -1, -1, -1]]

Or 2nd method is using map:

from operator import sub
a= [[1,2,3,4], [2,3,4,5],[3,4,5,6,7]]
b= [[5,6,7,8], [9,1,2,3], [4,5,6,7,8]]
c =[]
for i in range(len(a)):
    c.append(map(sub, a[i], b[i]))  
print c
[[-4, -4, -4, -4], [-7, 2, 2, 2], [-1, -1, -1, -1, -1]]
Harsha Biyani
  • 7,049
  • 9
  • 37
  • 61
0

Without NumPy:

result = []
for (m, n) in (zip(a, b)):
    result.append([i - j for i, j in zip(m, n)])

See also this question and this one.

Community
  • 1
  • 1
Matthias Wiehl
  • 1,799
  • 16
  • 22
0

What about a custom function such as:

import numpy as np

a = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6, 7]]
b = [[5, 6, 7, 8], [9, 1, 2, 3], [4, 5, 6, 7, 8]]


def np_substract(l1, l2):
    return np.array([np.array(l1[i]) - np.array(l2[i]) for i in range(len(l1))])

print np_substract(a, b)
BPL
  • 9,632
  • 9
  • 59
  • 117
0

You are getting the error, because your code is trying to subtract sublist from sublist, if you want to make it work, you can do the same in following manner:

import numpy as np
a= [[1,2,3,4], [2,3,4,5],[3,4,5,6,7]]
b= [[5,6,7,8], [9,1,2,3], [4,5,6,7,8]]

#You can apply different condition here, like (if (len(a) == len(b)), then only run the following code    
for each in range(len(a)):
    list = np.array(a[each])-np.array(b[each])
    #for converting the output array in to list
    subList[each] = list.tolist()

print subList
justjais
  • 344
  • 3
  • 13
0

A nested list comprehension will do the job:

In [102]: [[i2-j2 for i2,j2 in zip(i1,j1)] for i1,j1 in zip(a,b)] 
Out[102]: [[-4, -4, -4, -4], [-7, 2, 2, 2], [-1, -1, -1, -1, -1]]

The problem with np.array(a)-np.array(b) is that the sublists differ in length, so the resulting arrays are object type - arrays of lists

In [104]: np.array(a)
Out[104]: array([[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6, 7]], dtype=object)

Subtraction is iterating over the outer array just fine, but hitting a problem when subtracting one sublist from another - hence the error message.

If I made the inputs arrays of arrays, the subtraction will work

In [106]: np.array([np.array(a1) for a1 in a])
Out[106]: array([array([1, 2, 3, 4]), array([2, 3, 4, 5]), array([3, 4, 5, 6, 7])], dtype=object)

In [107]: aa=np.array([np.array(a1) for a1 in a])   
In [108]: bb=np.array([np.array(a1) for a1 in b])

In [109]: aa-bb
Out[109]: 
array([array([-4, -4, -4, -4]), 
       array([-7,  2,  2,  2]),
       array([-1, -1, -1, -1, -1])], dtype=object)

You can't count of array operations working on object dtype arrays. But in this case, subtraction is defined for the subarrays, so it can handle the nesting.

Another way to do the nesting is use np.subtract. This is a ufunc version of - and will apply np.asarray to its inputs as needed:

In [103]: [np.subtract(i1,j1) for i1,j1 in zip(a,b)]
Out[103]: [array([-4, -4, -4, -4]), array([-7,  2,  2,  2]), array([-1, -1, -1, -1, -1])]

Notice that these array calculations return arrays or a list of arrays. Turning the inner arrays back to lists requires iteration.

If you are starting with lists, converting to arrays often does not save time. Array calculations can be faster, but that doesn't compensate for the overhead in creating the arrays in the first place.

If I pad the inputs to equal length, then the simple array subtraction works, creating a 2d array.

In [116]: ao= [[1,2,3,4,0], [2,3,4,5,0],[3,4,5,6,7]]; bo= [[5,6,7,8,0], [9,1,2,3,0], [4,5,6,7,8]]

In [117]: np.array(ao)-np.array(bo)
Out[117]: 
array([[-4, -4, -4, -4,  0],
       [-7,  2,  2,  2,  0],
       [-1, -1, -1, -1, -1]])
hpaulj
  • 221,503
  • 14
  • 230
  • 353