Related
I have a 2d numpy array like so. I want to find the maximum consecutive streak of 1's for every row.
a = np.array([[1, 1, 1, 1, 1],
[1, 0, 1, 0, 1],
[1, 1, 0, 1, 0],
[0, 0, 0, 0, 0],
[1, 1, 1, 0, 1],
[1, 0, 0, 0, 0],
[0, 1, 1, 0, 0],
[1, 0, 1, 1, 0],
]
)
Desired Output: [5, 1, 2, 0, 3, 1, 2, 2]
I have found the solution to above for a 1D array:
a = np.array([1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0])
d = np.diff(np.concatenate(([0], a, [0])))
np.max(np.flatnonzero(d == -1) - np.flatnonzero(d == 1))
> 4
On similar lines, I wrote the following but it doesn't work.
d = np.diff(np.column_stack(([0] * a.shape[0], a, [0] * a.shape[0])))
np.max(np.flatnonzero(d == -1) - np.flatnonzero(d == 1))
The 2D equivalent of you current code would be using pad, diff, where and maximum.reduceat:
# pad with a column of 0s on left/right
# and get the diff on axis=1
d = np.diff(np.pad(a, ((0,0), (1,1)), constant_values=0), axis=1)
# get row/col indices of -1
row, col = np.where(d==-1)
# get groups of rows
val, idx = np.unique(row, return_index=True)
# subtract col indices of -1/1 to get lengths
# use np.maximum.reduceat to get max length per group of rows
out = np.zeros(a.shape[0], dtype=int)
out[val] = np.maximum.reduceat(col-np.where(d==1)[1], idx)
Output: array([5, 1, 2, 0, 3, 1, 2, 2])
Intermediates:
np.pad(a, ((0,0), (1,1)), constant_values=0)
array([[0, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0],
[0, 1, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0],
[0, 1, 0, 1, 1, 0, 0]])
np.diff(np.pad(a, ((0,0), (1,1)), constant_values=0), axis=1)
array([[ 1, 0, 0, 0, 0, -1],
[ 1, -1, 1, -1, 1, -1],
[ 1, 0, -1, 1, -1, 0],
[ 0, 0, 0, 0, 0, 0],
[ 1, 0, 0, -1, 1, -1],
[ 1, -1, 0, 0, 0, 0],
[ 0, 1, 0, -1, 0, 0],
[ 1, -1, 1, 0, -1, 0]])
np.where(d==-1)
(array([0, 1, 1, 1, 2, 2, 4, 4, 5, 6, 7, 7]),
array([5, 1, 3, 5, 2, 4, 3, 5, 1, 3, 1, 4]))
col-np.where(d==1)[1]
array([5, 1, 1, 1, 2, 1, 3, 1, 1, 2, 1, 2])
np.unique(row, return_index=True)
(array([0, 1, 2, 4, 5, 6, 7]),
array([ 0, 1, 4, 6, 8, 9, 10]))
out = np.zeros(a.shape[0], dtype=int)
array([0, 0, 0, 0, 0, 0, 0, 0])
out[val] = np.maximum.reduceat(col-np.where(d==1)[1], idx)
array([5, 1, 2, 0, 3, 1, 2, 2])
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
I am trying to do a simple task in python and I cannot figure out why it is failing at the append() function.
d = pd.DataFrame([1,2,3,4,5,6,1,2,3,])
d.columns = ['prediction_num']
def cumulative_vector(df):
vector = [0,0,0,0,0,0,0,0,0]
vectorL = []
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector)
df['cumulative_histogram'] = vectorL
print(df.cumulative_histogram)
return df
cumulative_vector(d)
When I print out the vector variable in the loop, I get the right output, which is:
[0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 2, 1, 1, 1, 0, 0]
However, when I print the newly created df.cumulative_histogram column, I get this:
0 [0, 2, 2, 2, 1, 1, 1, 0, 0]
1 [0, 2, 2, 2, 1, 1, 1, 0, 0]
2 [0, 2, 2, 2, 1, 1, 1, 0, 0]
3 [0, 2, 2, 2, 1, 1, 1, 0, 0]
4 [0, 2, 2, 2, 1, 1, 1, 0, 0]
5 [0, 2, 2, 2, 1, 1, 1, 0, 0]
6 [0, 2, 2, 2, 1, 1, 1, 0, 0]
7 [0, 2, 2, 2, 1, 1, 1, 0, 0]
8 [0, 2, 2, 2, 1, 1, 1, 0, 0]
Why does the column only contain the last value of vector in the loop and not each iterative value? It is appended during each loop, so I am unsure what I am missing.
For loop is reusing your old vector object. This means that at each iteration you only have one list that you are modifying. Printing is working fine because you are printing the state of the list at a specific point in time.
r = []
for idx in range(0,10):
r.append(idx)
print(r)
---
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for idx in range(0,10):
r = []
r.append(idx)
print(r)
---
[9]
To fix your specific case, add [:] to append a copy of the list instead.
# ...
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector[:]) # vector -> vector[:] here
Let's say I have a list of pattern [2, 1] and given a length = 5.
The pattern means that there are sets of 2 and 1 'ones' in the list in that order in a list of length = 5.
Also the space or 0 between successive groups has to be at least one.
What I've tried is:
for curr_col in pattern_list:
curr_pattern = curr_col
example_combo = [0] * dim0
idx, group_strt_idxs = 0, []
for num in curr_pattern :
group_strt_idxs.append(idx)
for i in range(num ):
example_combo[idx] = 1
idx += 1
if idx < dim0 and dim0 > 1:
example_combo[idx] = 0
idx += 1
print('ex', example_combo)
Please help!
The problem is to put the zeros into len(constraints_list) + 1 buckets. The first and last one can contain 0 or more zeros, the intermediate ones must contain at least one.
We generate the possible repartitions in the repartitions function. It is then easy to build the corresponding list:
from itertools import zip_longest
def repartitions(number, buckets, start=None):
if start is None:
start = []
mini = 0 # first sequence of zeros can be empty
else:
mini = 1 # others contain at least one zero
if buckets == 1:
# last bucket, we put all remaining zeros here
start = start + [number]
yield start
else:
for i in range(mini, number-buckets+3):
# we have to keep at least 1 zero for each other bucket
# except the last one.
current = start + [i]
yield from repartitions(number-i, buckets-1, current)
def permutations_with_constraints(constraints_list, length):
number_of_zeros = length - sum(constraints_list)
buckets = len(constraints_list) + 1
for rep in repartitions(number_of_zeros, buckets):
out = sum(([0]*zeros + [1]*ones
for zeros, ones in zip_longest(rep, constraints_list, fillvalue=0)), [])
yield out
Some examples:
print(list(permutations_with_constraints([1, 2], 5)))
# [[1, 0, 1, 1, 0], [1, 0, 0, 1, 1], [0, 1, 0, 1, 1]]
print(list(permutations_with_constraints([2, 3, 2], 11)))
# [[1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0],
# [1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0],
# [1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1],
# [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0],
# [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1],
# [1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
# [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
# [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
# [0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1],
# [0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1]]
Some explanations about the sum, as you asked in comments:
We have a rep list, and a one item shorter constraints list. We zip them with zip_longest and a fillvalue=0, which gives us [(rep[0], constraints[0]), (rep[1], constraints[1]), ... (rep[-1], 0)]. (It's really a generator, not a list, but this doesn't change anything to the explanation). The last 0 fills the missing value in constraints.
We then build a list from each tuple. For example, (2, 3) will give us [0, 0, 1, 1, 1]. sum then adds these lists, using [] as a start value.
Since the length of the groups of 1's are already given, the recursion can determine the placing for each:
def generate_groups(d, fill=1):
return [[fill]*i for i in d]
def all_groups(_d, _len):
def groupings(d, current = []):
if sum(not i for i in current) == d and sum(i == '*' for i in current) == len(_d):
yield current
else:
if sum(not i for i in current) < d:
yield from groupings(d, current+[0])
if not current or not current[-1]:
yield from groupings(d, current+['*'])
return [(lambda x, y:[c for h in y for c in ([h] if not h else next(x))])(iter(generate_groups(_d)), i)
for i in groupings(_len-sum(_d))]
print(all_groups([2, 1], 5))
print(all_groups([2, 3, 2], 11))
Output:
[[0, 1, 1, 0, 1], [1, 1, 0, 0, 1], [1, 1, 0, 1, 0]]
[[0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1], [0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1], [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1], [0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0], [1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0]]
I'm stuck on this problem. How can I create a program that adds 1 randomly to a list of [0, 0, 0, 0, 0, 0]. And I wanted to keep it going until all the numbers in the list is at least > 0.
I have three problems in my code and I don't know what it is. This my code and the list Votes = [0, 0, 0, 0, 0, 0]:
It stops printing after the 7th time
Sometimes it’s starts with more than 1 in an item
I want it to start it with an just 1 in a list and from there add 1 randomly to a item in the list.
So I want at least one of each in the list which would be greater than 0.
My code is
Def get_all_prizes():
For items in votes:
Items = random.radiant(0, 5)
Votes[items] + = 1
If items == 0:
False
Else:
Print(votes)
This is what is printed
[0, 0, 0, 0, 1, 0]
[0, 0, 1, 0, 1, 0]
[0, 1, 1, 0, 1, 0]
[0, 1, 2, 0, 1, 0]
[0, 1, 3, 0, 1, 0]
[0, 1, 3, 1, 1, 0]
It only does 6 times, and sometimes it starts like this. I wanted it to start just by having just 1 number in the list like the previously printed stuffs
[0, 1, 2, 0, 1, 0]
[0, 1, 3, 0, 1, 0]
[0, 1, 3, 1, 1, 0]
If I understand your problem correctly, you could use all to check if every element is larger than 0 and keep looping with while until this condition is fullfilled:
import random
n = 6
votes = [0] * n
while not all(votes):
i = random.randrange(0, n)
votes[i] += 1
print(votes)
# [0, 0, 0, 0, 1, 0]
# [1, 0, 0, 0, 1, 0]
# [1, 0, 1, 0, 1, 0]
# [1, 0, 2, 0, 1, 0]
# [1, 0, 2, 0, 1, 1]
# [1, 0, 2, 1, 1, 1]
# [1, 0, 2, 2, 1, 1]
# [1, 0, 3, 2, 1, 1]
# [2, 0, 3, 2, 1, 1]
# [2, 0, 3, 3, 1, 1]
# [2, 0, 3, 4, 1, 1]
# [2, 0, 3, 4, 2, 1]
# [2, 0, 3, 5, 2, 1]
# [2, 0, 3, 6, 2, 1]
# [3, 0, 3, 6, 2, 1]
# [4, 0, 3, 6, 2, 1]
# [4, 0, 3, 6, 3, 1]
# [4, 0, 3, 6, 4, 1]
# [4, 1, 3, 6, 4, 1]
I am trying to count the number of occurrences a 0 occurs in two lists together and save that number using python. I am trying to put it into a third list using 'list comprehension' commands but I am not getting the output I want.
My two lists are:
list1 = [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
list2 = [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
So, anytime there is a 0 occuring in the same place in each list I would like to append '0' into a new list. I would like to do the same thing with the ones.
the new list should look like:
newlist = [0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1]
Thanks for the help in advance, I've been trying to figure out how to do this for several hours now to no avail!
You can use a list comprehension, like this:
answer = [x for x, y in zip(list1, list2) if x == y]
Alternatively, you can solve it without list comprehensions by using simple list operations:
answer = []
for x, y in zip(list1, list2):
if x == y:
answer.append(x)
In both cases, answerwill be:
[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[x or y for x,y zip(list1, list2)]
[0 if x == (0,0) else 1 for x in zip(list1,list2)]
list1 = [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
list2 = [0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
temp = [ list1[i] if list1[i] == list2[i] else 2 for i in range( 0, len(list1) )]
answer = [value for value in temp if value != 2]
print( answer )
Solution
If you want list consisting of 0 and 1 in order of 0 or 1 appearing at the same position in both lists, then you can use the following list comprehension:
result = [a for a, b in zip(list1, list2) if a==b]
Test
Testing your values however:
>>> newlist = [a for a, b in zip(list1, list2) if a==b]
>>> newlist
[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
you see that the result is not equal to what you have been expecting:
>>> newlist == [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
False
So the question for you is: is the expected result you have provided a correct one?