Numpy array insert every second element from second array - python

I have two arrays of the same shape and now want to combine them by making every odd element and 0 one of the first array and every even one of the second array in the same order.
E.g.:
a = ([0,1,3,5])
b = ([2,4,6])
c = ([0,1,2,3,4,5,6])
I tried something including modulo to identify uneven indices:
a = ([0,1,3,5])
b = ([2,4,6])
c = a
i = 0
j = 2
l = 0
for i in range(1,22):
k = (i+j) % 2
if k > 0:
c = np.insert(c, i, b[l])
l+=1
else:
continue
I guess there is some easier/faster slicing option, but can't figure it out.

np.insert would work well:
>>> A = np.array([1, 3, 5, 7])
>>> B = np.array([2, 4, 6, 8])
>>> np.insert(B, np.arange(len(A)), A)
array([1, 2, 3, 4, 5, 6, 7, 8])
However, if you don't rely on sorted values, try this:
>>> A = np.array([5, 3, 1])
>>> B = np.array([1, 2, 3])
>>> C = [ ]
>>> for element in zip(A, B):
C.extend(element)
>>> C
[5, 1, 3, 2, 1, 3]

read the documentation of the range
for i in range(0,10,2):
print(i)
will print [0,2,4,6,8]

From what I understand, the first element in a is always first the rest are just intereleaved. If that is the case, then some clever use of stacking and reshaping is probably enough.
a = np.array([0,1,3,5])
b = np.array([2,4,6])
c = np.hstack([a[:1], np.vstack([a[1:], b]).T.reshape((-1, ))])

You could try something like this
import numpy as np
A = [0,1,3,5]
B = [2,4,6]
lst = np.zeros(len(A)+len(B))
lst[0]=A[0]
lst[1::2] = A[1:]
lst[2::2] = B
Even though I don't understand why you would make it so complicated

Related

Multiply two lists but multiply each number in the first list by all numbers in the second list in python

I have two lists I want to multiply each number in the first list by all numbers in the second list
[1,2]x[1,2,3]
I want my result to be like this [(1x1)+(1x2)+(1x3),(2x1)+(2x2)+(2x3)]
numpy
a = np.array([1,2])
b = np.array([1,2,3])
c = (a[:,None]*b).sum(1)
output: array([ 6, 12])
python
a = [1,2]
b = [1,2,3]
c = [sum(x*y for y in b) for x in a]
output: [6, 12]
old answer (product per element)
numpy
a = np.array([1,2])
b = np.array([1,2,3])
c = (a[:,None]*b).ravel()
output: array([1, 2, 3, 2, 4, 6])
python
a = [1,2]
b = [1,2,3]
c = [x*y for x in a for y in b]
## OR
from itertools import product
c = [x*y for x,y in product(a,b)]
output: [1, 2, 3, 2, 4, 6]
def multiplyLists(list1: list, list2:list) -> list:
toReturn = []
for i in list1:
temp_sum = 0
for j in list2:
temp_sum += i * j
toReturn.append(temp_sum)
return toReturn
Another way using numpy (that you can extend to many other functions between two lists):
a = [1,2]
b = [1,2,3]
np.multiply.outer(a,b).ravel()
#array([1, 2, 3, 2, 4, 6])
As the comments point out a pure Python solution will be very different to a numpy solution.
Pyhton
Here it woud be straightforward to use a nested loop or list comprehension:
list1 = [1, 2]
list2 = [1, 2, 3]
lst_output = []
for i in list1:
for j in list2:
lst_output .append(i*j)
#equivalent alternative
lst_output = [i*j for i in list1 for j in list2]
Numpy
There are mny ways to go about it with numpy as well. Here's one example:
arr1 = np.array([1, 2])
arr2 = np.array([1, 2, 3])
xx, yy = np.meshgrid(arr1, arr2)
arr_output = xx * yy
# optionally (to get a 1d array)
arr_output_flat = arr_output.flatten()
Edit: Reading your question again I noticed you state you actually want the output to be 2 sums (of 3 products). I suggest you phrase more precisely what you want an what you've tried. But to provide that here's what you can do with the lists or arrays from above:
# Pure Python
lst_output = [sum(i*j for j in list2) for i in list1]
# Numpy
xx, yy = np.meshgrid(arr1, arr2)
arr_output = np.sum(xx * yy, axis=0)

Split an array inside another in Python

