0

I ran into an error using Python's List comprehension today that I was not expecting. I checked this post:

TypeError: 'int' object is not iterable, why it's happening

which simply explains basically what the error is. My question is a bit more specific though. Why does the 'np.percentile' functions work, but not 'max' and 'min' NOTE: binnedMetric is a dictionary of nested lists, i.e., binnedMetric['key'][num1-numBins][listContainingItemsWithinBin]. I am taking statistics on all the items in each bin. Here is the snippit from my code that works:

     tempAvgMetric = [[] for dmx in range(numBins)]
     for idx in range(len(binnedMetric[expDir])):
        for xxx in range(numBins):
           tempAvgMetric[xxx].extend(binnedMetric[expDir][idx][nameNum][xxx])
     for idx in range(numBins):
        if np.isnan(avgMetric[idx]):
            tempAvgMetric[idx] = 0

     percentile50 = np.array([np.percentile(tempAvgMetric[dmx], 50) for dmx in range(numBins) if tempAvgMetric])
     percentile75 = np.array([np.percentile(tempAvgMetric[dmx], 75) for dmx in range(numBins) if tempAvgMetric])
     percentile25 = np.array([np.percentile(tempAvgMetric[dmx], 25) for dmx in range(numBins) if tempAvgMetric])
     maximum =      np.array([np.amax(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])
     minimum =      np.array([np.amin(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])

Converting 'nan' to zeros appears to be necessary to get the percentile function to work properly. I also tried using Python's 'min' and 'max' functions as follows:

 maximum =      np.array([max(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])
 minimum =      np.array([min(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])

I find it peculiar because I am not iterating over the min function, I am iterating over 'dmx', which is defined as an iterable in the list comprehension. I wouldn't think that the function call would affect anything. As shown above in the "np.percentile" list comprehensions, the loop is almost identical. Any clues as to why this behavior exists would be greatly appreciated. Thank you!

**UPDATE: Here is a functioning code. It works, with no "int object is not iterable" error.

import numpy as np
a = [[1,2,3],[1],[], [4,7,6,8,10],[13,12,0.2]]
b = [[1,4,2],[1,6,7],[6,5,3],[1,4,3],[13,11,1]]
c = [[1,2,3], [1,4,6], [1,4,6], [1], []]
d = [[2],[4],[6],[8],[10]] 
binnedMetric = {'tempKey': [[a,b], [c,d]]}
expDir = 'tempKey'
numBins = 5
nameNum = 0

tempAvgMetric = [[] for dmx in range(numBins)]
for idx in range(len(binnedMetric[expDir])):
    for xxx in range(numBins):
       tempAvgMetric[xxx].extend(binnedMetric[expDir][idx][nameNum][xxx])

avgMetric = np.array([np.mean(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])
varMetric = np.array([np.sqrt(np.var(tempAvgMetric[dmx])) for dmx in range(numBins) if tempAvgMetric])
for idx in range(numBins):
    if np.isnan(avgMetric[idx]):
        tempAvgMetric[idx] = 0

percentile50 = np.array([np.percentile(tempAvgMetric[dmx], 50) for dmx in range(numBins) if tempAvgMetric])
percentile75 = np.array([np.percentile(tempAvgMetric[dmx], 75) for dmx in range(numBins) if tempAvgMetric])
percentile25 = np.array([np.percentile(tempAvgMetric[dmx], 25) for dmx in range(numBins) if tempAvgMetric])
maximum =      np.array([np.amax(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])
minimum =      np.array([np.amin(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])

maximum2 =     np.array([max(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])
minimum2 =     np.array([min(tempAvgMetric[dmx]) for dmx in range(numBins) if tempAvgMetric])

print(percentile50)
print(maximum)
print(maximum2)

simply changing the values of 'a' to

a = [[np.nan, np.nan],[1],[], [4,7,6,8,10],[13,12,0.2]] 

breaks the code, but only for 'maximum2', giving the same error that I was running into.

  • got some sample data and expected results? you shouldn't need loops or list comprehensions with numpy – Paul H Jun 29 '17 at 16:47
  • Sorry, I had to edit a few things. My code with amax and amin started throwing errors, and I'm not sure why either. I will update the above post with a dummy list for binnedMetric so that it will run – Brian Burrows Jun 29 '17 at 16:51

2 Answers2

0

The reason is that some of the elements of your tempAvgMetric list are not lists but rather integers. Initially you construct tempAvgMetric as a nested list of empty lists. However, later, in the second major loop, you replace some lists with integers (0):

for idx in range(numBins):
    if np.isnan(avgMetric[idx]):    
        tempAvgMetric[idx] = 0
AGN Gazer
  • 8,025
  • 2
  • 27
  • 45
0

At some point your code is trying to apply max to an integer, as opposed to a list or other iterable

To illustrate:

In [354]: max(123)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-354-8de2de84b04d> in <module>()
----> 1 max(123)

TypeError: 'int' object is not iterable
In [355]: np.max(123)
Out[355]: 123
In [356]: np.max(np.array(123))
Out[356]: 123

np.max works because it first turns the argument into an array.

 tempAvgMetric = [[] for dmx in range(numBins)]
 ....
       tempAvgMetric[xxx].extend(binnedMetric[expDir][idx][nameNum][xxx])
 ....
        tempAvgMetric[idx] = 0

With this code, some tempAvgMetric elements will be lists (they all start as []), but for the idx case they are the integer 0.

Changing that assignment to:

tempAvgMetric[idx] = [0]

In [357]: max([0])
Out[357]: 0

Be aware that max([]) and np.max([]) both produce an error.


if tempAvgMetric

test doesn't make much sense. When would this be False? Only if the list was empty, i.e. if numBins==0.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Thank you. It seems like everyone figured it out but me. Works like a charm, and your comment about "if tempAvgMetric" was spot on. I was wondering why that check wasn't skipping empty lists within tempAvgMetric, but the line should have been: "if tempAvgMetric[dmx]", that way it would avoid the max([]) errors that you mention. – Brian Burrows Jun 30 '17 at 15:51