Skip to main content

RDataCompy

Lightning-fast dataframe comparison library, implemented in Rust with Python bindings.

Overview

RDataCompy is a high-performance library for comparing dataframes, inspired by Capital One's datacompy. Built in Rust and leveraging Apache Arrow, it provides 40+ million cells/second throughput with comprehensive comparison reports.

Why RDataCompy?

  • 🚀 Blazing Fast: 40-46M cells/second (100-1000x faster than Python-based solutions)
  • 💾 Memory Efficient: Zero-copy operations using Apache Arrow columnar format
  • 🎯 Flexible: Configurable tolerance for numeric comparisons
  • 📊 Comprehensive: Detailed reports showing exact differences
  • 🔧 Multi-Format: Works with PyArrow, Pandas, PySpark, and Polars DataFrames
  • 💰 Decimal Support: Full DECIMAL(p,s) support with cross-precision compatibility

Installation

pip install rdatacompy

Optional Dependencies

# For PySpark support
pip install rdatacompy[spark]

# For Pandas support
pip install rdatacompy[pandas]

# For Polars support
pip install rdatacompy[polars]

# Install everything
pip install rdatacompy[all]

Quick Start

Basic Usage (PyArrow)

import pyarrow as pa
from rdatacompy import Compare

# Create sample tables
df1 = pa.table({
    'id': [1, 2, 3, 4],
    'value': [10.0, 20.0, 30.0, 40.0],
    'name': ['Alice', 'Bob', 'Charlie', 'David']
})

df2 = pa.table({
    'id': [1, 2, 3, 5],
    'value': [10.001, 20.0, 30.5, 50.0],
    'name': ['Alice', 'Bob', 'Chuck', 'Eve']
})

# Compare dataframes
comp = Compare(
    df1, 
    df2,
    join_columns=['id'],
    abs_tol=0.01,  # Absolute tolerance for floats
    df1_name='original',
    df2_name='updated'
)

# Print comprehensive report
print(comp.report())

Example Output:

DataComPy Comparison
--------------------

DataFrame Summary
-----------------

DataFrame          Columns       Rows
original                 3          4
updated                  3          4

Column Summary
--------------

Number of columns in common: 3
Number of columns in original but not in updated: 0
Number of columns in updated but not in original: 0

Row Summary
-----------

Matched on: id
Any duplicates on match values: No
Absolute Tolerance: 0.01
Relative Tolerance: 0
Number of rows in common: 3
Number of rows in original but not in updated: 1
Number of rows in updated but not in original: 1

Number of rows with some compared columns unequal: 1
Number of rows with all compared columns equal: 2

Column Comparison
-----------------

Number of columns compared with some values unequal: 2
Number of columns compared with all values equal: 0
Total number of values which compare unequal: 2

Columns with Unequal Values or Types
------------------------------------

Column               original dtype  updated dtype      # Unequal     Max Diff  # Null Diff
value                float64         float64                    1       0.5000            0
name                 string          string                     1          N/A            0

Sample Rows with Unequal Values for 'value'
--------------------------------------------------

id                   value (original)          value (updated)          
3                    30.000000                 30.500000                

Sample Rows with Unequal Values for 'name'
--------------------------------------------------

id                   name (original)           name (updated)           
3                    Charlie                   Chuck                    

Understanding the Report:

  • DataFrame Summary: Shows the dimensions of both dataframes being compared
  • Column Summary: Lists columns that exist in both, and columns unique to each dataframe
  • Row Summary:
    • Shows which columns were used for matching (join keys)
    • Number of rows that exist in both dataframes (3 in this example)
    • Rows unique to each dataframe (id=4 only in original, id=5 only in updated)
    • How many matched rows have differences (1 row has differences, 2 are identical)
  • Column Comparison: Summary of which columns have differences across all matched rows
  • Columns with Unequal Values: Detailed breakdown per column showing:
    • Data types in each dataframe
    • Number of unequal values
    • Max difference (for numeric columns)
    • Number of null mismatches
  • Sample Rows: Shows actual examples of differences with join key values displayed first (not row index), making it easy to identify exactly which records differ

