Repository: pandas-dev/pandas

Issue:
pd.to_numeric produces misleading results on DataFrame
when `pd.to_numeric` is called with `errors='coerce'` on a `DataFrame`, it doesn't raise and just returns the original `DataFrame`. 

This may be related to the discussion here https://github.com/pydata/pandas/issues/11221 as this function currently doesn't support anything more than 1-d. 

```
In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': [1, 2, 'foo'], 'b': [2.3, -1, 'bar']})

In [3]: df
Out[3]:
     a    b
0    1  2.3
1    2   -1
2  foo  bar

In [4]: pd.to_numeric(df)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-9febd95a7c0a> in <module>()
----> 1 pd.to_numeric(df)

/Users/mortada_mehyar/code/github/pandas/pandas/tools/util.py in to_numeric(arg, errors)
     94         conv = lib.maybe_convert_numeric(arg,
     95                                          set(),
---> 96                                          coerce_numeric=coerce_numeric)
     97     except:
     98         if errors == 'raise':

/Users/mortada_mehyar/code/github/pandas/pandas/src/inference.pyx in pandas.lib.maybe_convert_numeric (pandas/lib.c:52369)()
    518 cdef int64_t iINT64_MIN = <int64_t> INT64_MIN
    519
--> 520 def maybe_convert_numeric(object[:] values, set na_values,
    521                           bint convert_empty=True, bint coerce_numeric=False):
    522     '''

ValueError: Buffer has wrong number of dimensions (expected 1, got 2)

In [5]: pd.to_numeric(df, errors='coerce')
Out[5]:
     a    b
0    1  2.3
1    2   -1
2  foo  bar
```

Note that the last expression doesn't raise but the previous one does. 

Seems like we should either
1. make `pd.to_numeric` work with `DataFrame` or `NDFrame` in general 
2. simply raise here too if a `DataFrame` or something more than 1-d is passed



Discussion:
best to raise for non 1-d
(and check pd.to_datetime/to_timedelta) for the same

sounds good, I'll send a PR


Resolving patch:
diff --git a/pandas/tools/util.py b/pandas/tools/util.py
--- a/pandas/tools/util.py
+++ b/pandas/tools/util.py
@@ -56,7 +56,7 @@ def to_numeric(arg, errors='raise'):
 
     Parameters
     ----------
-    arg : list, tuple or array of objects, or Series
+    arg : list, tuple, 1-d array, or Series
     errors : {'ignore', 'raise', 'coerce'}, default 'raise'
         - If 'raise', then invalid parsing will raise an exception
         - If 'coerce', then invalid parsing will be set as NaN
@@ -84,6 +84,8 @@ def to_numeric(arg, errors='raise'):
         index, name = arg.index, arg.name
     elif isinstance(arg, (list, tuple)):
         arg = np.array(arg, dtype='O')
+    elif getattr(arg, 'ndim', 1) > 1:
+        raise TypeError('arg must be a list, tuple, 1-d array, or Series')
 
     conv = arg
     arg = com._ensure_object(arg)
diff --git a/pandas/tseries/timedeltas.py b/pandas/tseries/timedeltas.py
--- a/pandas/tseries/timedeltas.py
+++ b/pandas/tseries/timedeltas.py
@@ -19,7 +19,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise', coerce=None):
 
     Parameters
     ----------
-    arg : string, timedelta, array of strings (with possible NAs)
+    arg : string, timedelta, list, tuple, 1-d array, or Series
     unit : unit of the arg (D,h,m,s,ms,us,ns) denote the unit, which is an integer/float number
     box : boolean, default True
         - If True returns a Timedelta/TimedeltaIndex of the results
@@ -37,7 +37,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise', coerce=None):
 
     def _convert_listlike(arg, box, unit, name=None):
 
-        if isinstance(arg, (list,tuple)) or ((hasattr(arg,'__iter__') and not hasattr(arg,'dtype'))):
+        if isinstance(arg, (list, tuple)) or not hasattr(arg, 'dtype'):
             arg = np.array(list(arg), dtype='O')
 
         # these are shortcutable
@@ -62,8 +62,10 @@ def _convert_listlike(arg, box, unit, name=None):
         return Series(values, index=arg.index, name=arg.name, dtype='m8[ns]')
     elif isinstance(arg, ABCIndexClass):
         return _convert_listlike(arg, box=box, unit=unit, name=arg.name)
-    elif is_list_like(arg):
+    elif is_list_like(arg) and getattr(arg, 'ndim', 1) == 1:
         return _convert_listlike(arg, box=box, unit=unit)
+    elif getattr(arg, 'ndim', 1) > 1:
+        raise TypeError('arg must be a string, timedelta, list, tuple, 1-d array, or Series')
 
     # ...so it must be a scalar value. Return scalar.
     return _coerce_scalar_to_timedelta_type(arg, unit=unit, box=box, errors=errors)
diff --git a/pandas/tseries/tools.py b/pandas/tseries/tools.py
--- a/pandas/tseries/tools.py
+++ b/pandas/tseries/tools.py
@@ -188,7 +188,7 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False,
 
     Parameters
     ----------
-    arg : string, datetime, array of strings (with possible NAs)
+    arg : string, datetime, list, tuple, 1-d array, or Series
     errors : {'ignore', 'raise', 'coerce'}, default 'raise'
         - If 'raise', then invalid parsing will raise an exception
         - If 'coerce', then invalid parsing will be set as NaT
@@ -288,7 +288,7 @@ def _to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False,
 
     def _convert_listlike(arg, box, format, name=None):
 
