Repository: pandas-dev/pandas
Pull request: TST: numpy RuntimeWarning with Series.round()
- [x] closes #14197
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ n/a] whatsnew entry


Problem statement:
BUG: numpy RuntimeWarning with Series.round()
Maybe needs wrapping in `numpy.errstate` (in pandas)?

``` python
>>> import pandas as pd
>>> pd.__version__
u'0.19.0rc1'
>>> pd.Series([pd.np.nan]).round()

Warning (from warnings module):
  File "C:\Program Files\Python27\lib\site-packages\pandas\core\series.py", line 1340
    result = _values_from_object(self).round(decimals)
RuntimeWarning: invalid value encountered in rint
0   NaN
dtype: float64
```

Same for `DataFrame.round()`.

Hints from issue discussion:
need to mask the values before rounding (iow not null ones)

I'll have a look and submit a PR

I can't seem to replicate the warning..

Running 2.7.12 and the latest dev version of pandas

hmm, maybe this is on an older version of numpy.

@xflr6 can you `pd.show_versions()` where you got that error

Sure:

``` python
>>> import pandas as pd
>>> pd.Series([pd.np.nan]).round()

Warning (from warnings module):
  File "C:\Program Files\Python27\lib\site-packages\pandas\core\series.py", line 1340
    result = _values_from_object(self).round(decimals)
RuntimeWarning: invalid value encountered in rint
0   NaN
dtype: float64
>>> pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.12.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: de_DE.cp1252

pandas: 0.19.0rc1
nose: 1.3.7
pip: 8.1.2
setuptools: 27.2.0
Cython: 0.24.1
numpy: 1.11.1
scipy: 0.18.0
statsmodels: 0.8.0rc1
xarray: None
IPython: 5.1.0
sphinx: 1.4.6
patsy: 0.4.1
dateutil: 2.5.3
pytz: 2016.6.1
blosc: None
bottleneck: 1.1.0
tables: None
numexpr: 2.6.1
matplotlib: 1.5.3
openpyxl: 2.4.0
xlrd: 1.0.0
xlwt: None
xlsxwriter: None
lxml: 3.6.4
bs4: 4.5.1
html5lib: 0.999999999
httplib2: 0.9.2
apiclient: None
sqlalchemy: 1.0.15
pymysql: None
psycopg2: 2.6.2 (dt dec pq3 ext lo64)
jinja2: 2.8
boto: None
pandas_datareader: None
```

In some environments, warnings are silenced, try this before:

``` python
>>> import warnings
>>> warnings.simplefilter('error')
```

Seems to be a Windows-specific upstream issue: numpy/numpy#7882

``` python
>>> import numpy as np
>>> np.ma.masked_invalid([np.nan]).round()

Warning (from warnings module):
  File "C:\Program Files\Python27\lib\site-packages\numpy\ma\core.py", line 5192
    result = self._data.round(decimals=decimals, out=out).view(type(self))
RuntimeWarning: invalid value encountered in rint
masked_array(data = [--],
             mask = [ True],
       fill_value = 1e+20)
```

``` python
>>> np.rint(np.nan)

Warning (from warnings module):
  File "__main__", line 2
RuntimeWarning: invalid value encountered in rint
nan
```

Correct me if I'm wrong, but doesn't Pandas usually ignore NA values in most calculations? So if you're trying to do some math, like rounding, what comes in as an NA would go out as an NA. Not sure why a warning is necessary here when it isn't necessary for multiplication, division, etc. 
but hats exactly the point; pandas needs a change to mask these values before sending to numpy; pull requests are welcome
I cannot reproduce this error at HEAD. is it still open?
Still open for me on Python 2, not on Python 3 though, see below.
```python
In [1]: import pandas as pd
In [2]: import warnings
   ...: warnings.simplefilter('error')
   ...: pd.Series([pd.np.nan]).round()

RuntimeWarningTraceback (most recent call last)
<ipython-input-2-0aec18ee80a1> in <module>()
      1 import warnings
      2 warnings.simplefilter('error')
----> 3 pd.Series([pd.np.nan]).round()

c:\programme\python27\lib\site-packages\pandas\core\series.pyc in round(self, decimals, *args, **kwargs)
   1826         """
   1827         nv.validate_round(args, kwargs)
-> 1828         result = com._values_from_object(self).round(decimals)
   1829         result = self._constructor(result, index=self.index).__finalize__(self)
   1830 

RuntimeWarning: invalid value encountered in rint

In [3]: pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 2.7.15.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.23.3
pytest: 3.6.3
pip: 10.0.1
setuptools: None
Cython: 0.28.4
numpy: 1.15.0rc1
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 5.7.0
sphinx: 1.7.5
patsy: None
dateutil: 2.7.3
pytz: 2018.5
blosc: None
bottleneck: 1.2.1
tables: None
numexpr: 2.6.5
feather: None
matplotlib: 2.2.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: 4.6.0
html5lib: 1.0.1
sqlalchemy: 1.2.9
pymysql: None
psycopg2: 2.7.5 (dt dec pq3 ext lo64)
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: 0.5.0
pandas_datareader: None
```

