<div dir="ltr"><div><div><div><div><div>While atleast_1d/2d/3d predates my involvement in numpy, I am probably partly to blame for popularizing them as I helped to fix them up a fair amount. I wouldn't call its use "guessing". Rather, I would treat them as useful input sanitizers. If your function is going to be doing 2d indexing on an input, then it is very convenient to have atleast_2d() at the top of your function, not only to sanitize the input, but to make it clear that your code expects at least two dimensions.<br><br></div>One place where it is used is in np.loadtxt(..., ndmin=N) to protect against the situation of a single row of data becoming a 1-D array rather than a 2-D array (or an empty text file returning something completely useless).<br><br></div>I have previously pointed out the oddity with atleast_3d(). I can't remember the explanation I got though. Maybe someone can find the old thread that has the explanation, if any?<br><br></div>I think the keyword argument approach for controlling the behavior might be a good approach, provided that a suitable design could be devised. 1 & 2 dimensions is fairly trivial to control, but 3+ dimensions has too many degrees of freedom for me to consider.<br><br></div>Cheers!<br></div>Ben Root<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 6, 2016 at 9:12 AM, Joseph Fox-Rabinovitz <span dir="ltr"><<a href="mailto:jfoxrabinovitz@gmail.com" target="_blank">jfoxrabinovitz@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I can add a keyword-only argument that lets you put the new dims<br>
before or after the existing ones. I am not sure how to specify<br>
arbitrary patterns for the new dimensions, but that should take care<br>
of most use cases.<br>
<br>
The use case that motivated this function in the first place is that I<br>
am doing some processing on 4D arrays and I need to reduce them but<br>
return a result with the original dimensionality (but not shape).<br>
atleast_nd seemed like a better solution than atleast_4d.<br>
<br>
-Joe<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On Wed, Jul 6, 2016 at 3:41 AM, <<a href="mailto:josef.pktd@gmail.com">josef.pktd@gmail.com</a>> wrote:<br>
><br>
><br>
> On Wed, Jul 6, 2016 at 3:29 AM, <<a href="mailto:josef.pktd@gmail.com">josef.pktd@gmail.com</a>> wrote:<br>
>><br>
>><br>
>><br>
>> On Wed, Jul 6, 2016 at 2:21 AM, Ralf Gommers <<a href="mailto:ralf.gommers@gmail.com">ralf.gommers@gmail.com</a>><br>
>> wrote:<br>
>>><br>
>>><br>
>>><br>
>>> On Wed, Jul 6, 2016 at 7:06 AM, Nathaniel Smith <<a href="mailto:njs@pobox.com">njs@pobox.com</a>> wrote:<br>
>>><br>
>>>> On Jul 5, 2016 9:09 PM, "Joseph Fox-Rabinovitz"<br>
>>>> <<a href="mailto:jfoxrabinovitz@gmail.com">jfoxrabinovitz@gmail.com</a>> wrote:<br>
>>>> ><br>
>>>> > Hi,<br>
>>>> ><br>
>>>> > I have generalized np.atleast_1d, np.atleast_2d, np.atleast_3d with a<br>
>>>> > function np.atleast_nd in PR#7804<br>
>>>> > (<a href="https://github.com/numpy/numpy/pull/7804" rel="noreferrer" target="_blank">https://github.com/numpy/numpy/pull/7804</a>).<br>
>>>> ><br>
>>>> > As a result of this PR, I have a couple of questions about<br>
>>>> > `np.atleast_3d`. `np.atleast_3d` appears to do something weird with<br>
>>>> > the dimensions: If the input is 1D, it prepends and appends a size-1<br>
>>>> > dimension. If the input is 2D, it appends a size-1 dimension. This is<br>
>>>> > inconsistent with `np.atleast_2d`, which always prepends (as does<br>
>>>> > `np.atleast_nd`).<br>
>>>> ><br>
>>>> > - Is there any reason for this behavior?<br>
>>>> > - Can it be cleaned up (e.g., by reimplementing `np.atleast_3d` in<br>
>>>> > terms of `np.atleast_nd`, which is actually much simpler)? This would<br>
>>>> > be a slight API change since the output would not be exactly the same.<br>
>>>><br>
>>>> Changing atleast_3d seems likely to break a bunch of stuff...<br>
>>>><br>
>>>> Beyond that, I find it hard to have an opinion about the best design for<br>
>>>> these functions, because I don't think I've ever encountered a situation<br>
>>>> where they were actually what I wanted. I'm not a big fan of coercing<br>
>>>> dimensions in the first place, for the usual "refuse to guess" reasons. And<br>
>>>> then generally if I do want to coerce an array to another dimension, then I<br>
>>>> have some opinion about where the new dimensions should go, and/or I have<br>
>>>> some opinion about the minimum acceptable starting dimension, and/or I have<br>
>>>> a maximum dimension in mind. (E.g. "coerce 1d inputs into a column matrix;<br>
>>>> 0d or 3d inputs are an error" -- atleast_2d is zero-for-three on that<br>
>>>> requirements list.)<br>
>>>><br>
>>>> I don't know how typical I am in this. But it does make me wonder if the<br>
>>>> atleast_* functions act as an attractive nuisance, where new users take<br>
>>>> their presence as an implicit recommendation that they are actually a useful<br>
>>>> thing to reach for, even though they... aren't that. And maybe we should be<br>
>>>> recommending folk move away from them rather than trying to extend them<br>
>>>> further?<br>
>>>><br>
>>>> Or maybe they're totally useful and I'm just missing it. What's your use<br>
>>>> case that motivates atleast_nd?<br>
>>><br>
>>> I think you're just missing it:) atleast_1d/2d are used quite a bit in<br>
>>> Scipy and Statsmodels (those are the only ones I checked), and in the large<br>
>>> majority of cases it's the best thing to use there. There's a bunch of<br>
>>> atleast_2d calls with a transpose appended because the input needs to be<br>
>>> treated as columns instead of rows, but that's still efficient and readable<br>
>>> enough.<br>
>><br>
>><br>
>><br>
>> As Ralph pointed out its usage in statsmodels. I do find them useful as<br>
>> replacement for several lines of ifs and reshapes<br>
>><br>
>> We stilll need in many cases the atleast_2d_cols, that appends the newaxis<br>
>> if necessary.<br>
>><br>
>> roughly the equivalent of<br>
>><br>
>> if x.ndim == 1:<br>
>> x = x[:, None]<br>
>> else:<br>
>> x = np.atleast_2d(x)<br>
>><br>
>> Josef<br>
>><br>
>>><br>
>>><br>
>>> For 3D/nD I can see that you'd need more control over where the<br>
>>> dimensions go, but 1D/2D are fine.<br>
><br>
><br>
><br>
> statsmodels has currently very little code with ndim >2, so I have no<br>
> overview of possible use cases, but it would be necessary to have full<br>
> control over the added axis since axis have a strict meaning and stats still<br>
> prefer Fortran order to default numpy/C ordering.<br>
><br>
> Josef<br>
><br>
><br>
>>><br>
>>><br>
>>><br>
>>> Ralf<br>
>>><br>
>>><br>
>>> _______________________________________________<br>
>>> NumPy-Discussion mailing list<br>
>>> <a href="mailto:NumPy-Discussion@scipy.org">NumPy-Discussion@scipy.org</a><br>
>>> <a href="https://mail.scipy.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.scipy.org/mailman/listinfo/numpy-discussion</a><br>
>>><br>
>><br>
><br>
><br>
> _______________________________________________<br>
> NumPy-Discussion mailing list<br>
> <a href="mailto:NumPy-Discussion@scipy.org">NumPy-Discussion@scipy.org</a><br>
> <a href="https://mail.scipy.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.scipy.org/mailman/listinfo/numpy-discussion</a><br>
><br>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@scipy.org">NumPy-Discussion@scipy.org</a><br>
<a href="https://mail.scipy.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.scipy.org/mailman/listinfo/numpy-discussion</a><br>
</div></div></blockquote></div><br></div>