From 39adf88aa3fc09d782e386f049e9711e1fa1cd61 Mon Sep 17 00:00:00 2001 From: sah0725 Date: Tue, 7 Oct 2025 23:37:50 +0530 Subject: [PATCH 1/8] DOC: Add comprehensive floating point precision documentation for CSV operations Addresses issue #13159 by adding detailed documentation about: - Why floating point precision loss occurs in CSV roundtrips - How to use float_format parameter to control precision - Format specifier reference (%.6f, %.10g, %.6e, etc.) - Best practices for different data types (scientific, financial) - Testing function to validate roundtrip precision - dtype preservation behavior Includes 6 working code examples with proper cleanup and comprehensive guidance for users experiencing CSV precision issues. --- doc/source/user_guide/io.rst | 202 +++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 5b25462568cfa..d79d3e1653438 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1671,6 +1671,208 @@ function takes a number of arguments. Only the first is required. * ``chunksize``: Number of rows to write at a time * ``date_format``: Format string for datetime objects +.. _io.csv_precision: + +Floating Point Precision in CSV +++++++++++++++++++++++++++++++++ + +When working with floating point numbers in CSV files, it's important to understand +that precision can be lost during the write/read roundtrip. This section explains +why this happens and how to control precision using the ``float_format`` parameter. + +Understanding Precision Loss +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Floating point numbers are represented internally using binary format, which can +lead to precision issues when converting to and from text representation in CSV files. +Consider this example: + +.. ipython:: python + + import pandas as pd + import numpy as np + + # Create a DataFrame with a problematic floating point value + df = pd.DataFrame({'value': [0.1 + 0.2]}) + print(f"Original value: {df['value'].iloc[0]!r}") + + # Save to CSV and read back + df.to_csv('test_precision.csv', index=False) + df_read = pd.read_csv('test_precision.csv') + print(f"After CSV roundtrip: {df_read['value'].iloc[0]!r}") + print(f"Values are equal: {df['value'].iloc[0] == df_read['value'].iloc[0]}") + +.. ipython:: python + :suppress: + + import os + if os.path.exists('test_precision.csv'): + os.remove('test_precision.csv') + +In this case, the slight precision loss occurs because the decimal ``0.3`` cannot be +exactly represented in binary floating point format. + +Using float_format for Precision Control +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``float_format`` parameter allows you to control how floating point numbers are +formatted when written to CSV. This can help preserve precision and ensure reliable +roundtrip operations. + +.. ipython:: python + + # Example with high precision number + df = pd.DataFrame({'precision_test': [123456789.123456789]}) + print(f"Original: {df['precision_test'].iloc[0]}") + + # Default behavior + df.to_csv('default.csv', index=False) + df_default = pd.read_csv('default.csv') + + # With explicit precision control + df.to_csv('formatted.csv', index=False, float_format='%.15g') + df_formatted = pd.read_csv('formatted.csv') + + print(f"Default read: {df_default['precision_test'].iloc[0]}") + print(f"Formatted read: {df_formatted['precision_test'].iloc[0]}") + +.. ipython:: python + :suppress: + + for f in ['default.csv', 'formatted.csv']: + if os.path.exists(f): + os.remove(f) + +Format Specifiers +~~~~~~~~~~~~~~~~~ + +Different format specifiers have different effects on precision and output format: + +**Fixed-point notation (f)**: + - ``'%.6f'`` - 6 decimal places: ``123456789.123457`` + - ``'%.10f'`` - 10 decimal places: ``123456789.1234567910`` + - Best for: Numbers with known decimal precision requirements + +**General format (g)**: + - ``'%.6g'`` - 6 significant digits: ``1.23457e+08`` + - ``'%.15g'`` - 15 significant digits: ``123456789.123457`` + - Best for: Preserving significant digits, automatic scientific notation + +**Scientific notation (e)**: + - ``'%.6e'`` - Scientific with 6 decimal places: ``1.234568e+08`` + - ``'%.10e'`` - Scientific with 10 decimal places: ``1.2345678912e+08`` + - Best for: Very large or very small numbers + +.. ipython:: python + + # Demonstrate different format effects + df = pd.DataFrame({'number': [123456789.123456789]}) + + formats = {'%.6f': '6 decimal places', + '%.10g': '10 significant digits', + '%.6e': 'scientific notation'} + + for fmt, description in formats.items(): + df.to_csv('temp.csv', index=False, float_format=fmt) + with open('temp.csv', 'r') as f: + csv_content = f.read().strip().split('\n')[1] + print(f"{description:20}: {csv_content}") + +.. ipython:: python + :suppress: + + if os.path.exists('temp.csv'): + os.remove('temp.csv') + +Best Practices +~~~~~~~~~~~~~~ + +**For high-precision scientific data**: + Use ``float_format='%.17g'`` to preserve maximum precision: + +.. ipython:: python + + # High precision example + scientific_data = pd.DataFrame({ + 'measurement': [1.23456789012345e-10, 9.87654321098765e15] + }) + scientific_data.to_csv('scientific.csv', index=False, float_format='%.17g') + +.. ipython:: python + :suppress: + + if os.path.exists('scientific.csv'): + os.remove('scientific.csv') + +**For financial data**: + Use fixed decimal places like ``float_format='%.2f'``: + +.. ipython:: python + + # Financial data example + financial_data = pd.DataFrame({ + 'price': [19.99, 1234.56, 0.01] + }) + financial_data.to_csv('financial.csv', index=False, float_format='%.2f') + +.. ipython:: python + :suppress: + + if os.path.exists('financial.csv'): + os.remove('financial.csv') + +**For ensuring exact roundtrip**: + Test your specific data to find the minimum precision needed: + +.. ipython:: python + + def test_roundtrip_precision(df, float_format): + """Test if a float_format preserves data during CSV roundtrip.""" + df.to_csv('test.csv', index=False, float_format=float_format) + df_read = pd.read_csv('test.csv') + return df.equals(df_read) + + # Test data + test_df = pd.DataFrame({'values': [123.456789, 0.000123456, 1.23e15]}) + + # Test different precisions + for fmt in ['%.6g', '%.10g', '%.15g']: + success = test_roundtrip_precision(test_df, fmt) + print(f"Format {fmt}: {'✓' if success else '✗'} roundtrip success") + +.. ipython:: python + :suppress: + + if os.path.exists('test.csv'): + os.remove('test.csv') + +**dtype Preservation Note**: + Be aware that CSV format does not preserve NumPy dtypes. All numeric data + will be read back as ``float64`` or ``int64`` regardless of the original dtype: + +.. ipython:: python + + # dtype preservation example + original_df = pd.DataFrame({ + 'float32_col': np.array([1.23], dtype=np.float32), + 'float64_col': np.array([1.23], dtype=np.float64) + }) + + print("Original dtypes:") + print(original_df.dtypes) + + original_df.to_csv('dtypes.csv', index=False) + read_df = pd.read_csv('dtypes.csv') + + print("\nAfter CSV roundtrip:") + print(read_df.dtypes) + +.. ipython:: python + :suppress: + + if os.path.exists('dtypes.csv'): + os.remove('dtypes.csv') + Writing a formatted string ++++++++++++++++++++++++++ From 7e302bf5e3070163a4e0bd741f8809f60ada6f3c Mon Sep 17 00:00:00 2001 From: sah0725 Date: Tue, 7 Oct 2025 23:51:36 +0530 Subject: [PATCH 2/8] Fix trailing whitespace in CSV precision documentation Removes trailing spaces that were causing pre-commit checks to fail. --- doc/source/user_guide/io.rst | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index d79d3e1653438..88be3352c6c0c 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1691,11 +1691,11 @@ Consider this example: import pandas as pd import numpy as np - + # Create a DataFrame with a problematic floating point value df = pd.DataFrame({'value': [0.1 + 0.2]}) print(f"Original value: {df['value'].iloc[0]!r}") - + # Save to CSV and read back df.to_csv('test_precision.csv', index=False) df_read = pd.read_csv('test_precision.csv') @@ -1704,7 +1704,7 @@ Consider this example: .. ipython:: python :suppress: - + import os if os.path.exists('test_precision.csv'): os.remove('test_precision.csv') @@ -1724,21 +1724,21 @@ roundtrip operations. # Example with high precision number df = pd.DataFrame({'precision_test': [123456789.123456789]}) print(f"Original: {df['precision_test'].iloc[0]}") - + # Default behavior df.to_csv('default.csv', index=False) df_default = pd.read_csv('default.csv') - + # With explicit precision control df.to_csv('formatted.csv', index=False, float_format='%.15g') df_formatted = pd.read_csv('formatted.csv') - + print(f"Default read: {df_default['precision_test'].iloc[0]}") print(f"Formatted read: {df_formatted['precision_test'].iloc[0]}") .. ipython:: python :suppress: - + for f in ['default.csv', 'formatted.csv']: if os.path.exists(f): os.remove(f) @@ -1754,7 +1754,7 @@ Different format specifiers have different effects on precision and output forma - Best for: Numbers with known decimal precision requirements **General format (g)**: - - ``'%.6g'`` - 6 significant digits: ``1.23457e+08`` + - ``'%.6g'`` - 6 significant digits: ``1.23457e+08`` - ``'%.15g'`` - 15 significant digits: ``123456789.123457`` - Best for: Preserving significant digits, automatic scientific notation @@ -1767,11 +1767,11 @@ Different format specifiers have different effects on precision and output forma # Demonstrate different format effects df = pd.DataFrame({'number': [123456789.123456789]}) - + formats = {'%.6f': '6 decimal places', - '%.10g': '10 significant digits', + '%.10g': '10 significant digits', '%.6e': 'scientific notation'} - + for fmt, description in formats.items(): df.to_csv('temp.csv', index=False, float_format=fmt) with open('temp.csv', 'r') as f: @@ -1780,7 +1780,7 @@ Different format specifiers have different effects on precision and output forma .. ipython:: python :suppress: - + if os.path.exists('temp.csv'): os.remove('temp.csv') @@ -1800,7 +1800,7 @@ Best Practices .. ipython:: python :suppress: - + if os.path.exists('scientific.csv'): os.remove('scientific.csv') @@ -1809,7 +1809,7 @@ Best Practices .. ipython:: python - # Financial data example + # Financial data example financial_data = pd.DataFrame({ 'price': [19.99, 1234.56, 0.01] }) @@ -1817,7 +1817,7 @@ Best Practices .. ipython:: python :suppress: - + if os.path.exists('financial.csv'): os.remove('financial.csv') @@ -1831,10 +1831,10 @@ Best Practices df.to_csv('test.csv', index=False, float_format=float_format) df_read = pd.read_csv('test.csv') return df.equals(df_read) - + # Test data test_df = pd.DataFrame({'values': [123.456789, 0.000123456, 1.23e15]}) - + # Test different precisions for fmt in ['%.6g', '%.10g', '%.15g']: success = test_roundtrip_precision(test_df, fmt) @@ -1842,7 +1842,7 @@ Best Practices .. ipython:: python :suppress: - + if os.path.exists('test.csv'): os.remove('test.csv') @@ -1857,19 +1857,19 @@ Best Practices 'float32_col': np.array([1.23], dtype=np.float32), 'float64_col': np.array([1.23], dtype=np.float64) }) - + print("Original dtypes:") print(original_df.dtypes) - + original_df.to_csv('dtypes.csv', index=False) read_df = pd.read_csv('dtypes.csv') - + print("\nAfter CSV roundtrip:") print(read_df.dtypes) .. ipython:: python :suppress: - + if os.path.exists('dtypes.csv'): os.remove('dtypes.csv') From d7af09a3a214f402f3aeb2c3e694e114bd329d91 Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 14:24:19 +0530 Subject: [PATCH 3/8] DOC: Fix heading capitalization in CSV precision documentation to pass CI --- doc/source/user_guide/io.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 88be3352c6c0c..c1e1ffb95949e 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1743,7 +1743,7 @@ roundtrip operations. if os.path.exists(f): os.remove(f) -Format Specifiers +Format specifiers ~~~~~~~~~~~~~~~~~ Different format specifiers have different effects on precision and output format: @@ -1784,7 +1784,7 @@ Different format specifiers have different effects on precision and output forma if os.path.exists('temp.csv'): os.remove('temp.csv') -Best Practices +Best practices ~~~~~~~~~~~~~~ **For high-precision scientific data**: From 11071550abc71bc2bc8ffd212c97ac24332f4bc1 Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 17:50:17 +0530 Subject: [PATCH 4/8] docs: fix ipython block indentation in CSV precision documentation --- doc/source/user_guide/io.rst | 116 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index c1e1ffb95949e..9e1b9bc88ee96 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1705,9 +1705,9 @@ Consider this example: .. ipython:: python :suppress: - import os - if os.path.exists('test_precision.csv'): - os.remove('test_precision.csv') + import os + if os.path.exists('test_precision.csv'): + os.remove('test_precision.csv') In this case, the slight precision loss occurs because the decimal ``0.3`` cannot be exactly represented in binary floating point format. @@ -1739,9 +1739,9 @@ roundtrip operations. .. ipython:: python :suppress: - for f in ['default.csv', 'formatted.csv']: - if os.path.exists(f): - os.remove(f) + for f in ['default.csv', 'formatted.csv']: + if os.path.exists(f): + os.remove(f) Format specifiers ~~~~~~~~~~~~~~~~~ @@ -1765,24 +1765,24 @@ Different format specifiers have different effects on precision and output forma .. ipython:: python - # Demonstrate different format effects - df = pd.DataFrame({'number': [123456789.123456789]}) + # Demonstrate different format effects + df = pd.DataFrame({'number': [123456789.123456789]}) - formats = {'%.6f': '6 decimal places', - '%.10g': '10 significant digits', - '%.6e': 'scientific notation'} + formats = {'%.6f': '6 decimal places', + '%.10g': '10 significant digits', + '%.6e': 'scientific notation'} - for fmt, description in formats.items(): - df.to_csv('temp.csv', index=False, float_format=fmt) - with open('temp.csv', 'r') as f: - csv_content = f.read().strip().split('\n')[1] - print(f"{description:20}: {csv_content}") + for fmt, description in formats.items(): + df.to_csv('temp.csv', index=False, float_format=fmt) + with open('temp.csv', 'r') as f: + csv_content = f.read().strip().split('\n')[1] + print(f"{description:20}: {csv_content}") .. ipython:: python :suppress: - if os.path.exists('temp.csv'): - os.remove('temp.csv') + if os.path.exists('temp.csv'): + os.remove('temp.csv') Best practices ~~~~~~~~~~~~~~ @@ -1792,59 +1792,59 @@ Best practices .. ipython:: python - # High precision example - scientific_data = pd.DataFrame({ - 'measurement': [1.23456789012345e-10, 9.87654321098765e15] - }) - scientific_data.to_csv('scientific.csv', index=False, float_format='%.17g') + # High precision example + scientific_data = pd.DataFrame({ + 'measurement': [1.23456789012345e-10, 9.87654321098765e15] + }) + scientific_data.to_csv('scientific.csv', index=False, float_format='%.17g') .. ipython:: python :suppress: - if os.path.exists('scientific.csv'): - os.remove('scientific.csv') + if os.path.exists('scientific.csv'): + os.remove('scientific.csv') **For financial data**: Use fixed decimal places like ``float_format='%.2f'``: .. ipython:: python - # Financial data example - financial_data = pd.DataFrame({ - 'price': [19.99, 1234.56, 0.01] - }) - financial_data.to_csv('financial.csv', index=False, float_format='%.2f') + # Financial data example + financial_data = pd.DataFrame({ + 'price': [19.99, 1234.56, 0.01] + }) + financial_data.to_csv('financial.csv', index=False, float_format='%.2f') .. ipython:: python :suppress: - if os.path.exists('financial.csv'): - os.remove('financial.csv') + if os.path.exists('financial.csv'): + os.remove('financial.csv') **For ensuring exact roundtrip**: Test your specific data to find the minimum precision needed: .. ipython:: python - def test_roundtrip_precision(df, float_format): - """Test if a float_format preserves data during CSV roundtrip.""" - df.to_csv('test.csv', index=False, float_format=float_format) - df_read = pd.read_csv('test.csv') - return df.equals(df_read) + def test_roundtrip_precision(df, float_format): + """Test if a float_format preserves data during CSV roundtrip.""" + df.to_csv('test.csv', index=False, float_format=float_format) + df_read = pd.read_csv('test.csv') + return df.equals(df_read) - # Test data - test_df = pd.DataFrame({'values': [123.456789, 0.000123456, 1.23e15]}) + # Test data + test_df = pd.DataFrame({'values': [123.456789, 0.000123456, 1.23e15]}) - # Test different precisions - for fmt in ['%.6g', '%.10g', '%.15g']: - success = test_roundtrip_precision(test_df, fmt) - print(f"Format {fmt}: {'✓' if success else '✗'} roundtrip success") + # Test different precisions + for fmt in ['%.6g', '%.10g', '%.15g']: + success = test_roundtrip_precision(test_df, fmt) + print(f"Format {fmt}: {'✓' if success else '✗'} roundtrip success") .. ipython:: python :suppress: - if os.path.exists('test.csv'): - os.remove('test.csv') + if os.path.exists('test.csv'): + os.remove('test.csv') **dtype Preservation Note**: Be aware that CSV format does not preserve NumPy dtypes. All numeric data @@ -1852,26 +1852,26 @@ Best practices .. ipython:: python - # dtype preservation example - original_df = pd.DataFrame({ - 'float32_col': np.array([1.23], dtype=np.float32), - 'float64_col': np.array([1.23], dtype=np.float64) - }) + # dtype preservation example + original_df = pd.DataFrame({ + 'float32_col': np.array([1.23], dtype=np.float32), + 'float64_col': np.array([1.23], dtype=np.float64) + }) - print("Original dtypes:") - print(original_df.dtypes) + print("Original dtypes:") + print(original_df.dtypes) - original_df.to_csv('dtypes.csv', index=False) - read_df = pd.read_csv('dtypes.csv') + original_df.to_csv('dtypes.csv', index=False) + read_df = pd.read_csv('dtypes.csv') - print("\nAfter CSV roundtrip:") - print(read_df.dtypes) + print("\nAfter CSV roundtrip:") + print(read_df.dtypes) .. ipython:: python :suppress: - if os.path.exists('dtypes.csv'): - os.remove('dtypes.csv') + if os.path.exists('dtypes.csv'): + os.remove('dtypes.csv') Writing a formatted string ++++++++++++++++++++++++++ From 84f9bbeb650f87768bfe62966773e8c834b9836b Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 19:56:45 +0530 Subject: [PATCH 5/8] docs: fix f-string syntax issues in CSV precision documentation --- doc/source/user_guide/io.rst | 51 ++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 9e1b9bc88ee96..591a57524c1e6 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1692,17 +1692,17 @@ Consider this example: import pandas as pd import numpy as np - # Create a DataFrame with a problematic floating point value - df = pd.DataFrame({'value': [0.1 + 0.2]}) - print(f"Original value: {df['value'].iloc[0]!r}") - - # Save to CSV and read back - df.to_csv('test_precision.csv', index=False) - df_read = pd.read_csv('test_precision.csv') - print(f"After CSV roundtrip: {df_read['value'].iloc[0]!r}") - print(f"Values are equal: {df['value'].iloc[0] == df_read['value'].iloc[0]}") - -.. ipython:: python + # Create a DataFrame with a problematic floating point value + df = pd.DataFrame({'value': [0.1 + 0.2]}) + original_value = df['value'].iloc[0] + print(f"Original value: {original_value!r}") + + # Save to CSV and read back + df.to_csv('test_precision.csv', index=False) + df_read = pd.read_csv('test_precision.csv') + read_value = df_read['value'].iloc[0] + print(f"After CSV roundtrip: {read_value!r}") + print(f"Values are equal: {original_value == read_value}").. ipython:: python :suppress: import os @@ -1721,22 +1721,23 @@ roundtrip operations. .. ipython:: python - # Example with high precision number - df = pd.DataFrame({'precision_test': [123456789.123456789]}) - print(f"Original: {df['precision_test'].iloc[0]}") + # Example with high precision number + df = pd.DataFrame({'precision_test': [123456789.123456789]}) + original_val = df['precision_test'].iloc[0] + print(f"Original: {original_val}") - # Default behavior - df.to_csv('default.csv', index=False) - df_default = pd.read_csv('default.csv') + # Default behavior + df.to_csv('default.csv', index=False) + df_default = pd.read_csv('default.csv') - # With explicit precision control - df.to_csv('formatted.csv', index=False, float_format='%.15g') - df_formatted = pd.read_csv('formatted.csv') + # With explicit precision control + df.to_csv('formatted.csv', index=False, float_format='%.15g') + df_formatted = pd.read_csv('formatted.csv') - print(f"Default read: {df_default['precision_test'].iloc[0]}") - print(f"Formatted read: {df_formatted['precision_test'].iloc[0]}") - -.. ipython:: python + default_val = df_default['precision_test'].iloc[0] + formatted_val = df_formatted['precision_test'].iloc[0] + print(f"Default read: {default_val}") + print(f"Formatted read: {formatted_val}").. ipython:: python :suppress: for f in ['default.csv', 'formatted.csv']: @@ -1769,7 +1770,7 @@ Different format specifiers have different effects on precision and output forma df = pd.DataFrame({'number': [123456789.123456789]}) formats = {'%.6f': '6 decimal places', - '%.10g': '10 significant digits', + '%.10g': '10 significant digits', '%.6e': 'scientific notation'} for fmt, description in formats.items(): From b8c48e6d04e5264feb5b777a0a598af15fd8fce3 Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 20:41:38 +0530 Subject: [PATCH 6/8] trigger: force CI rebuild for doc build From 544e8a0b51dce9beb951a5c6f4b478625c1d4c52 Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 21:12:26 +0530 Subject: [PATCH 7/8] docs: add missing StringIO import and fix remaining file I/O --- doc/source/user_guide/io.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 591a57524c1e6..02d25fc877fed 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1827,10 +1827,12 @@ Best practices .. ipython:: python + from io import StringIO + def test_roundtrip_precision(df, float_format): """Test if a float_format preserves data during CSV roundtrip.""" - df.to_csv('test.csv', index=False, float_format=float_format) - df_read = pd.read_csv('test.csv') + csv_string = df.to_csv(index=False, float_format=float_format) + df_read = pd.read_csv(StringIO(csv_string)) return df.equals(df_read) # Test data From 76d86a9167d1b2a054dad107999e905b795f8cfe Mon Sep 17 00:00:00 2001 From: sah0725 Date: Wed, 8 Oct 2025 22:16:12 +0530 Subject: [PATCH 8/8] docs: fix code formatting and remove f-strings for compatibility --- doc/source/user_guide/io.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 02d25fc877fed..84e89877ea655 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1828,7 +1828,7 @@ Best practices .. ipython:: python from io import StringIO - + def test_roundtrip_precision(df, float_format): """Test if a float_format preserves data during CSV roundtrip.""" csv_string = df.to_csv(index=False, float_format=float_format) @@ -1841,7 +1841,8 @@ Best practices # Test different precisions for fmt in ['%.6g', '%.10g', '%.15g']: success = test_roundtrip_precision(test_df, fmt) - print(f"Format {fmt}: {'✓' if success else '✗'} roundtrip success") + status = '✓' if success else '✗' + print("Format {}: {} roundtrip success".format(fmt, status)) .. ipython:: python :suppress: