<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 4, 2017 at 12:11 PM, Jeff Reback <span dir="ltr"><<a href="mailto:jeffreback@gmail.com" target="_blank">jeffreback@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><span class="gmail-"><span style="font-size:12.8px">> We have been discussing this amongst the pandas core developers for</span><br style="font-size:12.8px"><span style="font-size:12.8px">some time, and the general consensus is to adopt Option 1 (sum of</span><br style="font-size:12.8px"><span style="font-size:12.8px">all-NA or empty is 0) as the behavior for sum with skipna=True.</span><br style="font-size:12.8px"><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">Actually, no there has not been general consensus among the core developers.</span></div></div></blockquote><div><br></div><div>I think that's the preference of the majority though.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><span style="font-size:12.8px">Everyone loves to say that</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">s.sum([NA]) == 0</font> makes a ton of sense, but then you have my simple example</span></div><div><span style="font-size:12.8px">from original issue, which Nathaniel did quote and I'll repeat here (with a small modification):</span></div><div><span style="font-size:12.8px"><br></span></div><div><div><span style="font-size:12.8px"><font face="monospace, monospace">In [2]: df = DataFrame({'A' : [np.nan, np.nan], 'B' : [np.nan, 0]})</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace"><br></font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">In [3]: df</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">Out[3]: </font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">    A    B</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">0 NaN  NaN</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">1 NaN  0.0</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace"><br></font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">In [4]: df.sum()</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">Out[4]: </font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">A    NaN</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">B    0.0</font></span></div><div><span style="font-size:12.8px"><font face="monospace, monospace">dtype: float64</font></span></div><div style="font-size:12.8px"><font face="monospace, monospace"><br></font></div></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">Option 1 is de-facto making [4] have A AND B == 0.0. This loses the fact that you have 0</span></div><div><span style="font-size:12.8px">present in B. If you conflate these, you then have a situation where I do not</span></div><div><span style="font-size:12.8px">know that I had a valid value in B.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">Option 2 (and 3) for that matter preserves [4]. This DOES NOT lose</span></div><div><span style="font-size:12.8px">information. No argument has been presented at all why this should not hold.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">From [4] it follows that sum([NA]) must be NA.</span></div></div></blockquote><div><br></div><div>Extending that slightly:<br><br><span style="font-family:monospace,monospace"><br>In [4]: df = DataFrame({'A' : [np.nan, np.nan], 'B' : [np.nan, 0], 'C': [0, 0]})<br><br>In [5]: df.sum()<br>Out[5]:<br>A    NaN<br>B    0.0<br>C    0.0<br>dtype: float64<br></span><br></div><div>This is why I don't think the "preserving information" argument is correct. Taking "Preserving information"<br></div><div>to its logical conclusion would return NaN for "B", since that distinguishes between the sum of all<br></div><div>valid and the the sum with some NaNs.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><span style="font-size:12.8px">I am indifferent whether sum([]) == 0 or NA. Though I would argue that NA is more consistent with</span></div><div><span style="font-size:12.8px">the rest of pandas (IOW *every* other operation on an empty Series returns NA).</span></div><span class="gmail-"><div><br></div><div><span style="font-size:12.8px">> * We should prepare a 0.21.1 release in short order with Option 1</span><br style="font-size:12.8px"><span style="font-size:12.8px">implemented for sum() (always 0 for empty/all-null) and prod() (1,</span><br style="font-size:12.8px"><span style="font-size:12.8px">respectively)</span><br style="font-size:12.8px"></div><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">I can certainly understand pandas reverting back to the de-facto state of affairs prior</span></div><div><span style="font-size:12.8px">to 0.21.0, which would be option 3, but a radical change on a minor release is</span></div><div><span style="font-size:12.8px">not warranted at all. Frankly, we only have (and are likely to get) even a small</span></div><div><span style="font-size:12.8px">fraction of users opinions on this whole matter.</span></div></div></blockquote><div><br></div><div>Yeah, agreed that bumping to 0.22 is for the best.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><span class="gmail-HOEnZb"><font color="#888888"><div><span style="font-size:12.8px">Jeff</span></div></font></span><div><div class="gmail-h5"><div><span style="font-size:12.8px"><br></span></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 4, 2017 at 11:05 AM, Wes McKinney <span dir="ltr"><<a href="mailto:wesmckinn@gmail.com" target="_blank">wesmckinn@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">We have been discussing this amongst the pandas core developers for<br>
some time, and the general consensus is to adopt Option 1 (sum of<br>
all-NA or empty is 0) as the behavior for sum with skipna=True.<br>
<br>
In a groupby setting, and with categorical group keys, the issue<br>
becomes a bit more nuanced -- if you group by a categorical, and one<br>
of the categories is not observed at all in the dataset, e.g:<br>
<br>
s.groupby(some_categorical).su<wbr>m()<br>
<br>
This change will necessarily yield a Series containing no nulls -- so<br>
if there is a category containing no data, then the sum for that<br>
category is 0.<br>
<br>
For the sake of algebraic completeness, I believe we should introduce<br>
a new aggregation method that performs Option 2 (equivalent to what<br>
pandas 0.21.0 is currently doing for sum()), so that empty or all-NA<br>
yields NA.<br>
<br>
So the TL;DR is:<br>
<br>
* We should prepare a 0.21.1 release in short order with Option 1<br>
implemented for sum() (always 0 for empty/all-null) and prod() (1,<br>
respectively)<br>
* Add a new method for Option 2, either in 0.21.1 or in a later release<br>
<br>
We should probably alert the long GitHub thread that this discussion<br>
is taking place before we cut the release. Since GitHub comments can<br>
be permanently deleted at any time, I think it's better for<br>
discussions about significant issues like this to take place on the<br>
permanent public record.<br>
<br>
Thanks<br>
<span class="gmail-m_-6764551032968972804gmail-HOEnZb"><font color="#888888">Wes<br>
</font></span><div class="gmail-m_-6764551032968972804gmail-HOEnZb"><div class="gmail-m_-6764551032968972804gmail-h5"><br>
On Sun, Dec 3, 2017 at 11:17 AM, Pietro Battiston <<a href="mailto:ml@pietrobattiston.it" target="_blank">ml@pietrobattiston.it</a>> wrote:<br>
> Il giorno sab, 02/12/2017 alle 17.32 -0800, Nathaniel Smith ha scritto:<br>
>> [...]<br>
><br>
> I think Nathaniel just expressed my thoughts better than I was/would be<br>
> able to!<br>
><br>
> Pietro<br>
> ______________________________<wbr>_________________<br>
> Pandas-dev mailing list<br>
> <a href="mailto:Pandas-dev@python.org" target="_blank">Pandas-dev@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/pandas-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/pandas-dev</a><br>
______________________________<wbr>_________________<br>
Pandas-dev mailing list<br>
<a href="mailto:Pandas-dev@python.org" target="_blank">Pandas-dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/pandas-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/pandas-dev</a><br>
</div></div></blockquote></div><br></div></div></div></div>
<br>______________________________<wbr>_________________<br>
Pandas-dev mailing list<br>
<a href="mailto:Pandas-dev@python.org">Pandas-dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/pandas-dev" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/pandas-dev</a><br>
<br></blockquote></div><br></div></div>