numpy / python - indexing by arrays with duplicates - python

I'm trying to make a 3D histogram. Initially h = zeros((6,6,8)).
I'll explain my problem with an example. Suppose I have 3 lists of coordinates for h, each list for one dimension:
x = array([2,1,0,1,2,2])
y = array([1,3,0,3,2,1])
z = array([6,2,0,2,5,6]) (the coordinates (x[0],y[0],z[0]) and (x[6],y[6],z[6]) are duplicates, and (x[1],y[1],z[1]) and (x[3],y[3],z[3]) also are)
and also a list of corresponding quantities to accumulate into h:
q = array([1,2,5,9,8,7])
I tried and h[x,y,z] += q does not work because only q[5] = 7 is added to h[2,1,6] and q[0] = 1 is not.
How can I work around this? Thank you.

IIUC, you want np.add.at. To quote the docs: "For addition ufunc, this method is equivalent to a[indices] += b, except that results are accumulated for elements that are indexed more than once."
For example:
>>> np.add.at(h, [x,y,z], q)
>>> for i, val in np.ndenumerate(h):
... if val: print(i, val)
...
((0, 0, 0), 5.0)
((1, 3, 2), 11.0)
((2, 1, 6), 8.0)
((2, 2, 5), 8.0)

Related

How to find if list instance is available in another list or not?

I have two sets of lists.
list A= [(1,6),(3,10),(4,1),(0,5)]
list B = [(0,3),(0,4),(30,1),(4,10)]
Now for each item in B, I have to check if its available in list A or not for a threshold of -2 to +2.
So the very first value in B which is (0,3), for that using threshold in each point I have found that (from -2 to 2, from 1 to 5) within this rage a list item is available in the list A or not. We can see that the last item value (0,5) fulfil this condition. so I can say that item (0,3) is in list A.Now I have to put this value in a new list.
According to the process, my new list would be :
[(0,3),(0,4),(4,10)]
I will be so glad if somebody tells me how to achieve this.
Here is what i think you are looking for
A= [(1,6),(3,10),(4,1),(0,5)]
B = [(0,3),(0,4),(30,1),(4,10)]
result=[x for x in B if any(x[0]-2<=a[0]<=x[0]+2 and x[1]-2<=a[1]<=x[1]+2 for a in A)]
print(result)
output :
[(0, 3), (0, 4), (4, 10)]
You can use taxi cab geometry:
def manhattan(as_, b):
threshold = 4
for a in as_:
p1, p2 = a
q1, q2 = b
dist = abs(p1 - q1) + abs(p2 - q2)
if dist <= threshold:
return b
else:
continue
t = list(filter(lambda i: manhattan(listA, i), listB))
[(0, 3), (0, 4), (4, 10)]
Or
from operator import truth
t = list(filter(truth, (manhattan(listA, i) for i in listB)))

multiple for statements in any() python

