diff --git a/pandas/core/common.py b/pandas/core/common.py index dc2ee31bbaf3d..a8d61d7ec0297 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -473,7 +473,7 @@ def _infer_dtype_from_scalar(val): dtype = np.dtype('M8[ns]') elif isinstance(val, (np.timedelta64, timedelta)): - val = tslib.convert_to_timedelta(val, 'ns') + val = lib.Timedelta(val).value dtype = np.dtype('m8[ns]') elif is_bool(val): @@ -826,6 +826,7 @@ def trans(x): # noqa def _maybe_convert_string_to_object(values): """ + Convert string-like and string-like array to convert object dtype. This is to avoid numpy to handle the array as str dtype. """ @@ -837,6 +838,20 @@ def _maybe_convert_string_to_object(values): return values +def _maybe_convert_scalar(values): + """ + Convert a scalar scalar to the appropriate dtype + This avoids numpy directly converting according to platform preferences + """ + if lib.isscalar(values): + dtype, values = _infer_dtype_from_scalar(values) + try: + values = dtype(values) + except TypeError: + pass + return values + + def _lcd_dtypes(a_dtype, b_dtype): """ return the lcd dtype to hold these types """ diff --git a/pandas/core/internals.py b/pandas/core/internals.py index c21e78f547988..463a2da529b5d 100644 --- a/pandas/core/internals.py +++ b/pandas/core/internals.py @@ -18,6 +18,7 @@ is_datetime64_dtype, is_datetimetz, is_sparse, array_equivalent, _is_na_compat, _maybe_convert_string_to_object, + _maybe_convert_scalar, is_categorical, is_datetimelike_v_numeric, is_numeric_v_string_like, is_internal_type) import pandas.core.algorithms as algos @@ -1201,6 +1202,7 @@ def where(self, other, cond, align=True, raise_on_error=True, "like") other = _maybe_convert_string_to_object(other) + other = _maybe_convert_scalar(other) # our where function def func(cond, values, other): diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index c77d71be7c9c9..905816081f0c5 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -770,6 +770,36 @@ def test_maybe_convert_string_to_array(self): tm.assert_numpy_array_equal(result, np.array(['x', 2], dtype=object)) self.assertTrue(result.dtype == object) + def test_maybe_convert_scalar(self): + + # pass thru + result = com._maybe_convert_scalar('x') + self.assertEqual(result, 'x') + result = com._maybe_convert_scalar(np.array([1])) + self.assertEqual(result, np.array([1])) + + # leave scalar dtype + result = com._maybe_convert_scalar(np.int64(1)) + self.assertEqual(result, np.int64(1)) + result = com._maybe_convert_scalar(np.int32(1)) + self.assertEqual(result, np.int32(1)) + result = com._maybe_convert_scalar(np.float32(1)) + self.assertEqual(result, np.float32(1)) + result = com._maybe_convert_scalar(np.int64(1)) + self.assertEqual(result, np.float64(1)) + + # coerce + result = com._maybe_convert_scalar(1) + self.assertEqual(result, np.int64(1)) + result = com._maybe_convert_scalar(1.0) + self.assertEqual(result, np.float64(1)) + result = com._maybe_convert_scalar(pd.Timestamp('20130101')) + self.assertEqual(result, pd.Timestamp('20130101').value) + result = com._maybe_convert_scalar(datetime(2013, 1, 1)) + self.assertEqual(result, pd.Timestamp('20130101').value) + result = com._maybe_convert_scalar(pd.Timedelta('1 day 1 min')) + self.assertEqual(result, pd.Timedelta('1 day 1 min').value) + class TestConvert(tm.TestCase):