Using with Pandas

import pandas as pd
from rdatacompy import Compare

df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'amount': [100.50, 200.75, 300.25]
})

df2 = pd.DataFrame({
    'id': [1, 2, 3],
    'amount': [100.51, 200.75, 300.24]
})

# Directly compare Pandas DataFrames (auto-converted to Arrow)
comp = Compare(df1, df2, join_columns=['id'], abs_tol=0.01)
print(comp.report())

Using with PySpark

from pyspark.sql import SparkSession
from rdatacompy import Compare

# For Spark 3.5, enable Arrow for better performance
spark = SparkSession.builder \
    .config("spark.sql.execution.arrow.pyspark.enabled", "true") \
    .getOrCreate()

df1 = spark.createDataFrame([(1, 100), (2, 200)], ['id', 'value'])
df2 = spark.createDataFrame([(1, 100), (2, 201)], ['id', 'value'])

# Directly compare Spark DataFrames (auto-converted to Arrow)
# Works with Spark <4.0 (via toPandas) and 4.0+ (via toArrow)
comp = Compare(df1, df2, join_columns=['id'])
print(comp.report())

Decimal Support

from decimal import Decimal
import pyarrow as pa
from rdatacompy import Compare

# Compare DECIMAL columns with different precision/scale
df1 = pa.table({
    'id': [1, 2, 3],
    'price': pa.array([
        Decimal('123.456789012345'),
        Decimal('999.999999999999'),
        Decimal('42.123456789012')
    ], type=pa.decimal128(28, 12))  # High precision
})

df2 = pa.table({
    'id': [1, 2, 3],
    'price': pa.array([
        Decimal('123.456789'),
        Decimal('999.999998'),
        Decimal('42.123457')
    ], type=pa.decimal128(18, 6))  # Lower precision
})

# Compare with tolerance - handles different precision automatically
comp = Compare(df1, df2, join_columns=['id'], abs_tol=0.00001)
print(comp.report())

Features

Comparison Report

The report includes:

  • DataFrame Summary: Row and column counts
  • Column Summary: Common columns, unique to each dataframe
  • Row Summary: Matched rows, unique rows, duplicates
  • Column Comparison: Which columns have differences
  • Sample Differences: Example rows with unequal values
  • Statistics: Number of differences, max difference, null differences

API Methods

comp = Compare(df1, df2, join_columns=['id'])

# Get full comparison report
report = comp.report()

# Check if dataframes match
matches = comp.matches()  # Returns bool

# Get common columns
common_cols = comp.intersect_columns()

# Get columns unique to each dataframe
df1_only = comp.df1_unq_columns()
df2_only = comp.df2_unq_columns()

Supported Data Types

  • ✅ Integers: int8, int16, int32, int64, uint8, uint16, uint32, uint64
  • ✅ Floats: float32, float64
  • ✅ Decimals: decimal128, decimal256 (with cross-precision compatibility)
  • ✅ Strings: utf8, large_utf8
  • ✅ Booleans
  • ✅ Dates: date32, date64
  • ✅ Timestamps (with timezone support)

Cross-Type Compatibility

RDataCompy is designed for real-world data migration scenarios:

# Compare different numeric types (int vs float vs decimal)
df1 = pa.table({'id': [1], 'val': pa.array([100], type=pa.int64())})
df2 = pa.table({'id': [1], 'val': pa.array([100.0], type=pa.float64())})
comp = Compare(df1, df2, join_columns=['id'])
comp.matches()  # True - types are compatible!

# Compare different decimal precisions
df1 = pa.table({'val': pa.array([Decimal('123.45')], type=pa.decimal128(28, 12))})
df2 = pa.table({'val': pa.array([Decimal('123.45')], type=pa.decimal128(18, 6))})
# Compares successfully - precision difference handled automatically