```python
In [1]: import pandas as pd
   ...: import warnings
   ...: warnings.simplefilter('error')
   ...: pd.Series([pd.np.nan]).round()
Out[1]: 
0   NaN
dtype: float64

In [2]: pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 3.7.0.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.23.3
pytest: 3.6.3
pip: 10.0.1
setuptools: None
Cython: 0.28.4
numpy: 1.15.0rc1
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 6.4.0
sphinx: 1.7.5
patsy: None
dateutil: 2.7.3
pytz: 2018.5
blosc: None
bottleneck: 1.2.1
tables: None
numexpr: 2.6.5
feather: None
matplotlib: 2.2.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: 1.0.1
sqlalchemy: None
pymysql: None
psycopg2: 2.7.5 (dt dec pq3 ext lo64)
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: 0.4.1
pandas_datareader: None
```

Commit message: add skipif PY2 and is_platform_windows

Patch to review:
diff --git a/pandas/tests/frame/test_analytics.py b/pandas/tests/frame/test_analytics.py
index 2e690ebbfa121..06b9179220a46 100644
--- a/pandas/tests/frame/test_analytics.py
+++ b/pandas/tests/frame/test_analytics.py
@@ -8,7 +8,7 @@
 import numpy as np
 import pytest
 
-from pandas.compat import PY35, lrange
+from pandas.compat import PY2, PY35, lrange, is_platform_windows
 import pandas.util._test_decorators as td
 
 import pandas as pd
@@ -1842,6 +1842,16 @@ def test_numpy_round(self):
         with pytest.raises(ValueError, match=msg):
             np.round(df, decimals=0, out=df)
 
+    @pytest.mark.skipif(
+        PY2 and is_platform_windows(), reason="numpy/numpy#7882")
+    def test_numpy_round_nan(self):
+        # See gh-14197
+        df = Series([1.53, np.nan, 0.06]).to_frame()
+        with np.errstate(invalid='raise'):
+            result = df.round()
+        expected = Series([2., np.nan, 0.]).to_frame()
+        tm.assert_frame_equal(result, expected)
+
     def test_round_mixed_type(self):
         # GH 11885
         df = DataFrame({'col1': [1.1, 2.2, 3.3, 4.4],
diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py
index 6811e370726b2..45560390be01e 100644
--- a/pandas/tests/series/test_analytics.py
+++ b/pandas/tests/series/test_analytics.py
@@ -9,7 +9,7 @@
 from numpy import nan
 import pytest
 
-from pandas.compat import PY35, lrange, range
+from pandas.compat import PY2, PY35, is_platform_windows, lrange, range
 import pandas.util._test_decorators as td
 
 import pandas as pd
@@ -285,6 +285,16 @@ def test_numpy_round(self):
         with pytest.raises(ValueError, match=msg):
             np.round(s, decimals=0, out=s)
 
+    @pytest.mark.skipif(
+        PY2 and is_platform_windows(), reason="numpy/numpy#7882")
+    def test_numpy_round_nan(self):
+        # See gh-14197
+        s = Series([1.53, np.nan, 0.06])
+        with np.errstate(invalid='raise'):
+            result = s.round()
+        expected = Series([2., np.nan, 0.])
+        assert_series_equal(result, expected)
+
     def test_built_in_round(self):
         if not compat.PY3:
             pytest.skip(


Code review comments:
diff_hunk: @@ -1842,6 +1842,16 @@ def test_numpy_round(self):
         with pytest.raises(ValueError, match=msg):
             np.round(df, decimals=0, out=df)
 
+    @pytest.mark.skipif(
+        PY2 and is_platform_windows(), reason="numpy/numpy#7882")
+    def test_numpy_round_nan(self):
+        # See gh-14197
+        df = Series([1.53, np.nan, 0.06]).to_frame()
+        with np.errstate(invalid='raise'):
path: pandas/tests/frame/test_analytics.py
text: @user1:
can u add assert_produces_warning() to these tests asserting that no warning happens

@author:
~~i don't think there is any value add. the RuntimeWarning issued by numpy seems to be only issued once and therefore is highly unlikely to be detected by a test unless run in isolation. hence the `with np.errstate(invalid='raise'):` context mangaer is used to convert the `RuntimeWarning: invalid value encountered in rint` to `FloatingPointError: invalid value encountered in rint`. Also `assert_produces_warning` is not thread-safe.~~

issues warning for both tests in py2 windows pytest environment. (i was not able to run pytest in my py2 environment.)

`np.errstate` now replaced with `assert_produces_warning`.