-        if isinstance(arg, (list,tuple)):
+        if isinstance(arg, (list, tuple)):
             arg = np.array(arg, dtype='O')
 
         # these are shortcutable
@@ -312,8 +312,9 @@ def _convert_listlike(arg, box, format, name=None):
             result = arg.astype('datetime64[ns]')
             if box:
                 return DatetimeIndex(result, tz='utc' if utc else None, name=name)
-
             return result
+        elif getattr(arg, 'ndim', 1) > 1:
+            raise TypeError('arg must be a string, datetime, list, tuple, 1-d array, or Series')
 
         arg = com._ensure_object(arg)
         require_iso8601 = False


Test patch:
diff --git a/pandas/tools/tests/test_util.py b/pandas/tools/tests/test_util.py
--- a/pandas/tools/tests/test_util.py
+++ b/pandas/tools/tests/test_util.py
@@ -113,7 +113,6 @@ def test_error(self):
         expected = pd.Series([1, -3.14, np.nan])
         tm.assert_series_equal(res, expected)
 
-
     def test_list(self):
         s = ['1', '-3.14', '7']
         res = to_numeric(s)
@@ -136,6 +135,14 @@ def test_all_nan(self):
         expected = pd.Series([np.nan, np.nan, np.nan])
         tm.assert_series_equal(res, expected)
 
+    def test_type_check(self):
+        # GH 11776
+        df = pd.DataFrame({'a': [1, -3.14, 7], 'b': ['4', '5', '6']})
+        with tm.assertRaisesRegexp(TypeError, "1-d array"):
+            to_numeric(df)
+        for errors in ['ignore', 'raise', 'coerce']:
+            with tm.assertRaisesRegexp(TypeError, "1-d array"):
+                to_numeric(df, errors=errors)
 
 if __name__ == '__main__':
     nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py
--- a/pandas/tseries/tests/test_period.py
+++ b/pandas/tseries/tests/test_period.py
@@ -2984,6 +2984,16 @@ def test_to_datetime_1703(self):
         result = index.to_datetime()
         self.assertEqual(result[0], Timestamp('1/1/2012'))
 
+    def test_to_datetime_dimensions(self):
+        # GH 11776
+        df = DataFrame({'a': ['1/1/2012', '1/2/2012'],
+                        'b': ['12/30/2012', '12/31/2012']})
+        with tm.assertRaisesRegexp(TypeError, "1-d array"):
+            to_datetime(df)
+        for errors in ['ignore', 'raise', 'coerce']:
+            with tm.assertRaisesRegexp(TypeError, "1-d array"):
+                to_datetime(df, errors=errors)
+
     def test_get_loc_msg(self):
         idx = period_range('2000-1-1', freq='A', periods=10)
         bad_period = Period('2012', 'A')
diff --git a/pandas/tseries/tests/test_timedeltas.py b/pandas/tseries/tests/test_timedeltas.py
--- a/pandas/tseries/tests/test_timedeltas.py
+++ b/pandas/tseries/tests/test_timedeltas.py
@@ -444,26 +444,36 @@ def check(value):
 
     def test_timedelta_range(self):
 
-        expected = to_timedelta(np.arange(5),unit='D')
-        result = timedelta_range('0 days',periods=5,freq='D')
+        expected = to_timedelta(np.arange(5), unit='D')
+        result = timedelta_range('0 days', periods=5, freq='D')
         tm.assert_index_equal(result, expected)
 
-        expected = to_timedelta(np.arange(11),unit='D')
-        result = timedelta_range('0 days','10 days',freq='D')
+        expected = to_timedelta(np.arange(11), unit='D')
+        result = timedelta_range('0 days', '10 days', freq='D')
         tm.assert_index_equal(result, expected)
 
-        expected = to_timedelta(np.arange(5),unit='D') + Second(2) + Day()
-        result = timedelta_range('1 days, 00:00:02','5 days, 00:00:02',freq='D')
+        expected = to_timedelta(np.arange(5), unit='D') + Second(2) + Day()
+        result = timedelta_range('1 days, 00:00:02', '5 days, 00:00:02', freq='D')
         tm.assert_index_equal(result, expected)
 
-        expected = to_timedelta([1,3,5,7,9],unit='D') + Second(2)
-        result = timedelta_range('1 days, 00:00:02',periods=5,freq='2D')
+        expected = to_timedelta([1,3,5,7,9], unit='D') + Second(2)
+        result = timedelta_range('1 days, 00:00:02', periods=5, freq='2D')
         tm.assert_index_equal(result, expected)
 
-        expected = to_timedelta(np.arange(50),unit='T')*30
-        result = timedelta_range('0 days',freq='30T',periods=50)
+        expected = to_timedelta(np.arange(50), unit='T') * 30
+        result = timedelta_range('0 days', freq='30T', periods=50)
         tm.assert_index_equal(result, expected)
 
+        # GH 11776
+        arr = np.arange(10).reshape(2, 5)
+        df = pd.DataFrame(np.arange(10).reshape(2, 5))
+        for arg in (arr, df):
+            with tm.assertRaisesRegexp(TypeError, "1-d array"):
+                to_timedelta(arg)
+            for errors in ['ignore', 'raise', 'coerce']:
+                with tm.assertRaisesRegexp(TypeError, "1-d array"):
+                    to_timedelta(arg, errors=errors)
+
         # issue10583
         df = pd.DataFrame(np.random.normal(size=(10,4)))
         df.index = pd.timedelta_range(start='0s', periods=10, freq='s')