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.3

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.3
File Actions
rdatacompy-1.1.3-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details for rdatacompy-1.1.3-cp314-cp314-win_amd64.whl
rdatacompy-1.1.3-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.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details for rdatacompy-1.1.3-cp313-cp313-win_amd64.whl
rdatacompy-1.1.3-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.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details for rdatacompy-1.1.3-cp312-cp312-win_amd64.whl
rdatacompy-1.1.3-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.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details for rdatacompy-1.1.3-cp311-cp311-win_amd64.whl
rdatacompy-1.1.3-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.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details for rdatacompy-1.1.3-cp310-cp310-win_amd64.whl
rdatacompy-1.1.3-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.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details for rdatacompy-1.1.3-cp39-cp39-win_amd64.whl
rdatacompy-1.1.3-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.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
rdatacompy-1.1.3-cp38-cp38-win_amd64.whl CPython 3.8 CPython 3.8 Windows x86-64 Details for rdatacompy-1.1.3-cp38-cp38-win_amd64.whl
rdatacompy-1.1.3-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.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Total release size: 13.5 MB

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

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

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

Download URL rdatacompy-1.1.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.14 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
4febff7a5e615d18d4c608a3dd5d1dcceeb69907799fff47b51dcdf297d342b9
BLAKE2b-256 checksum
How to use checksums
9946f5961a909cc430d67eb616a4a03590ba571b7b2b76f71970be6d837da940
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL rdatacompy-1.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.13 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
36a1b00d20dbbc3f2abbe279470d8c262e12b5ac2e2c4fafdc340cfb92af00f7
BLAKE2b-256 checksum
How to use checksums
37e03aa67a84dbd42877e0ce5a44ef2f03675979820295b20f23f9439082f626
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp312-cp312-win_amd64.whl
Size 921.4 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
cc0cf6b3cc0728dd9070a4693dccb73aea31e91782e3a83d3039c1e31a884287
BLAKE2b-256 checksum
How to use checksums
856aa5498dd5d2333b45150f7436ce90a7c3c1e40d1a41600fa5f94dcfa244be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
4a1e86578392512ec758043ff7aa83aa62d64104ae3da7d13435c0dd2b6d95a4
BLAKE2b-256 checksum
How to use checksums
3366e6fbc0ec1354f21576197d57ecb31bf8f2f80e648de34eeae3405e1bcc25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp311-cp311-win_amd64.whl
Size 920.4 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
1fb06ae55c1b2d2d11f4b01f8e134cb5391efcfa01bd9c2d271e3b3805561f9a
BLAKE2b-256 checksum
How to use checksums
306d04fe9efaa11a54604c7e27040063abbf65914742453e04378710e1784ab5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

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

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

Download URL rdatacompy-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
5ebaa0fddaa94433e0eee928df630e46111b7aa9cec009d11069ae50b2bab640
BLAKE2b-256 checksum
How to use checksums
815de4c2757cd40a7270922233982e32c03b79e92e79e0ade044b2d40cfcb46e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp39-cp39-win_amd64.whl
Size 923.4 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
44c6e3f99fb3256ce54361012d49710833aaf765c8b8fd0910b9e9704d5df944
BLAKE2b-256 checksum
How to use checksums
45f0aaa79cd363a9b1979d8bd9165c6ba52048483fbe9f31eaed5e64e2f1adab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
235ee43fdaeb588a69e887236045b7999eeae34d4d512b57dc0960850bd211b3
BLAKE2b-256 checksum
How to use checksums
e6653adbe78da87ffb42426f4b0be9f3a31f60890640ea3477d3db4c03aca5c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp38-cp38-win_amd64.whl
Size 922.6 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
4b87437ec64497e79f7f78873fb371426244eea3f39ec49adc8ac447d17e7230
BLAKE2b-256 checksum
How to use checksums
d6fe8b9466713be402313d5878d72348890221b13cb2710f1ebb7e81922d323f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
ecdf60c3cc1098d676805cbd7f22f91b2474139e4b11678b0bad6cea8d065a44
BLAKE2b-256 checksum
How to use checksums
13ee9ab294d0a9bc8e9cfef3ecb04a1b9717dc65e8330cb6090b5de9427162b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Security for rdatacompy 1.1.3

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