Related
I want to merge certain values that are numerically close.
In this example I'll look to merge anything that can be connected via a neighboring value with a difference less 2.
import numpy as np
a = np.arange(10)
a = np.delete(a, (3, 7))
matrix = np.abs(a.reshape(-1,1) - a)
matrix < 2
array([[ True, True, False, False, False, False, False, False],
[ True, True, True, False, False, False, False, False],
[False, True, True, False, False, False, False, False],
[False, False, False, True, True, False, False, False],
[False, False, False, True, True, True, False, False],
[False, False, False, False, True, True, False, False],
[False, False, False, False, False, False, True, True],
[False, False, False, False, False, False, True, True]])
Starting at the top left corner:
First move horizontal to find the last true value.
Then go downwards to find the last true value.
Repeat both until the square is found.
Cannot connect True values diagonally.
This would give you the first square that goes from [0,2] to [2,2].
The desired output of this example would be:
[[0, 2], [3, 5], [6, 7]]
Where the values indicate the beginning and end of the square. Is there a good way of doing this?
I'd prefer not to loop if possible.
So I've done this using np.diagonal as the basis for the logic.
bm = matrix < 2
endcoords = np.argwhere(bm[1:].diagonal() == False)
zers = np.zeros(endcoords.shape)
zers[1:] += endcoords[:-1] + 1
end = np.hstack((zers, endcoords))
end
array([[0., 2.],
[3., 5.]])
I know this excludes the last coordinate, which for my example doesn't give the 'correct' answer. This however, does give the right answer for my workflow as I'm chunking arrays together - so the last missing coordinate will be the first of my next array. It shouldn't be too hard to finagle the right answer from this anyways.
I have the following tensor:
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
I applied conditions along the axis like below.
new_pred= []
if predictions == ([True,False,False]):
new_pred = torch.Tensor(0)
if predictions == ([False,False,True]):
new_pred = torch.Tensor(2)
if predictions == ([False,True,True]):
new_pred = torch.Tensor(2)
So I want the final output (new_pred) to be:
tensor([0, 2, 2, 0])
But I am getting a blank [] for the new_pred tensor. I think my logic must be flawed since nothing is getting stored in the new_pred. Can someone help me write this logic accurately?
The type of predictions is torch.Tensor while ([True, False, False]) is a list, first, you have to make sure both sides have the same type.
predictions == torch.tensor([True,False,False])
>>> tensor([[ True, True, True],
[False, True, False],
[False, False, False],
[True, True, True]])
Then, you are still comparing a 2d tensor to a 1d tensor, which is ambiguous in an if statement, an easy way to fix this would be to write a for loop, compare each row of the predictions to the conditions and append the result to the new_pred list. Note that you will be comparing two booleans tensors with the size of three, therefore, you have to make sure the result of the comparison is True for all of the cells.
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
conditions = torch.tensor([[True,False,False],
[False,False,True],
[False,True,True]])
new_predict = []
for index in range(predictions.size(0)):
if (predictions[index] == conditions[0]).all():
new_predict.append(0)
# ...
Alternatively, you can use slicing to achieve your expected result without any for loop.
I need to find in which index in the large list where it match with the sub list.
c = np.array(close)
EMA50 = np.array(MA50)
sublist = [False,True,True]
biglist = (c-EMA50)/c>0.01
>>>array([False, False, False, False, False, False, False, False, False,
False, False, False, False, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, False, False, True, False, True, True, False, False,
True, False, False, False, False, False, False, False, True,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, True, True, True,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, True, True, True, True], dtype=bool)
>>>sublist in biglist
>>>False
I expected True but it return False.
The desired output is
index_loc = [12,31,68,112]
One very easy solution using the sublist pattern for slicing and checking for that signature and getting the indices would be -
np.flatnonzero(~a[:-2] & a[1:-1] & a[2:]) # a as data array
Explanation
Basically, we are slicing three slices out of the data array - One that starts at 0th index and goes until leaving out last two elements, another that starts at 1st index and ends at second last element and a third slice starting at 2nd and goes on until the end. These three slices correspond to the three elements of matching required against the sublist pattern that's - [False, True, True]. We need to make sure that the first one is False, in other words, let's make sure the negation of it is True. Negation in NumPy is achieved through ~ operator. So, in essence, we get the combined mask off those three slices and get the corresponding indices with np.flatnonzero.
For the given data results in -
In [79]: np.flatnonzero(~a[:-2] & a[1:-1] & a[2:])
Out[79]: array([ 12, 31, 68, 112])
in won't check for sub-arrays. Instead, it checks for elements.
You will have to do something like this:
(Using A for big array and b for sub-list for readability.)
n = len(b)
c = [i for i in xrange(len(A)-n+1) if (b==A[i:i+n]).all()]
c is the required list of indexes.
Explanation:
This is basic List Comprehension in python.
The idea is to create sub-arrays of the bigarray and check if it matches the sublist.
Breaking down the statement for better understanding:
c = []
for i in xrange(len(A)-n+1):
if (b==A[i:i+n]).all(): # if list and arrays match
c.append(i)
Is there a way to generate an array, masking a rectangular area, without the need to initialize an empty array first?
mask = np.zeros((10,10), dtype=bool)
mask[10/2:,10/2:] = True
Im looking for an numpy expression that would replace these two lines and generate mask
If you really, really want to have a one-liner, this is a possible way. But I'd say your original code is cleaner, clearer, and overall better...
>>> np.logical_and.outer(np.arange(10) >= 5, np.arange(6) >= 3)
array([[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True]], dtype=bool)
That can be done in one line:
mask = np.fromfunction(lambda i, j: (i >= 5) * (j >= 5), (10, 10), dtype=int)
but this turns out to be quite a bit slower than the original implementation. (It creates two arrays holding row and column indices).
You can use np.empty if you don't want to initialize the array and set the values manually. In this specific case, however, you might be better off using np.zeros or np.ones and flip the values for whichever is the smallest number of entries that you need to update.
I have a string of 50 Christmas lights in a single line, and when they are first plugged in, all of the lights are off. The lights are controlled by a single button, where every time the button is pressed, some of the lights flip their state (i.e. if they are off, they change to on; if they are on, they change to off). The selection of lights which change depends on how many times the button has been pressed so far:
On the 1st press, the 1st, 2nd, 3rd, 4th, …, 50th lights change state
On the 2nd press, the 2nd, 4th, 6th, …, lights change state;
On the 3rd press, the 3rd, 6th, 9th, …, lights change state;
etc.
On the nth press, the lights corresponding to all multiples of n change state.
How do I find out what lights are on after any given number of "n" presses?
I tried defining a boolean array to represent the lights. I wrote the following function:
lightsarray = [False] * 50 ### All lights are off at start ###
def pressbutton(n):
count = 0
for count in range(0, n):
lightsarray[::int(n)] = [not y for y in lightsarray[::int(n)]]
count = count + 1
return lightsarray
Currently, the output for n = 1 is True, True, True, True, True, True...
The output for n = 2 is True, False, True, False, True, False...
So far so good. But for n = 3, I'm expecting True, False, False, False, True, True, True...
But I'm getting True, False, False, True, False, False...
I think I'm going wrong in assigning/getting the state of the array. How do I correct this? Or is there a better approach?
--EDIT--
Thanks for the responses everyone. I implemented the changes and I'm getting the output you've suggested, but I'm not sure whether this matches the expected state of the lights. Keeping in mind that False = OFF and True = ON, let's look at the first 5 lights. This is what is expected:
For 0 presses, everything is off:
False, False, False, False, False...
For 1 press, lights at every multiple of 1 are flipped:
True, True, True, True, True...
For 2 presses, the lights at every multiple of 2 are flipped:
True, False, True, False, True...
Note that the second and the fourth light were toggled, otherwise the rest remained unchanged.
For 3 presses, the lights at every multiple of 3 are flipped:
True, False, False, False, True...
However after making the changes, for instance, 2 presses gives False, True... not True, False... and 3 presses gives True, True, False, False, False... (there are two Trues in the beginning.)
How do I correct this? I hope that made sense.
Your main problem is that you are using count in multiple ways in the same function. In essence, for count in range uses the same variable as count=0, and count = count + 1 is modifying the loop variable.
The other problem is that you are modifying the global lightsarray every time you run the function, so your output will depend on how you previously rand the function.
Finally, if your pressbutton function is supposed to be showing the result of pressing the button n times, as it appears to be doing, you should be changing different lights every loop iteration, instead of flipping every nth light every loop iteration.
You should just be doing
def pressbutton(n):
lightsarray = [False] * 50 ### All lights are off at start ###
for count in range(0, n):
lightsarray[::count] = [not y for y in lightsarray[::count]]
return lightsarray
If I understand the progression I would say that for each step k, we select first the kth element and then move to the 2kth element, 3k, 4k...
This can be achieved using xrange (I prefer xrange to range since it doesn't fillup memory) wich take a step argument.
here's an example of such progressions
for k in xrange(1, n + 1):
print range(k, n, k)
That should do it, here's the output, looks similar to your example:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 4, 6, 8]
[3, 6, 9]
[4, 8]
[5]
[6]
[7]
[8]
[9]
[]
Notince that you don't have to go to n + 1, you can stop at n :)
You switch the wrong lights; you are using n, not count, the loop counter, so you are always switching the wrong lights.
You need to start counting at 1, and count up to n (so range to `n + 1).
Your indentation is wrong; you return too early. Unindent the return statement to not be part of the loop.
I'd also make the lightsarray value part of the function itself, don't use a global here, as it'll be mutated each time you call the function, making it harder to test the function itself.
Last but not least, there is no need to increment count manually, that's what the for loop is already doing for you:
def pressbutton(n):
lightsarray = [False] * 50 ### All lights are off at start ###
for count in range(1, n + 1):
lightsarray[::count] = [not y for y in lightsarray[::count]]
return lightsarray
Now this works as expected:
>>> pressbutton(1)
[True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]
>>> pressbutton(2)
[False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True]
>>> pressbutton(3)
[True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True, False, False, False, True, True, True]