Python list index out of range - finding local maxima - python

I have a dataset and am trying to work out where there are peaks in the data; a data point with a higher value than the point before and after it.
I have code which works for one dataset but now transferring it to another dataset brings up index out of range error for certain lines.
The code I have is:
for line in file.readlines():
peaks.append(0)
line = line.split(',')
time.append(float(line[0]))
TP.append(float(line[3]))
level.append(float(line[5]))
for i in range(len(level)-1):
i = i + 1
if (level[i] > level[i-1]) and (level[i] > level[i+1]):
peaks[i] = 1
noPeaks = noPeaks +1
print noPeaks
Yet for one line (so far) it says data is out of range - visually inspecting the data doesn't suggest this - the value is higher than the previous value but lower than the next so on a rising limb of the graph.
Any help would be great!

I cannot see your loop but the (level[i] > level[i+1]) suggests that you are forgetting to put
for i in range(1,len(list)-1)
key to note there is that -1 since you're doing that +1 and the range only goes to max-1 anyway.
Starting your loop at 0 would not throw an out of bounds error since list[-1] is perfectly legal in python. however, i dont think you want your first comparison to be list[-1] > list[0]
Due to edit,
You do not need to do the
i = i + 1
line in you're code, you will hit the length of the list because the for loop will also increment, causing an out of bounds error. Remove that line and it should work.

If you're looping over a list l usingi`, then you should take to handle both the first and last points specially:
for i in xrange(1, len(l) - 1):
# your check

When i is referring to the last element of level, level[i+1] will not exist and will raise IndexError.

I've rewritten this taking into account other people's answers:
for line in file:
line = line.split(',')
time.append(float(line[0]))
TP.append(float(line[3]))
level.append(float(line[5]))
peaks = [0]*len(level)
numPeaks = 0
for i in range(1, len(level)-1):
if level[i-1] < level[i] and level[i+1] < level[i]:
peaks[i] = 1
numPeaks += 1
print numPeaks

Related

Extracting multiple data from a single list

I working on a text file that contains multiple information. I converted it into a list in python and right now I'm trying to separate the different data into different lists. The data is presented as following:
CODE/ DESCRIPTION/ Unity/ Value1/ Value2/ Value3/ Value4 and then repeat, an example would be:
P03133 Auxiliar helper un 203.02 417.54 437.22 675.80
My approach to it until now has been:
Creating lists to storage each information:
codes = []
description = []
unity = []
cost = []
Through loops finding a code, based on the code's structure, and using the code's index as base to find the remaining values.
Finding a code's easy, it's a distinct type of information amongst the other data.
For the remaining values I made a loop to find the next value that is numeric after a code. That way I can delimitate the rest of the indexes:
The unity would be the code's index + index until isnumeric - 1, hence it's the first information prior to the first numeric value in each line.
The cost would be the code's index + index until isnumeric + 2, the third value is the only one I need to store.
The description is a little harder, the number of elements that compose it varies across the list. So I used slicing starting at code's index + 1 and ending at index until isnumeric - 2.
for i, carc in enumerate(txtl):
if carc[0] == "P" and carc[1].isnumeric():
codes.append(carc)
j = 0
while not txtl[i+j].isnumeric():
j = j + 1
description.append(" ".join(txtl[i+1:i+j-2]))
unity.append(txtl[i+j-1])
cost.append(txtl[i+j])
I'm facing some problems with this approach, although there will always be more elements to the list after a code I'm getting the error:
while not txtl[i+j].isnumeric():
txtl[i+j] list index out of range.
Accepting any solution to debug my code or even new solutions to problem.
OBS: I'm also going to have to do this to a really similar data font, but the code would be just a sequence of 7 numbers, thus harder to find amongst the other data. Any solution that includes this facet is also appreciated!
A slight addition to your code should resolve this:
while i+j < len(txtl) and not txtl[i+j].isnumeric():
j += 1
The first condition fails when out of bounds, so the second one doesn't get checked.
Also, please use a list of dict items instead of 4 different lists, fe:
thelist = []
thelist.append({'codes': 69, 'description': 'random text', 'unity': 'whatever', 'cost': 'your life'})
In this way you always have the correct values together in the list, and you don't need to keep track of where you are with indexes or other black magic...
EDIT after comment interactions:
Ok, so in this case you split the line you are processing on the space character, and then process the words in the line.
from pprint import pprint # just for pretty printing
textl = 'P03133 Auxiliar helper un 203.02 417.54 437.22 675.80'
the_list = []
def handle_line(textl: str):
description = ''
unity = None
values = []
for word in textl.split()[1:]:
# it splits on space characters by default
# you can ignore the first item in the list, as this will always be the code
# str.isnumeric() doesn't work with floats, only integers. See https://stackoverflow.com/a/23639915/9267296
if not word.replace(',', '').replace('.', '').isnumeric():
if len(description) == 0:
description = word
else:
description = f'{description} {word}' # I like f-strings
elif not unity:
# if unity is still None, that means it has not been set yet
unity = word
else:
values.append(word)
return {'code': textl.split()[0], 'description': description, 'unity': unity, 'values': values}
the_list.append(handle_line(textl))
pprint(the_list)
str.isnumeric() doesn't work with floats, only integers. See https://stackoverflow.com/a/23639915/9267296