Performance

Benchmarked on a dataset with 150,000 rows × 200 columns (58.8M data points):

  • Comparison time: 1.3 seconds
  • Throughput: 46 million cells/second
  • Memory overhead: 16 MB (only stores differences)

vs datacompy

RDataCompy is significantly faster than Python-based solutions:

  • Columnar processing: Uses SIMD-optimized Arrow compute kernels
  • Zero-copy: Works directly on Arrow arrays without data duplication
  • Hash-based joins: O(n) row matching vs O(n²) pandas merge
  • No type inference: Arrow types known upfront (no runtime checks per column)

Development

Prerequisites

  • Rust 1.70+
  • Python 3.8+
  • maturin

Building from Source

# Clone repository
git clone https://github.com/yourusername/rdatacompy
cd rdatacompy

# Create virtual environment
python -m venv .venv
source .venv/bin/activate

# Install maturin
pip install maturin

# Build and install in development mode
maturin develop --release

# Run examples
python examples/basic_usage.py

Running Tests

# Rust tests
cargo test

# Python examples
python examples/test_multi_dataframe_types.py
python examples/test_decimal_types.py
python examples/benchmark_large.py

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Apache-2.0

Acknowledgments

Roadmap

See TODO.md for planned features and improvements.

Metadata

Release files for rdatacompy 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for rdatacompy 1.1.1
File Actions
rdatacompy-1.1.1-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details for rdatacompy-1.1.1-cp314-cp314-win_amd64.whl
rdatacompy-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details for rdatacompy-1.1.1-cp313-cp313-win_amd64.whl
rdatacompy-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details for rdatacompy-1.1.1-cp312-cp312-win_amd64.whl
rdatacompy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details for rdatacompy-1.1.1-cp311-cp311-win_amd64.whl
rdatacompy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details for rdatacompy-1.1.1-cp310-cp310-win_amd64.whl
rdatacompy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details for rdatacompy-1.1.1-cp39-cp39-win_amd64.whl
rdatacompy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.1-cp38-cp38-win_amd64.whl CPython 3.8 CPython 3.8 Windows x86-64 Details for rdatacompy-1.1.1-cp38-cp38-win_amd64.whl
rdatacompy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 CPython 3.8 Linux glibc 2.17+ x86-64 Details for rdatacompy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Total release size: 12.6 MB

Release files / rdatacompy-1.1.1-cp314-cp314-win_amd64.whl

Download URL rdatacompy-1.1.1-cp314-cp314-win_amd64.whl
Size 853.4 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
8b27feba61c4291ffaee589bb0980c20a5a3d47191345f8796ae19bab0330902
BLAKE2b-256 checksum
How to use checksums
82d675baca73082de33657dd33418b8369ebadc79104e95d152f76adf221b1b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 943.1 kB
Tags CPython 3.14 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
c706a380db99bc926150fcbfbe5a2ec54d1e4d8d8eaa7688df57ae2ed65351d2
BLAKE2b-256 checksum
How to use checksums
c44d059b901e48e3751fb73c851da07c0575fabc85679bc3e9dfe0e8e960dfe5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp313-cp313-win_amd64.whl

Download URL rdatacompy-1.1.1-cp313-cp313-win_amd64.whl
Size 853.4 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
2091f6e12e10fa05ea968b9356fdb2cf0eccdf7c6096d50d307cc2d935adde42
BLAKE2b-256 checksum
How to use checksums
95ccd4a0070e08654f2faf7f18083301e49a6f9edfcf8ea2348723d8324ece08
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 943.1 kB
Tags CPython 3.13 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
c6cac59e731de18d2d28c31b0bc1312918eaa0bda0307faac03590fdff843fdd
BLAKE2b-256 checksum
How to use checksums
1a3b08004d9a91d9a43912b1a5547e359b9bfea4bf6122576d8764f07438281e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp312-cp312-win_amd64.whl

