Creating a for loop to find mean for a specific section of list - python-3.x

I would like to loop a list to find the mean for a specific window.
What I mean by this is for example:
num_list=[1,2,3,4,5]
window=3
Thus, I would find the mean for [1,2,3] , [2,3,4] and [3,4,5].
How I approached this was as the following:
average_list=[]
first_list=num_list[0:window]
def mean(data):
n=len(data)
mean=sum(data)/n
return mean
for i in first_list:
first_value=mean(i)
average_list.append(first_value)
I am not quite sure how to incorporate the other two lists without typing it individually. Any help would be greatly appreciated!!

You can use list comprehension to iterate num_list taking slices of length window.
Try this:
mean_lst = [sum(num_list[i:i+window])/window for i in range(len(num_list)-window + 1)]
Result is
[2.0, 3.0, 4.0]

Here's the most obvious solution to your problem:
for i in range(list_len-window+1):
average_list.append(mean(num_list[i:i+window]))
It does work properly, but it isn't optimal. Consider num_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and window = 5. Using obvious method, the code will first calculate the sum of [1, 2, 3, 4, 5], then divide by 5, then it will calculate the sum of [2, 3, 4, 5, 6], then divide by 5, and so on.
This code is clearly doing a lot more calculations than it needs to. An optimal way would be to calculate the mean of first window and then for calculating mean of every consecutive window remove the first_element_of_previous_window/window_size (1/5 for 2nd window) and add last_element_of_current_window/window_size (6/5 for 2nd window) to the mean of previous window. This approach avoids a lot of unnecessary calculations.
Code Implementation:
prev_mean = mean(num_list[:window])
average_list = [prev_mean]
for i in range(1, list_len-window+1):
prev_mean -= num_list[i-1] / window
prev_mean += num_list[i+window-1] / window
average_list.append(prev_mean)

Related

why inserting some element into a list giving None instead of the whole lists? [duplicate]

#!/usr/bin/python
numbers = [1, 2, 3, 5, 6, 7]
clean = numbers.insert(3, 'four')
print clean
# desire results [1, 2, 3, 'four', 5, 6, 7]
I am getting "None". What am I doing wrong?
Mutating-methods on lists tend to return None, not the modified list as you expect -- such metods perform their effect by altering the list in-place, not by building and returning a new one. So, print numbers instead of print clean will show you the altered list.
If you need to keep numbers intact, first you make a copy, then you alter the copy:
clean = list(numbers)
clean.insert(3, 'four')
this has the overall effect you appear to desire: numbers is unchanged, clean is the changed list.
The insert method modifies the list in place and does not return a new reference. Try:
>>> numbers = [1, 2, 3, 5, 6, 7]
>>> numbers.insert(3, 'four')
>>> print numbers
[1, 2, 3, 'four', 5, 6, 7]
The list.insert() operator doesn't return anything, what you probably want is:
print numbers
insert will insert the item into the given list. Print numbers instead and you'll see your results. insert does not return the new list.

Is there a reason why the python 3.x insert function behaves differently from other list functions when it comes to indexing with minus one

I am trying to understand why the index of minus one behaves as it does with the built-in insert function.
# assinging a list to variable a.
a = [1, 2, 3, 4]
print(a) # we get [1, 2, 3, 4]
a.insert(-1, 5)
print(a) # we get [1, 2, 3, 5, 4]
# why is this different than other list indexing using minus one.
It's not, actually. In case you use
>>> a = [1, 2, 3, 4]
>>> a[-1]
4
The [-1] index gives you the last element. All is fine. So why the -1 in insert() function inserts the element before the element, and not as the last? Answer is in the docs:
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
So as you see, it might be counterintuitive, but it's all in the docs. As a sidenote, I'd recommend you reading wtfpython, maybe you'll find some other fancy quirks.

Removing duplicates in a list (Python 3.8.3)

I want to just understand why the below code is not very good at removing duplicates:
numbers = [4, 4, 4, 10, 10, 10, 20, 20, 2]
for duplicates in numbers:
numbers.count(duplicates)
if numbers.count(duplicates) > 1:
numbers.remove(duplicates)
numbers.sort()
print(numbers)
The final output is: [2, 4, 10, 10, 20]
This could just be a fundamental error in my understanding of the methods used, but I would like to know what is wrong here.
PS. I'm aware I could do an easier version of this code posted below, but I am just curious.
Easier version of above code:
numbers = [4, 4, 4, 10, 10, 10, 20, 20, 2]
unique_list = []
for duplicates_check in numbers:
if duplicates_check not in unique_list:
unique_list.append(duplicates_check)
unique_list.sort()
print(unique_list)
Thanks in advance for your help!
Modifying the list as you're iterating over it is a bad idea (since the loop gets "confused" about which index it's on).
Since you're sorting the numbers in the end, you apparently don't care about the order.
Just do
numbers = sorted(set(numbers))
– that is, convert the numbers to a set; sets can only contain each element once, then use sorted() to sort the set into a new list.
If you would care about the order,
def unique_in_order(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
numbers = list(unique_in_order(iterable))
is your recipe.

Why is the output of this code only even numbers between 1 and 121?

A=list(range(1,121))
for i in A:
A.remove(i)
print(A)
Shouldn't it be empty? I really don't get this..
You typically don't want to modify lists you're iterating over because you will get weird results like what you're running into.
You have a list of numbers, 1-121. You remove the first one, everything shifts down in memory so 2 is now in the zeroeth position. Do range 2-122 and you'll get only odd numbers.
x = [1, 2, 3, 4, 5, 6]
for i in x:
x.remove(i)
#first time through x = [2, 3, 4, 5, 6]
# ^ i is still pointing here though and the next time
# through it will be pointing at 3 (i = 2)

How to use iter and next in a function to return a list of peaks?

Problem:
I need to define a peaks function which passed to an iterable as parameter, by computing this iterable, the function should return a list of peaks. The only data structure that I can create is the list is returning; use no intermediate data structures to help the computation: e.g., I cannot create a list with all the values in the iterable. Note that I also cannot assume the argument is indexable, nor can I compute len for it: it is just iterable.
For example:
peaks([0,1,-1,3,8,4,3,5,4,3,8]) returns [1, 8, 5].
This result means the values 1, 8, and 5 are strictly bigger than the values immediately preceding and following them.
def peaks(iterable):
l=[]
i=iter(iterable)
v=next(i)
try:
while True:
if v>next(iter(iterable)):
l.append(v)
v=next(i)
except StopIteration:
pass
return l
Calling these should give me:
peaks([0,1,-1,3,8,4,3,5,4,3,8]) --> [1,8,5]
peaks([5,2,4,9,6,1,3,8,0,7]) -->[9,8]
But I am getting:
peaks([0,1,-1,3,8,4,3,5,4,3,8]) --> [1, 3, 8, 4, 3, 5, 4, 3, 8]
peaks([5,2,4,9,6,1,3,8,0,7]) --> [9, 6, 8, 7]
Please help me with this problem, I have spent so much time on it and am making no progress on it. And, I don't know how to write the if statement to check the values immediately preceding and following. Any helps would be great! Actual codes would be really appreciated since my English is bad.
def peaks(L):
answer = []
a,b,c = itertools.tee(L, 3)
next(b)
next(c)
next(c)
for first, second, third in zip(a,b,c):
if first <= second >= third:
answer.append(second)
return answer
In [61]: peaks([0,1,-1,3,8,4,3,5,4,3,8])
Out[61]: [1, 8, 5]
In [62]: peaks([5,2,4,9,6,1,3,8,0,7])
Out[62]: [9, 8]

Resources