IndexError: list index out of range even though printing individual lists and index doesn't seem to have an error

take = randint(0, len(teacherClass[teacher])-1)
print(take)
print(teacherClass)
print(teacher)
print(teacherClass[teacher])
triesDone = 0
while triesDone < len(teacherClass[teacher]):
cp = teacherClass[teacher][take]
if (cp not in (blocks[teacher][day])) and (blocksS[cp][day][block] == ""):
blocks[teacher][day][block] = cp
blocksS[cp][day][block] = teacherSub[teacher]
take +=1
triesDone += 1
if take == len(teacherClass[teacher])-1:
take = 0
When I run the program after some time, the above part is hit and the program starts working as intended but line 8 raises the error ("IndexError: list index out of range").
Trying to solve that and understand the problem, I tried to print the entire dictionary(teacherClass) and the indices used(teacher and take) but even after that, it seems the line 8 should work.
Output I am getting:
Output with list and index
Please help me understand the problem and a solution. Thanks
There is a possibility that take could be: len(teacherClass[teacher])-1 from the assignment on the first line. Later there is take += 1. This mean that it is larger than the limit, so take = 0 is never executed.
Did you mean:
if take >= len(teacherClass[teacher])-1:
take = 0

Unsure of how to reference an element within a list to an if statement

for row in range(numLines):
if row[intIdx](3) is not 'DEP':
check_total += float(row[intIdx][2])
else:
deposit_total += float(row[intIdx][2])
I'm very green to python, coming from vb.net, so it may not make sense.
I have a list that has 4 elements per line with a comma delimiter. This block of code is supposed to run through each "row" and compare the 4th element with the parameter of the if statement, and to carry on whatever operation depending on the results.
I keep getting the 'int' object is not a subscriptable error, which I suspect that it might be more errors on top of this one.
I just need an explanation of what is going on and how I can improve the code so that my program can run properly.
I thank everyone for any input they can give me.
You are looping through a range. numLines is either the size of a list or the length of an input file. Honestly I did not quite get your idea, but I think that is what you are trying to do.
with open('Transactions.txt') as file:
for line in file:
rowarray = line.split(',')
if rowarray[3] != 'DEP':
check_total += float(rowarray[2])
else:
deposit_total += float(rowarray[2])
When you write
for i in range(nuList):
you are basically doing
for i in [1, 2, 3, ...., N]: # being N the size of your list
Therefor you are not looping through your data but rather through the range of indexes.
This line is your problem:
if row[intIdx](3) is not 'DEP':
You need to create an array from the row, currently it is just a string. Here is the code:
for row in range(numLines):
rowarray = row.split(',')
if rowarray[3] != 'DEP':
check_total += float(rowarray[2])
else:
deposit_total += float(rowarray[2])

Really weird python error

