diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 539275c7ff617..c1ddf2c29c5ae 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2656,7 +2656,7 @@ def memory_usage(self, index=True, deep=False) -> Series: Examples -------- >>> dtypes = ['int64', 'float64', 'complex128', 'object', 'bool'] - >>> data = dict([(t, np.ones(shape=5000).astype(t)) + >>> data = dict([(t, np.ones(shape=5000, dtype=int).astype(t)) ... for t in dtypes]) >>> df = pd.DataFrame(data) >>> df.head() @@ -2691,7 +2691,7 @@ def memory_usage(self, index=True, deep=False) -> Series: int64 40000 float64 40000 complex128 80000 - object 160000 + object 180000 bool 5000 dtype: int64 @@ -2790,7 +2790,7 @@ def transpose(self, *args, copy: bool = False) -> DataFrame: >>> df2_transposed 0 1 name Alice Bob - score 9.5 8 + score 9.5 8.0 employed False True kids 0 0 diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index d234997ee670c..dcd91b3a12294 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -1311,7 +1311,7 @@ def _format_strings(self) -> List[str]: float_format = get_option("display.float_format") if float_format is None: precision = get_option("display.precision") - float_format = lambda x: f"{x: .{precision:d}g}" + float_format = lambda x: f"{x: .{precision:d}f}" else: float_format = self.float_format @@ -1372,6 +1372,8 @@ def _format(x): tpl = " {v}" fmt_values.append(tpl.format(v=_format(v))) + fmt_values = _trim_zeros_float(str_floats=fmt_values, decimal=".") + return fmt_values @@ -1891,27 +1893,31 @@ def _trim_zeros_float( Trims zeros, leaving just one before the decimal points if need be. """ trimmed = str_floats - number_regex = re.compile(fr"\s*[\+-]?[0-9]+(\{decimal}[0-9]*)?") + number_regex = re.compile(fr"^\s*[\+-]?[0-9]+\{decimal}[0-9]*$") - def _is_number(x): + def is_number_with_decimal(x): return re.match(number_regex, x) is not None - def _cond(values): - finite = [x for x in values if _is_number(x)] - has_decimal = [decimal in x for x in finite] + def should_trim(values: Union[np.ndarray, List[str]]) -> bool: + """ + Determine if an array of strings should be trimmed. - return ( - len(finite) > 0 - and all(has_decimal) - and all(x.endswith("0") for x in finite) - and not (any(("e" in x) or ("E" in x) for x in finite)) - ) + Returns True if all numbers containing decimals (defined by the + above regular expression) within the array end in a zero, otherwise + returns False. + """ + numbers = [x for x in values if is_number_with_decimal(x)] + return len(numbers) > 0 and all(x.endswith("0") for x in numbers) - while _cond(trimmed): - trimmed = [x[:-1] if _is_number(x) else x for x in trimmed] + while should_trim(trimmed): + trimmed = [x[:-1] if is_number_with_decimal(x) else x for x in trimmed] # leave one 0 after the decimal points if need be. - return [x + "0" if x.endswith(decimal) and _is_number(x) else x for x in trimmed] + result = [ + x + "0" if is_number_with_decimal(x) and x.endswith(decimal) else x + for x in trimmed + ] + return result def _has_names(index: Index) -> bool: diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index b30ceed23b02e..78cb8ccc05077 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3439,3 +3439,25 @@ def test_to_string_complex_number_trims_zeros(): result = s.to_string() expected = "0 1.00+1.00j\n1 1.00+1.00j\n2 1.05+1.00j" assert result == expected + + +def test_nullable_float_to_string(float_ea_dtype): + # https://github.com/pandas-dev/pandas/issues/36775 + dtype = float_ea_dtype + s = pd.Series([0.0, 1.0, None], dtype=dtype) + result = s.to_string() + expected = """0 0.0 +1 1.0 +2 """ + assert result == expected + + +def test_nullable_int_to_string(any_nullable_int_dtype): + # https://github.com/pandas-dev/pandas/issues/36775 + dtype = any_nullable_int_dtype + s = pd.Series([0, 1, None], dtype=dtype) + result = s.to_string() + expected = """0 0 +1 1 +2 """ + assert result == expected