I am trying to write a code that compares two arrays ('a' and 'b)' and do something like that, getting the 'c' array:
a = [1, 2, 2, 3, 3, 5]
b = [1, 2, 3] (It is taken from 'a' randomly)
c = [2, 3, 5]
The problem I have is very simple since the algorithm is ok.
The code I am using is:
vetor1 = [1, 2, 2, 3, 3, 5]
vetor2 = sorted(random.sample(vetor1, 3))
inter = np.intersect1d(vetor1, vetor2)
cont_array2 = []
for i in range(len(inter)):
cont2 = 0
for j in range(len(vetor2)):
if inter[i]==vetor2[j]:
cont2 = cont2 + 1
cont_array2.append(cont2)
cont_array1 = []
for i in range(0,len(inter),1):
cont1 = 0
for j in range(0, len(vetor1), 1):
if inter[i]==vetor1[j]:
cont1 = cont1 + 1
cont_array1.append(cont1)
n_elements = np.subtract(cont_array1, cont_array2)
vetor2_1 = []
for i in range(len(n_elements)):
if n_elements[i]!=0:
vetor2_1.append(inter[i]*np.ones(n_elements[i]))
vetor2_2 = []
for data1 in vetor1:
if data1 not in inter:
vetor2_2.append(data1)
vetor3 = sorted(vetor2_1 + vetor2_2)
print(vetor3)
The result I am getting is:
[array([2.]), array([3.]), 5]
I imagine the problem is in:
vetor2_1.append(inter[i]*np.ones(n_elements[i]))
Because:
print(vetor2_1)
Gives me:
[array([2.]), array([3.])]
What should I do since I am not receving as answer [2, 3, 5]?
IIUC, you can turn all your algorithm into one line:
a = [1, 2, 2, 3, 3, 5]
b = [1, 2, 3]
c = [a.pop(a.index(i)) for i in b] #Works even with strings.
Output:
[2, 3, 5]
If you need to parametrize something, you can turn it into a function. This will work with sorted(random.sample(vetor1, 3)), but I didn't use it for replicability.
//generating a random index for array a, to take 3 elements out of it
my_random_int = random.randint(0,len(a)-2)
//popping the element out of the array to put them in b
for x in range(0,2):
b[x]=a.pop(my_random_int+x)
sources:
https://www.programiz.com/python-programming/methods/list/pop
https://www.edureka.co/blog/generate-random-number-in-python/

Removing matching elements from two numpy arrays

Consider two sorted numpy arrays:
import numpy as np
a = np.array([1,2,4,4,6,8,10,10,21])
b = np.array([3,3,4,6,10,18,22])
How do I:
1. Find the elements that appear in both lists, and
2. Remove only one instance of that occurrence from each list.
That is the output should be:
a = [1,2,4,8,10,21]
b = [3,3,18,22]
So even if there are duplicates, only one instance is removed. However if the lists are
c = np.array([1,2,4,4,6,8,10,10,10,21])
d = np.array([3,3,4,6,10,10,18,22])
I expect to obtain the new outputs:
c = [1,2,4,8,10,21]
d = [3,3,18,22]
which is the same as above. The difference is the number of 10's in the list. Each of the two 10's in list d takes away one 10 each from c leaving the same result.
This post was the closest match to my question, but it removed all instances of repeats from both lists.
You can use collections.Counter:
from collections import Counter
import numpy as np
a = np.array([1, 2, 4, 4, 6, 8, 10, 10, 21])
b = np.array([3, 3, 4, 6, 10, 18, 22])
ca = Counter(a)
cb = Counter(b)
result_a = sorted((ca - cb).elements())
result_b = sorted((cb - ca).elements())
print(result_a)
print(result_b)
Output
[1, 2, 4, 8, 10, 21]
[3, 3, 18, 22]
It returns the same result for (as expected):
a = np.array([1, 2, 4, 4, 6, 8, 10, 10, 10, 21])
b = np.array([3, 3, 4, 6, 10, 10, 18, 22])
You can find the indices of first occurences of intersecting items using np.searchsorted as following and then remove them using np.delete() function:
In [58]: intersect = a[np.in1d(a, b)]
In [59]: mask1 = np.searchsorted(a, intersect)
In [60]: mask2 = np.searchsorted(b, intersect)
In [61]: np.delete(a, mask1)
Out[61]: array([ 1, 2, 4, 8, 10, 21])
In [62]: np.delete(b, mask2)
Out[62]: array([ 3, 3, 18, 22])
I'm not 100% sure what you're looking to do based on the question, but I have been able to duplicate the output using the methods described.
import numpy as np
# List of b that are not in a
a = np.array([1,2,4,4,6,8,10,10,21])
b = np.array([3,3,4,6,10,18,22])
newb = [x for x in b if x not in a]
print(newb)
# REMOVE ONE DUPLICATED ELEMENT FROM LIST
import collections
counter=collections.Counter(a)
print(counter)
newa = list(a)
for k,v in counter.items():
if v > 1:
newa.remove(k)
print(newa)
If you don't mind the verbosity:
import numpy as np
a = np.array([1,2,4,4,6,8,10,10,21])
b = np.array([3,3,4,6,10,18,22])
common_values = set(a) & set(b)
a = a.tolist()
b = b.tolist()
for value in common_values:
a.remove(value)
b.remove(value)
a = np.array(a)
b = np.array(b)
Using for loops:
import numpy as np
a = np.array([1,2,4,4,6,8,10,10,21])
b = np.array([3,3,4,6,10,18,22])
for i, val in enumerate(a):
if val in b:
a = np.delete(a, np.where(a == val)[0][0])
b = np.delete(b, np.where(b == val)[0][0])
for i, val in enumerate(b):
if val in a:
a = np.delete(a, np.where(a == val)[0][0])
b = np.delete(b, np.where(b == val)[0][0])
print(a)
print(b)
Outputs:
[1,2,4,8,10,21]
[3,3,18,22]
Here is a numpy approach:
import numpy as np
a = np.array([1,2,4,4,6,8,10,10,21])
b = np.array([3,3,4,6,10,18,22])
# join and sort (with Tim sort this should be O(n))
ab = np.concatenate([a,b])
i = ab.argsort(kind="stable")
abo = ab[i]
# mark 1st of each group of equal values
d = np.flatnonzero(np.diff(abo,prepend=abo[0]-1,append=abo[-1]+1))
# mark sorted total by origin (a -> False, b -> True)
ig = i>=len(a)
# compare origins of first and last of each group of equal values
# if they are different mark for deletion
dupl = ig[d[:-1]] ^ ig[d[1:]-1]
# finally, delete
ar = np.delete(a,i[d[:-1][dupl]])
br = np.delete(b,i[d[1:][dupl]-1]-len(a))
# inspect
ar
array([ 1, 2, 4, 8, 10, 21])
br
array([ 3, 3, 18, 22])

Efficient way to iterate python loop until previous position

I have a list a and I need to iterate from position 2 until its previous position 1.
# old index - 0 1 2 3 4
a = [1,2,3,4,5]
# new index - 2,3,4,0,1
# new value - 3,4,5,1,2
cnt = 0
while True:
for i in range(2,len(a)):
print(a[i])
for i in range(len(a)-2-1):
print(a[i])
break
I'm using 2 for loops but I believe there should be a better way to do it.
Let's assume we start with a list a = [1,2,3,4,5].
You can use collections.deque and its method deque.rotate:
from collections import deque
b = deque(a)
b.rotate(-2)
print(b)
deque([3, 4, 5, 1, 2])
Or, if you are happy to use a 3rd party library, you can use NumPy and np.roll:
import numpy as np
c = np.array(a)
c = np.roll(c, -2)
print(c)
array([3, 4, 5, 1, 2])
you can create a new list combining the elements after the particular value and before the particular value, let's say 3 in your case:
a = [1, 2, 3, 4, 5]
piv = a.index(3)
print(a[piv:] + a[:piv])
which gives you [3, 4, 5, 1, 2]
a = [1,2,3,4,5]
position = 2
for item in a[position:] + a[:position]:
print(item)
A base python based solution
a[2::] + a[:2:]
Gives
[3, 4, 5, 1, 2]
A generic version of the same would be
rotate_from = 2
a[rotate_from::] + a[:rotate_from:]
Write a function for rotate list,
In [114]: def rotate(lst, n):
...: return lst[-n:] + lst[:-n]
...:
In [115]: rotate(a,-2)
Out[115]: [3, 4, 5, 1, 2]

Summing and removing repeated elements of Numpy Arrays

I have 4 1D Numpy arrays of equal length.
The first three act as an ID, uniquely identifying the 4th array.
The ID arrays contain repeated combinations, for which I need to sum the 4th array, and remove the repeating element from all 4 arrays.
x = np.array([1, 2, 4, 1])
y = np.array([1, 1, 4, 1])
z = np.array([1, 2, 2, 1])
data = np.array([4, 7, 3, 2])
In this case I need:
x = [1, 2, 4]
y = [1, 1, 4]
z = [1, 2, 2]
data = [6, 7, 3]
The arrays are rather long so loops really won't work. I'm sure there is a fairly simple way to do this, but for the life of me I can't figure it out.
To get started, we can stack the ID vectors into a matrix such that each ID is a row of three values:
XYZ = np.vstack((x,y,z)).T
Now, we just need to find the indices of repeated rows. Unfortunately, np.unique doesn't operate on rows, so we need to do some tricks:
order = np.lexsort(XYZ.T)
diff = np.diff(XYZ[order], axis=0)
uniq_mask = np.append(True, (diff != 0).any(axis=1))
This part is borrowed from the np.unique source code, and finds the unique indices as well as the "inverse index" mapping:
uniq_inds = order[uniq_mask]
inv_idx = np.zeros_like(order)
inv_idx[order] = np.cumsum(uniq_mask) - 1
Finally, sum over the unique indices:
data = np.bincount(inv_idx, weights=data)
x,y,z = XYZ[uniq_inds].T
You can use unique and sum as reptilicus suggested to do the following
from itertools import izip
import numpy as np
x = np.array([1, 2, 4, 1])
y = np.array([1, 1, 4, 1])
z = np.array([1, 2, 2, 1])
data = np.array([4, 7, 3, 2])
# N = len(x)
# ids = x + y*N + z*(N**2)
ids = np.array([hash((a, b, c)) for a, b, c in izip(x, y, z)]) # creates flat ids
_, idx, idx_rep = np.unique(ids, return_index=True, return_inverse=True)
x_out = x[idx]
y_out = y[idx]
z_out = z[idx]
# data_out = np.array([np.sum(data[idx_rep == i]) for i in idx])
data_out = np.bincount(idx_rep, weights=data)
print x_out
print y_out
print z_out
print data_out

Categories