...
def splitMunipulation(p,threshold=5000):
runs=[];i=0
while i<len(p):
l=[];i+=1
print i,p[i]
while p[i]!=press(0,1,0):
l.append(p[i]);i+=1
else:
runs.append(l)#here i points to another (0,1,0)
return runs
...
record=splitMunipulation(record)
'''
Output:
1 <__main__.press instance at 0x046690A8>
File "H:\mutate.py", line 28, in splitMunipulation
while p[i]!=press(0,1,0):
IndexError: list index out of range
pressis a class
and since print p[i] works well,why p[i] is considered out of range?
Really don't get what's going on
'''
so, a few things..
Firstly, your code is very... unpythonic. This isn't C, so you don't need to use while loops for iteration, and don't use semicolons to separate multiple commands on one line in Python. Ever. Also, the while...else format is confusing and should be avoided.
If you look at the first few 'lines' of your while loop,
while i<len(p):
l=[];i+=1
You keep i below the length of p, but you immediately increase i's value by one. As such, when i=len(p) - 1, you will make i one larger, len(p). So when you try to access p[i], you are trying to access a value that doesn't exist.
Fixing those issues, you would get:
...
def splitMunipulation(p,threshold=5000):
runs=[]
for i in p:
l=[]
print i
if i != press(0,1,0):
runs.append(i)
return runs
...
record=splitMunipulation(record)
while p[i]!=press(0,1,0):
l.append(p[i]);i+=1
The variable i gets incremented in this loop until p[i]!=press(0,1,0). Since nothing is happening to make p longer, or to test that i is not greater than the length of p, it is easy to see how the index could get out of range.
len returns the length, not the last index. If l=[1,2,3], then len(l) returns 3, but l[3] is out of range.
so you should use
while i<len(p)-1
or better yet:
for i in range(len(p)):

Loop thru a list and stop when the first string is found

I have a list and I want to extract to another list the data that exist between top_row and bottom_row.
I know the top_row and also that the bottom_row corresponds to data[0] = last integer data (next row is made of strings, but there are also rows with integers which I'm not interested).
I've tried several things, but w/o success:
for row,data in enumerate(fileData):
if row > row_elements: #top_row
try:
n = int(data[0])
aux = True
except:
n = 0
while aux: #until it finds the bottom_row
elements.append(data)
The problem is that it never iterates the second row, if I replace while with if I get all rows which the first column is an integer.
fileData is like:
*Element, type=B31H
1, 1, 2
2, 2, 3
.
.
.
359, 374, 375
360, 375, 376
*Elset, elset=PART-1-1_LEDGER-1-LIN-1-2-RAD-2__PICKEDSET2, generate
I'm only interested in rows with first column values equal to 1 to 360.
Many thanks!
The code you've posted is confusing. For example, "aux" is a poorly-named variable. And the loop really wants to start with a specific element of the input, but it loops over everything until it finds the iteration it wants, turning what might be a constant-time operation into a linear one. Let's try rewriting it:
for record in fileData[row_elements:]: # skip first row_elements (might need +1?)
try:
int(record[0])
except ValueError:
break # found bottow_row, stop iterating
elements.append(record)
If no exception is thrown in the try part, then you basically end up with an endless loop, given that aux will always be True.
I’m not perfectly sure what you are doing in your code, given the way the data looks isn’t clear and some things are not used (like n?), but in general, you can stop a running loop (both for and while loops) with the break statement:
for row, data in enumerate(fileData):
if conditionToAbortTheLoop:
break
So in your case, I would guess something like this would work:
for row, data in enumerate(fileData):
if row > row_elements: # below `top_row`
try:
int(data[0])
except ValueError:
break # not an int value, `bottom_row` found
# if we get here, we’re between the top- and bottom row.
elements.append(data)
Will this work?
for row, data in enumerate(fileData):
if row > row_elements: #top_row
try:
n = int(data[0])
elements.append(data)
except ValueError:
continue
Or what about:
elements = [int(data[0]) for data in fileData if data[0].isdigit()]
By the way, if you care to follow the convention of most python code, you can rename fileData to file_data.
Use a generator:
def isInteger(testInput):
try:
int(testInput)
return True
except ValueError: return False
def integersOnly(fileData):
element = fileData.next()
while isInteger(element):
yield element
element = fileData.next()

Categories