So, I have four lists. Two hold x coordinates (foodX and newPosXArray) and the other two hold y coordinates (foodX and newPosYArray). Both the food and the newPos arrays are of different dimensions because I have multiple "food sources", and multiple objects searching for the food.
I want to write an if statement that does something when the objects get to within a certain distance of the food.
My attempt with any()
if any(np.sqrt((newPosXArray[u]-foodX[t])**2 + (newPosYArray[u]-foodY[t])**2) <= 0.2 for t in zip(food[0], food[1]) for u in zip(newPosXArray, newPosYArray)):
#dosomething
I am getting an error TypeError: list indices must be integers, not tuple
Edit:
maybe I am misunderstanding zip(). I was assuming that it condenses this
if any(np.sqrt((newPosXArray[u]-foodX[t])**2 + (newPosYArray[u]-foodY[t])**2) <= 0.2 for t in foodX for t in foodY for u in newPosXArray for u in newPosYArray):
Typical Values of what I am working with
foodX = [5,5,-5,-5]
foodY = [5,-5,5,-5]
In [65]: newPosXArray
Out[65]:
[-0.012880860643600167,
-0.566815786730638,
0.7905336304903405,
0.09006991095474826,
0.26518652615441063,
0.3161232055076695,
0.681255361368023,
-0.6849985596071202,
0.7140832628874829,
0.4958515031060564]
In [66]: newPosYArray
Out[66]:
[-0.41112817779983235,
-0.08554837651693648,
0.8743935617169996,
-0.9384733737088207,
0.02423386678116546,
-0.3735855691077572,
-0.5251118585489394,
0.3950871276165102,
0.9892320167752822,
-0.7342372054958279]
of course, none of these values will return true in the if statement because none are within a 0.2 radius of any of the food coordinates
Just to be clear nested loops and zip do not do the same thing:
>>> [(i, j) for i in range(3) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
Whereas:
>>> list(zip(range(3), range(3)))
[(0, 0), (1, 1), (2, 2)]
itertools.product does the same as next for loops:
>>> import itertools
>>> list(itertools.product(range(3), range(3)))
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
You don't index into the array when you iterate over an array, e.g:
>>> food = [1,2,3,4]
>>> [f+1 for f in food] # Note you did [food[f] for f in food]
[2,3,4,5]
So fixing your second example looks like:
if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2
for t_x in foodX for t_y in foodY for u_x in newPosXArray for u_y in newPosYArray):
But this iterates foodY for every foodX so assume you do want these to be zipped which would be written:
if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2
for t_x, t_y in zip(foodX, foodY) for u_x, u_y in zip(newPosXArray, newPosYArray)):
Or using itertools.product (which personally I don't find any easier to follow in this instance:
import itertools
if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2
for (t_x, t_y), (u_x, u_y) in itertools.product(zip(foodX, foodY), zip(newPosXArray, newPosYArray))):
You try to get food[][z] but z is tuple (from zip method ), perhaps you meant to do
food[0][z[0]]
Of course, Pythonic way is to just use complex numbers instead of those 2D data separated along the wrong axis. But if you really need to use that data format, I guess
any(math.hypot(X-x,Y-y)<.2 for X,Y in zip(foodX,foodY) for x,y in zip(posX,posY))
will do what you want.
The problem is that u and t are tuples because zip places x and y side by side in tuple format. You need to say food[0][t[1]]andfood[1][t[0]] where you intend to use the list values as coordinates.
From what it sees, you are trying to give it an x,(x,y) coordinate instead of an x,y coordinate.
This holds where you are using u as a list index as well.
if any(np.sqrt((u[0] - t[0]) ** 2 + (u[1] - t[1]) ** 2) <= 0.2 for t in zip(foodX,foodY) for u in zip(newPosXArray,newPosYArray))
From values given it evaluates to False until the 0.2 value gets to 5, which sounds weird given how low your initial value was, but that's how the distance formula works.
Alternatively for readability you could change u to new and t to current.

Looping through a 2-D list within a 1-D list

I have 2 lists:
One dimensional: x_int_loc = [0,1,2,3,4,5]
Two dimensional: xtremes = [[0,2],[0,3],[1,3],[1,5],[2,5],[3,6],[4,8]]
I am trying to gather a count of how many times each element in x_int_loc lies within the range of values in the xtremes list. That is, count of 1 (in list x_int_loc) will be 2, as it appears in [0,2], [0,3] and so on.
Although this appears to be quite simple, I got a bit stuck while looping through these lists. Here is my code:
for i in range(len(x_int_loc)):
while k < len(xtremes):
if x_int_loc[i]>xtremes[k][0] and xtremes[k][1] > x_int_loc[i]:
count[i] = count[i]+1
print(count[:])
Could any of you please tell me where I am going wrong?
You never increment k, or reset it when i increments. The minimal fix is:
for i in range(len(x_int_loc)):
k = 0
while k < len(xtremes):
if x_int_loc[i]>xtremes[k][0] and xtremes[k][1] > x_int_loc[i]:
count[i] = count[i]+1
k += 1
It is not good practice to use a while loop with a manual index; as this clearly demonstrates, it is error prone. Why not just for loop over xtremes directly? All you really need is:
count = [sum(x < n < y for x, y in xtremes) for n in x_int_loc]
which gives me:
>>> count
[0, 2, 3, 2, 3, 2]
Unless you are too particular about optimization, in general cases, the following solution would be optimal
>>> x_int_loc = [0,1,2,3,4,5]
>>> xtremes = [[0,2],[0,3],[1,3],[1,5],[2,5],[3,6],[4,8]]
>>> xtremes_ranges = [xrange(r[0]+1,r[1]) for r in xtremes]
>>> [(x, sum(x in r for r in xtremes_ranges)) for x in x_int_loc]
[(0, 0), (1, 2), (2, 3), (3, 2), (4, 3), (5, 2)]

