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

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

Total release size: 12.6 MB

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

Download URL rdatacompy-1.1.2-cp314-cp314-win_amd64.whl
Size 853.1 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
53533307b5784252058166efdd476c043cfc02775e2c8e07b843e552615d7a42
BLAKE2b-256 checksum
How to use checksums
9c92320dd68821212f286d0029115b9c7702659593a51860f025e1ecd1445925
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.2-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
f892908cdd8182154892073d5b93ed51c51cfe791b4cb501f18d533bec7f0dcc
BLAKE2b-256 checksum
How to use checksums
ce0d6f778d3afd6f89c1766285aa6332133b348d3a55ee673ef7e88206952986
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL rdatacompy-1.1.2-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
a17f63ea35c8e448356a0f6ad1af28960150ae93d49fcc2bab885cdde6af958f
BLAKE2b-256 checksum
How to use checksums
5ae40d9e413114e5d525651721081c10c165cc8f7dbce61814e9c76adb616c06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.2-cp312-cp312-win_amd64.whl
Size 853.3 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
991fa64d9167864894a55415e4e1ce254565b2b4ffd5792b2def03f7dec3717d
BLAKE2b-256 checksum
How to use checksums
1ffe81585e704a7e295498e4b5303ace82996f8ad0b2f01e0c91f4d188abf9a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

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

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

Download URL rdatacompy-1.1.2-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
d6ef28da8710a47ef7a68edb5db4c6f59fc06f18d2d492a61edb4e7c25f31793
BLAKE2b-256 checksum
How to use checksums
40bcc2148e6e33caab2765d3bcf4ac29dcc3a1828878d45e21cee05e32373a27
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL rdatacompy-1.1.2-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
5c8b053f467011c71ed5beebe69af46fad0015dedbb8f1407835e9ea24d23228
BLAKE2b-256 checksum
How to use checksums
3b80f09570d663f98570cccd9b4f82aaed53e06292236868d24cd48b929eb65b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

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

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

Download URL rdatacompy-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 945.3 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
38a7fdd8178989a9521c60cf48c26df295751e23df6472b6e75622d9f51cb1df
BLAKE2b-256 checksum
How to use checksums
2393d0adadde4d4966a95791c605428c5c38295e1eef6a740a22159c31afdbd0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.2-cp38-cp38-win_amd64.whl
Size 854.2 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
8b79994add1947c93e1348d8229aee0469b8db5af721a8eb1f885028ec376f58
BLAKE2b-256 checksum
How to use checksums
787788b15284534b4dac56df7be0b55ea31441c23f91610d1be9cf9d130e9f38
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

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

Download URL rdatacompy-1.1.2-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
bad5790618d67eb6c928aaacf0b04a74e6ce651ed0851fffb8ddf91083a78340
BLAKE2b-256 checksum
How to use checksums
da01d83324c6ea852da93e428592860a42a14610cbe6085d5407505b6bde2aa6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Security for rdatacompy 1.1.2

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