Download URL rdatacompy-1.1.1-cp312-cp312-win_amd64.whl
Size 853.5 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
514b61705e6989f1763a6ebc9899f9921de53be5ecf15e6ff732d2d8c0ba7d37
BLAKE2b-256 checksum
How to use checksums
35cd21b7fe91b73c585e4b2ad3841eafb20857f547b1968edef9e8a6a1948aa5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 943.3 kB
Tags CPython 3.12 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
56bb76a983f570d5d27db3e46957f63929d3cb8e6333e0316c9f051016415f03
BLAKE2b-256 checksum
How to use checksums
7735b99ac5e4560934c1a5af336444a72fef17f0bb3d88fa0a044930f0897c03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp311-cp311-win_amd64.whl

Download URL rdatacompy-1.1.1-cp311-cp311-win_amd64.whl
Size 852.5 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
25283e6ae7a5e62525a9b6a0d6c3c33fd4dc6d67423018d13f20b7a2ac3ba5e7
BLAKE2b-256 checksum
How to use checksums
55399cb5222269614f1b5a162e71b5118c9ca5c19f9a88ec5abe423bb3478922
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 942.7 kB
Tags CPython 3.11 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
81922cb41ca43a0e4e09ddfd7b51a22f80cf99641909bf380a691760e32f096c
BLAKE2b-256 checksum
How to use checksums
0d03f224acdb5bce77cf15ff4eb2323b8e452107539e1fab2efd7cf98979b3b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp310-cp310-win_amd64.whl

Download URL rdatacompy-1.1.1-cp310-cp310-win_amd64.whl
Size 854.0 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
bb3812c52cdbf0a837a394e4b7fce4486d5cc389467e65ccb4f3e58fc9fd3f67
BLAKE2b-256 checksum
How to use checksums
addfd52e5b2602c429bed7ff80348d4f061b2df8bd506323cd7007ad99d8a956
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 944.4 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
6ee5a4a75b6b969ea78b3a3bb9110a0089e2e9295298d728c9c6155aff3d91ca
BLAKE2b-256 checksum
How to use checksums
72ee71660359405a5e1ce9fb54bdcccdf38b2fa5c887d24c9c5bad90217be211
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp39-cp39-win_amd64.whl

Download URL rdatacompy-1.1.1-cp39-cp39-win_amd64.whl
Size 854.7 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
71bcee63cd12b6d0fcd393367a03412e80caf1de2e3f7f0099e3bff18830efb1
BLAKE2b-256 checksum
How to use checksums
715cd4033ce10b6af164423c0deeca8f1576d4f36d72a2b2b75b0ffa50a67ed2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 945.2 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
8f90a70e186aeba6d5a268e2c61b99f222c3bb6a3d475657d5daa0c3568d9480
BLAKE2b-256 checksum
How to use checksums
51d6eb22ece56cd74b98275c1b7b9b46f3e9610317fa6bde3a32081ed4a71503
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp38-cp38-win_amd64.whl

Download URL rdatacompy-1.1.1-cp38-cp38-win_amd64.whl
Size 854.1 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
82f65fa60baf50c784fda435a4a61aa2bbc802e530bce15a0164513bb84ba39c
BLAKE2b-256 checksum
How to use checksums
7ec42e819445bdd3cc94e441efd064dd8dc468e573f86ffad7a29b337de18711
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / rdatacompy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rdatacompy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 943.5 kB
Tags CPython 3.8 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
7d9b6a9f9391faea3be32c1a96649bf792a8eb1c3a533707ef7f8fe89e1631a4
BLAKE2b-256 checksum
How to use checksums
4e7e819db282083e2e77f2d1c7f7ca3cb794be78ca605493a831177232dc07d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Security for rdatacompy 1.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page