merge two numpy.array without a loop

I have a two numpy.arrays, I want to get following result efficiently
1.add the element's of b to a's sub-array
a=numpy.array([(1,2,3),(1,2,3)])
b=numpy.array([0,0])
->
c=[(0,1,2,3),(0,1,2,3)]
code in a loop
a=numpy.array([(1,2,3),(1,2,3)])
b=numpy.array([(0,0)])
c=numpy.zeros(2 , 4)
idx=0
for x in a:
c[idx]=(a[idx][0],a[idx][1],a[idx][2], b[idx])
idx = idx+1
and
2. Get an 2-D array with dimension(a.dim*b.dim, 2) from two 1-D arrays
a=numpy.array([(1,2)])
b=numpy.array([(3,4)])
->
c=[(1,3),(1,4),(2,3),(2,4)]
code in a loop
a=numpy.array([(1,2)])
b=numpy.array([(3,4)])
c=numpy.zeros(a.size*b.size , 2)
idx=0
for x in a:
for y in b:
c[idx]=(x,y)
idx = idx+1
For the first problem, you can define b differently and use numpy.hstack:
a = numpy.array([(1,2,3),(1,2,3)])
b = numpy.array([[0],[0]])
numpy.hstack((b,a))
Regarding the second problem, I would probably use sza's answer and create the numpy array from that result, if necessary. That technique was suggested in an old Stack Overflow question.
For the first one, you can do
>>> a=numpy.array([(1,2,3),(1,2,3)])
>>> b=numpy.array([0,0])
>>> [tuple(numpy.insert(x, 0, y)) for (x,y) in zip(a,b)]
[(0, 1, 2, 3), (0, 1, 2, 3)]
For the 2nd one, you can get the 2-D array like this
>>> a=numpy.array([(1,2)])
>>> b=numpy.array([(3,4)])
>>> import itertools
>>> c = list(itertools.product(a.tolist()[0], b.tolist()[0]))
[(1, 3), (1, 4), (2, 3), (2, 4)]

construct graph from python set type

The short question, is there an off the self function to make a graph from a collection of python sets?
The longer question: I have several python sets. They each overlap or some are sub sets of others. I would like to make a graph (as in nodes and edges) nodes are the elements in the sets. The edges are intersection of the sets with weighted by number of elements in the intersection of the sets. There are several graphing packages for python. (NetworkX, igraph,...) I am not familiar with the use of any of them. Will any of them make a graph directly from a list of sets ie, MakeGraphfromSets(alistofsets)
If not do you know of an example of how to take the list of sets to define the edges. It actually looks like it might be straight forward but an example is always good to have.
It's not too hard to code yourself:
def intersection_graph(sets):
adjacency_list = {}
for i, s1 in enumerate(sets):
for j, s2 in enumerate(sets):
if j == i:
continue
try:
lst = adjacency_list[i]
except KeyError:
adjacency_list[i] = lst = []
weight = len(s1.intersection(s2))
lst.append( (j, weight) )
return adjacency_list
This function numbers each set with its index within sets. We do this because dict keys must be immutable, which is true of integers but not sets.
Here's an example of how to use this function, and it's output:
>>> sets = [set([1,2,3]), set([2,3,4]), set([4,2])]
>>> intersection_graph(sets)
{0: [(1, 2), (2, 1)], 1: [(0, 2), (2, 2)], 2: [(0, 1), (1, 2)]}
def MakeGraphfromSets(sets):
egs = []
l = len(sets)
for i in range(l):
for j in range(i,l):
w = sets[i].intersection(sets[j])
egs.append((i,j,len(w)))
return egs
# (source set index,destination set index,length of intersection)
sets = [set([1,2,3]), set([2,3,4]), set([4,2])]
edges = MakeGraphfromSets(sets)
for e in edges:
print e
OUTPUT:
(0, 0, 3)
(0, 1, 2)
(0, 2, 1)
(1, 1, 3)
(1, 2, 2)
(2, 2, 2)

Categories