Repository: pandas-dev/pandas

Issue:
BUG: skipna parameter in series.any() returns wrong result

```
#importing pandas module 
import pandas as pd 

#importing numpy module
import numpy as np

data=pd.DataFrame({'A':[1,2,3,4,0,np.nan,3],
                  'B':[3,1,4,5,0,np.nan,5]})

data.any(axis=1,skipna=True)
```

Expected output:
0     True
1     True
2     True
3     True
4    False
5    True
6     True
dtype: bool


Returned output:

0     True
1     True
2     True
3     True
4    False
5    False
6     True
dtype: bool



As written in documentation,  If an entire row/column is NA, the result will be NA
But NA isn't returned in any of the cases (Keeping skipna True or False) 


Discussion:
> As written in documentation, If an entire row/column is NA, the result will be NA

I think the docs at https://github.com/pandas-dev/pandas/blob/12a0dc49ac63b63bcc5f93bccf71bce51c60bdad/pandas/core/generic.py#L9728-L9730 are incorrect. Skipna should be the same as the operation on the values with NAs removed (is that right @jorisvandenbossche?).
Isn't this a better way? ↓
If skipana is None which is default then it returns NA on whole NaN rows/column
If True/False then return True/False respectively for whole NA 

Because if the docs are incorrect then there is probably no way to return NA for Null values
min_count I thikn

On Fri, Oct 12, 2018 at 11:25 AM Kartikay Bhutani <notifications@github.com>
wrote:

> Isn't this a better way? ↓
> If skipana is None which is default then it returns NA on whole NaN
> rows/column
> If True/False then return True/False respectively for whole NA
>
> Because if the docs are incorrect then there is probably no way to return
> NA for Null values
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/pandas-dev/pandas/issues/23109#issuecomment-429382736>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ABQHIhLJLLq1TczRspP-JDekrFBh8mKiks5ukMJtgaJpZM4XZlWL>
> .
>

My opinion: I think the problem is the documentation; the result is actually correct.  If you ask if any of an empty set of statements is True, the answer is no.  This is consistent with `numpy`:

```
In [1]: import numpy as np

In [2]: np.any([])
Out[2]: False
```
> Skipna should be the same as the operation on the values with NAs removed (is that right @jorisvandenbossche?).

I suppose this as well. `any`/`all` can be seen as reductions like `sum` or `prod`, so we should probably follow their design.

So I think @dsaxton is right that it is only the documentation that is incorrect.
@jorisvandenbossche What would you say is the appropriate fix for this?  If the documentation is a general statement about the `skipna` parameter, maybe it makes sense to just remove the claim that the result will be NA (since it's not true for `any`, but presumably would be true in other contexts)?

Resolving patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -9894,11 +9894,11 @@ def _add_numeric_operations(cls):
         axis_descr, name, name2 = _doc_parms(cls)
 
         cls.any = _make_logical_function(
-            cls, 'any', name, name2, axis_descr,
-            _any_desc, nanops.nanany, _any_examples, _any_see_also)
+            cls, 'any', name, name2, axis_descr, _any_desc, nanops.nanany,
+            _any_examples, _any_see_also, empty_value=False)
         cls.all = _make_logical_function(
-            cls, 'all', name, name2, axis_descr, _all_doc,
-            nanops.nanall, _all_examples, _all_see_also)
+            cls, 'all', name, name2, axis_descr, _all_desc, nanops.nanall,
+            _all_examples, _all_see_also, empty_value=True)
 
         @Substitution(outname='mad',
                       desc="Return the mean absolute deviation of the values "
@@ -10219,12 +10219,14 @@ def _doc_parms(cls):
       original index.
     * None : reduce all axes, return a scalar.
 
-bool_only : boolean, default None
+bool_only : bool, default None
     Include only boolean columns. If None, will attempt to use everything,
     then use only boolean data. Not implemented for Series.
-skipna : boolean, default True
-    Exclude NA/null values. If an entire row/column is NA, the result
-    will be NA.
+skipna : bool, default True
+    Exclude NA/null values. If the entire row/column is NA and skipna is
+    True, then the result will be %(empty_value)s, as for an empty row/column.
+    If skipna is False, then NA are treated as True, because these are not
+    equal to zero.
 level : int or level name, default None
     If the axis is a MultiIndex (hierarchical), count along a
     particular level, collapsing into a %(name1)s.
@@ -10234,28 +10236,37 @@ def _doc_parms(cls):
 
 Returns
 -------
-%(outname)s : %(name1)s or %(name2)s (if level specified)
+%(name1)s or %(name2)s
+    If level is specified, then, %(name2)s is returned; otherwise, %(name1)s
+    is returned.
 
 %(see_also)s
 %(examples)s"""
 
-_all_doc = """\
+_all_desc = """\
 Return whether all elements are True, potentially over an axis.
 
-Returns True if all elements within a series or along a Dataframe
-axis are non-zero, not-empty or not-False."""
+Returns True unless there at least one element within a series or
+along a Dataframe axis that is False or equivalent (e.g. zero or
+empty)."""
 
 _all_examples = """\
 Examples
 --------
-Series
+**Series**
 
 >>> pd.Series([True, True]).all()
 True
 >>> pd.Series([True, False]).all()
 False
+>>> pd.Series([]).all()
+True
+>>> pd.Series([np.nan]).all()
+True
+>>> pd.Series([np.nan]).all(skipna=False)
+True
 
-DataFrames
+**DataFrames**
 
 Create a dataframe from a dictionary.
 
@@ -10597,10 +10608,11 @@ def _doc_parms(cls):
 """
 
 _any_desc = """\
-Return whether any element is True over requested axis.
+Return whether any element is True, potentially over an axis.
 
-Unlike :meth:`DataFrame.all`, this performs an *or* operation. If any of the
-values along the specified axis is True, this will return True."""
+Returns False unless there at least one element within a series or
+along a Dataframe axis that is True or equivalent (e.g. non-zero or
+non-empty)."""
 
 _any_examples = """\
 Examples
@@ -10610,8 +10622,16 @@ def _doc_parms(cls):
 For Series input, the output is a scalar indicating whether any element
 is True.
 
+>>> pd.Series([False, False]).any()
+False
 >>> pd.Series([True, False]).any()
 True
+>>> pd.Series([]).any()
+False
+>>> pd.Series([np.nan]).any()
+False
+>>> pd.Series([np.nan]).any(skipna=False)
+True
 
 **DataFrame**
 
@@ -10897,9 +10917,10 @@ def cum_func(self, axis=None, skipna=True, *args, **kwargs):
 
 
 def _make_logical_function(cls, name, name1, name2, axis_descr, desc, f,
-                           examples, see_also):
+                           examples, see_also, empty_value):
     @Substitution(outname=name, desc=desc, name1=name1, name2=name2,
-                  axis_descr=axis_descr, examples=examples, see_also=see_also)
+                  axis_descr=axis_descr, examples=examples, see_also=see_also,
+                  empty_value=empty_value)
     @Appender(_bool_doc)
     def logical_func(self, axis=0, bool_only=None, skipna=True, level=None,
                      **kwargs):


Test patch: