I need a fast way to keep a running maximum of a numpy array. For example, if my array was:
x = numpy.array([11,12,13,20,19,18,17,18,23,21])
I'd want:
numpy.array([11,12,13,20,20,20,20,20,23,23])
Obviously I could do this with a little loop:
def running_max(x):
result = [x[0]]
for val in x:
if val > result[-1]:
result.append(val)
else:
result.append(result[-1])
return result
But my arrays have hundreds of thousands of entries and I need to call this many times. It seems like there's got to be a numpy trick to remove the loop, but I can't seem to find anything that will work. The alternative will be to write this as a C extension, but it seems like I'd be reinventing the wheel.
numpy.maximum.accumulate works for me.
>>> import numpy
>>> numpy.maximum.accumulate(numpy.array([11,12,13,20,19,18,17,18,23,21]))
array([11, 12, 13, 20, 20, 20, 20, 20, 23, 23])
As suggested, there is scipy.maximum.accumulate:
In [9]: x
Out[9]: [1, 3, 2, 5, 4]
In [10]: scipy.maximum.accumulate(x)
Out[10]: array([1, 3, 3, 5, 5])
Related
I want to check if elements of my series are continuously increasing.
For example if I have the following numbers:
[7, 15, 23, 0, 32, 18]
my output should be
[0, 1, 2, 0, 1, 0]
If any value is greater than the previous value, then the output value will be output of previous value + 1, otherwise it resets to zero.
I have implemented a naive for loop solution in python, which is as follows:
def const_increasing(tmp):
inc_ser = np.zeros(len(tmp))
for i in range(1, len(tmp)):
if tmp[i] > tmp[i-1]:
inc_ser[i] = 1 + inc_ser[i-1]
return inc_ser
But this solution is quite slow, as I am working with pandas series of large sizes. Is there any efficient way of implementing it ? Maybe using expanding() function or any better way in pandas or numpy.
Any help in this regard would be really appreciated.
Since you tagged pandas:
s = pd.Series([7, 15, 23, 0, 32, 18] ).diff().gt(0)
s.groupby((~s).cumsum()).cumcount().to_list()
Output:
[0, 1, 2, 0, 1, 0]
Here is an answer that does not use a cumulative sum:
import numpy as np
a = np.array([7, 15, 23, 0, 32, 18])
c = np.append(np.array([False]), (a[1:] > a[:-1]))
result = np.concatenate([np.arange(x.size)
for x in np.split(c, np.where(c == False)[0][1:])])
Is there a way to use reduce with numpy's append? I want to append 3 arrays together like this:
a = np.array([1,2,3])
b = np.array([11,12,13])
c = np.array([21,22,23])
#below is my real code - the above is just for this example)
np.append.reduce((a,b,c))
but it looks like reduce isn't implemented with append. Thanks for any suggestions.
The output should be:
array([ 1, 2, 3, 11, 12, 13, 21, 22, 23])
np.r_[] will do this cleanly...
a = np.array([1,2,3])
b = np.array([11,12,13])
c = np.array([21,22,23])
#below is my real code - the above is just for this example)
np.r_[a,b,c]
I have an assignment to add a value to a sorted list using list comprehension. I'm not allowed to import modules, only list comprehension, preferably a one liner. I'm not allowed to create functions and use them aswell.
I'm completely in the dark with this problem. Hopefully someone can help :)
Edit: I don't need to mutate the current list. In fact, I'm trying my solution right now with .pop, I need to create a new list with the element properly added, but I still can't figure out much.
try:
sorted_a.insert(next(i for i,lhs,rhs in enumerate(zip(sorted_a,sorted_a[1:])) if lhs <= value <= rhs),value)
except StopIteration:
sorted_a.append(value)
I guess ....
with your new problem statement
[x for x in sorted_a if x <= value] + [value,] + [y for y in sorted_a if y >= value]
you could certainly improve the big-O complexity
For bisecting the list, you may use bisect.bisect (for other readers referencing the answer in future) as:
>>> from bisect import bisect
>>> my_list = [2, 4, 6, 9, 10, 15, 18, 20]
>>> num = 12
>>> index = bisect(my_list, num)
>>> my_list[:index]+[num] + my_list[index:]
[2, 4, 6, 9, 10, 12, 15, 18, 20]
But since you can not import libraries, you may use sum and zip with list comprehension expression as:
>>> my_list = [2, 4, 6, 9, 10, 15, 18, 20]
>>> num = 12
>>> sum([[i, num] if i<num<j else [i] for i, j in zip(my_list,my_list[1:])], [])
[2, 4, 6, 9, 10, 12, 15, 18]
Given an list of integers does exists a default method find the max distance between values?
So if I have this array
[1, 3, 5, 9, 15, 30]
The max step between the values is 15. Does the list object has a method for do that?
No, list objects have no standard "adjacent differences" method or the like. However, using the pairwise function mentioned in the itertools recipes:
def pairwise(iterable):
a, b = tee(iterable)
next(b, None)
return izip(a, b)
...you can (concisely and efficiently) define
>>> max(b-a for (a,b) in pairwise([1, 3, 5, 9, 15, 30]))
15
No, but it's trivial to code:
last = data[0]
dist = 0
for i in data[1:]:
dist = max(dist, i-last)
last = i
return dist
You can do:
>>> s = [1, 3, 5, 9, 15, 30]
>>> max(x[0] - x[1] for x in zip(s[1:], s))
15
This uses max and zip. It computes the difference between all consecutive elements and returns the max of those.
l=[1, 3, 5, 9, 15, 30]
max([j-i for i, j in zip(l[:-1], l[1:])])
That is using pure python and gives you the desired output "15".
If you like to work with "numpy" you could do:
import numpy as np
max(np.diff(l))
The list object does not. However, it is pretty quick to write a function that does that:
def max_step(my_list):
max_step = 0
for ind in xrange(len(my_list)-1):
step = my_list[ind+1] - my_list[ind]
if step > max_step:
max_step = step
return max_step
>>> max_step([1, 3, 5, 9, 15, 30])
15
Or if you prefer even shorter:
max_step = lambda l: max([l[i+1] - l[i] for i in xrange(len(l)-1)])
>>> max_step([1, 3, 5, 9, 15, 30])
15
It is possible to use the reduce() function, but it is not that elegant as you need some way to keep track of the previous value:
def step(maxStep, cur):
if isinstance(maxStep, int):
maxStep = (abs(maxStep-cur), cur)
return (max(maxStep[0], abs(maxStep[1]-cur)), cur)
l = [1, 3, 5, 9, 15, 30]
print reduce(step, l)[0]
The solution works by returing the previous value and the accumulated max calculation as a tuple for each iteration.
Also what is the expected outcome for [10,20,30,5]? Is it 10 or 25? If 25 then you need to add abs() to your calculation.
I am fairly new to python and am trying to figure out how to duplicate items within a list. I have tried several different things and searched for the answer extensively but always come up with an answer of how to remove duplicate items, and I feel like I am missing something that should be fairly apparent.
I want a list of items to duplicate such as if the list was [1, 4, 7, 10] to be [1, 1, 4, 4, 7, 7, 10, 10]
I know that
list = range(5)
for i in range(len(list)):
list.insert(i+i, i)
print list
will return [0, 0, 1, 1, 2, 2, 3, 3, 4, 4] but this does not work if the items are not in order.
To provide more context I am working with audio as a list, attempting to make the audio slower.
I am working with:
def slower():
left = Audio.getLeft()
right = Audio.getRight()
for i in range(len(left)):
left.insert(????)
right.insert(????)
Where "left" returns a list of items that are the "sounds" in the left headphone and "right" is a list of items that are sounds in the right headphone. Any help would be appreciated. Thanks.
Here is a simple way:
def slower(audio):
return [audio[i//2] for i in range(0,len(audio)*2)]
Something like this works:
>>> list = [1, 32, -45, 12]
>>> for i in range(len(list)):
... list.insert(2*i+1, list[2*i])
...
>>> list
[1, 1, 32, 32, -45, -45, 12, 12]
A few notes:
Don't use list as a variable name.
It's probably cleaner to flatten the list zipped with itself.
e.g.
>>> zip(list,list)
[(1, 1), (-1, -1), (32, 32), (42, 42)]
>>> [x for y in zip(list, list) for x in y]
[1, 1, -1, -1, 32, 32, 42, 42]
Or, you can do this whole thing lazily with itertools:
from itertools import izip, chain
for item in chain.from_iterable(izip(list, list)):
print item
I actually like this method best of all. When I look at the code, it is the one that I immediately know what it is doing (although others may have different opinions on that).
I suppose while I'm at it, I'll just point out that we can do the same thing as above with a generator function:
def multiply_elements(iterable, ntimes=2):
for item in iterable:
for _ in xrange(ntimes):
yield item
And lets face it -- Generators are just a lot of fun. :-)
listOld = [1,4,7,10]
listNew = []
for element in listOld:
listNew.extend([element,element])
This might not be the fastest way but it is pretty compact
a = range(5)
list(reduce(operator.add, zip(a,a)))
a then contains
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
a = [0,1,2,3]
list(reduce(lambda x,y: x + y, zip(a,a))) #=> [0,0,1,1,2,2,3,3]