[Numpy-discussion] Counting array elements

Peter Verveer verveer at embl-heidelberg.de
Tue Oct 26 11:20:02 CDT 2004


On Oct 26, 2004, at 6:19 PM, Chris Barker wrote:

> Peter Verveer wrote:
>> It seems to me that the behavior one would expect for a function like 
>> that, would be to apply the operation to the whole array. Not along 
>> an axis. What would you expect as a new user if you call a minimum() 
>> function?  A single value that is the minimum. So that is the logical 
>> choice for the default behavior, I would think.
>
> nope. I'd expect it to be along an axis, by default the last one.

I still do not agree completely with that, I will elaborate more below, 
because I also do not agree anymore with my own earlier writings :-).

But I see your point that this type of operation can be natural 
depending on what you are doing. Sometimes a single value does make 
sense, sometimes not, I think we can agree on that.

>> Yes, that would be the idea anyway. The question is what should be 
>> the default behavior for this type of functions, something I think we 
>> should not decide based on the current behavior of a single existing 
>> function, but based on what makes the most sense. That is obviously 
>> something that can be discussed...
>
> yup, but frankly, this isn't about just one function, it's really 
> about all the reductions: min, max, sum, etc, etc.

Actually no. It seems that sum() is a special case, along with a few 
others. Again: I elaborate on the general case below.

> I think the rule of thumb is not to break backward compatibility 
> unless there is a compelling reason, and given that it's not clear 
> what is most "natural" in this case, keeping the default the same 
> makes the most sense.

I agree. In contrast what I have said before I think we should keep it 
as it is, for compatibility.

Now to elaborate on the general problem, please correct me if I get 
something wrong. I will use the minimum function as an example and come 
back to sum() later.

If you look at a minimum operation then there are three different 
things you might like to do:

1) An element by element minimum: minimum(a1, a2). This is the current 
behaviour. Like all binary ufuncs of this type, it operates on pairs of 
arrays. So by default it does not do reduction or calculate a single 
minimum. For most ufuncs that is the natural behavior anyway.

2) A reduction: minimum.reduce(a1). The reduce method of ufuncs is 
generally used for reductions. Having to use .reduce makes clear what 
you are doing. Although a bit odd at first sight, I think it is a 
clever way to overload ufuncs names with different functionality.

3) The minimum of the array:  In numarray you do a1.min(). I think in 
Numeric, you have to do something like minimum.reduce(a1.flat), correct 
me if I am wrong. Not nice in both cases...

Note that calling a binary ufunc with a single argument will give an 
error: minimum(a1) raises a TypeError. That seems to be a good 
decision, because people seem to have different ideas of what should 
happen: I would expect the minimum of the array, others expect a 
reduction. Generally I guess it was a wise decision not to change the 
meaning of a function depending on wether it has one or two arguments.

The sum() function is an alias to add.reduce. there are a few more of 
these aliases (i.e. product). I would still say that it is a bit 
unfortunate, since not everybody may immediately realize that these 
functions are in fact reductions.

I wonder if one would not be better of without these functions at all, 
after all you can access the functionality through .reduce(). If you 
mind the extra typing, just define your own alias. Can't we shift them 
into numarray.numeric? Just a thought...

In any case, clearly these functions need to stay around as they are 
for compatibility reasons. It is far more productive to add the 
functionality that a few people already proposed: allow reductions over 
multiple axes. I would welcome that, I always found 1D reductions a bit 
limited anyway. Obviously you can do sequential 1D reductions, but that 
can be quite inefficient. As proposed, the axis argument would take 
maybe a list of dimensions, and 'all' or None. I would like to propose 
an additional possibility: like minimum.reduce(), we could have a 
minimum.all() function that reduces over all dimensions (with a 
potentially much more efficient implementation.) We don't need a 
sum_all(a1) then, you would use add.all(a1). I guess this would be 
easily prototyped using sequential reductions, one can worry  about 
efficiency later.

Sorry for the long story...

Cheers, Peter





More information about the Numpy-discussion mailing list