TABDSR: Three-Step Table Processing for Accurate Calculations
TL;DR
TABDSR is a three-agent framework for working with tables: first break the question into sub-questions, then clean the junk out of the table, then generate code to do the math. The point is that each step tackles a separate LLM weakness instead of trying to do everything in one prompt.
Models are bad at complex table questions for three reasons: (1) multi-hop questions ("calculate X, then compare it with Y") get lost, and the model answers only part of them; (2) "dirty" cells ("$3,275", "1.24 (approx)") break code or cause calculation errors; (3) LLMs imitate arithmetic rather than actually doing it, so accuracy drops when the numbers change. The GSM-Symbolic study showed it: change the numbers in a problem and the model gets it wrong more often.
The method solves this with a three-step pipeline: the decomposer splits the question into atomic sub-questions (it works ONLY with the question text and ignores the table, so important details don't get lost in a large context), the sanitizer cleans the table (strips currency symbols, percent signs and footnotes, standardizes empty cells), and the reasoner generates Python code for each sub-question and runs it.
Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.
Method Blueprint
STEP 1: DECOMPOSITION → list of sub-questions
(question text only, NO table)
STEP 2: TABLE CLEANUP → clean JSON/DataFrame
(strip $, %, footnotes; null instead of "N/A", "-", "???")
STEP 3: CODE FOR EACH SUB-QUESTION → execution → final answer
(Pandas + Python)
The steps run in sequence. Steps 1 and 2 can run in parallel (they're independent). Step 3 uses the output of both.
Example in Practice
Task: A CFO receives a quarterly report in Excel. The question: "What's the total revenue for Q2-Q4, and by what percentage is it higher than Q1?"
The table contains cells like: "$12,500K", "N/A", "15.3% (prelim.)".
Prompt (step 1: decomposition):
Analyze the question and break it into sub-questions.
Look for conjunctions (and, or), commas, linking words (then, after that, by how much).
Question: "What's the total revenue for Q2-Q4, and by what percentage is it higher than Q1?"
Output:
1. Number of sub-questions
2. List of sub-questions
Prompt (step 2: cleanup):
Clean the table for machine processing:
1. Remove currency symbols ($, €), percent signs (%), thousands separators
2. Delete notes in parentheses: (prelim.), (approx), (estimate)
3. Replace empty values (N/A, -, ???, None) with null
4. Convert numbers to int or float
Table: [paste table]
Output the cleaned table as JSON.
Prompt (step 3: code):
Write Python code to answer each sub-question.
Use Pandas. The data is already loaded into a DataFrame df.
Sub-questions:
1. What is the sum of revenue for Q2, Q3, Q4?
2. What is the revenue for Q1?
3. By what percentage is (1) greater than (2)?
Output the code and the result.
Result: The model returns three code blocks: filtering and summing Q2-Q4, extracting Q1, and computing the percentage. Each block can be checked on its own. The final answer is an exact number, not a "roughly."
Why It Works
Weakness 1: details get lost in long context. When the prompt contains both the question and a big table, the model "forgets" parts of the question. A multi-hop request ("calculate X, compare with Y") turns into an answer about X only. TABDSR's fix: the decomposer works ONLY with the question; the table isn't passed in. The model sees the whole question and doesn't drop details.
Weakness 2: "dirty" data breaks code. The cell "$3,275" doesn't convert to a number, so Python throws an error. The note "(approx)" turns a cell into a string instead of a number. The fix: the sanitizer cleans the table BEFORE code generation. It strips symbols and standardizes empty values. If the first cleanup attempt doesn't parse, the model gets the error and tries again (reflection).
Weakness 3: LLMs imitate arithmetic. Models are trained on examples of calculations but don't "understand" arithmetic. They slip up on new numbers. The fix: code does the calculations, not the model. Python computes exactly. The model only generates the code.
Control knobs:
- Sanitizer iteration limit (currently 1) → raise it for very messy tables
- Decomposition granularity → ask for finer-grained sub-questions on hard tasks
- Cleanup instructions → add rules specific to your domain (e.g., "date format DD.MM.YYYY → YYYY-MM-DD")
Prompt Template
Step 1: Question Decomposition
You are analyzing a question to find the sub-questions inside it.
Rules:
1. Look for conjunctions (and, or, as well as), commas, linking words
2. Each sub-question must be atomic: one calculation or one comparison
3. Preserve order: if sub-question 2 depends on sub-question 1, say so
Question: {question}
Output:
- Number of sub-questions: [number]
- Sub-questions:
1. [sub-question 1]
2. [sub-question 2]
...
Step 2: Table Cleanup
Clean the table for machine processing.
Structure rules:
1. If there are multi-level headers, merge them into a single level
2. If the table is split into sections (blank rows, separators), remove the separators
Content rules:
1. Remove symbols: $, £, €, %, commas in numbers
2. Delete notes in parentheses: (approx), (prelim.), (estimated)
3. Convert empty values to null: N/A, -, ???, None, empty string
4. Numbers → int or float
Table:
{table}
Output the cleaned table as JSON:
{
"columns": [...],
"data": [[...], [...]]
}
Step 3: Code Generation
Write Python code to answer the sub-questions.
The data is loaded into a pandas DataFrame named df.
Sub-questions:
{sub_question_list}
For each sub-question:
1. Write the code
2. Show the result
3. If the sub-question depends on a previous one, use its result
At the end, combine the results into a final answer.
Placeholders:
{question}: the full text of the user's question{table}: the source table (you can paste it straight from Excel/CSV){sub_question_list}: the output of step 1
🚀 Quick start: paste into the chat (ChatGPT with Code Interpreter, or Claude):
I have a data table and a complex question.
Help me answer it using the TABDSR method:
1. Break the question into sub-questions (work only with the question text)
2. Clean the junk out of the table (currency symbols, footnotes, empty values)
3. Write Python code for each sub-question
Table: [paste table]
Question: [paste question]
The LLM will ask about the table format and clarify which symbols count as junk, because cleanup rules depend on the domain (finance, logistics, HR).
Limitations
⚠️ Requires Code Interpreter: The method generates Python code that has to be executed. In a regular chat without Code Interpreter (ChatGPT) or Computer Use (Claude), it won't work. You need a plan with code execution.
⚠️ Code generation errors: In 15-17% of cases the generated code crashes with errors (ValueError, KeyError, TypeError). The dirtier the source data and the harder the question, the higher the risk.
⚠️ Not for simple questions: If the question is "What was Q1 revenue?", three steps are overkill. The method is for multi-hop questions with calculations.
⚠️ Model dependence: The quality of decomposition and cleanup depends on the underlying LLM's abilities. On weak models (7B parameters) results are worse.
How They Tested It
A team from Wuhan University and the University of North Texas tested TABDSR on three datasets: TAT-QA (financial tables), TableBench (hard questions), and their own CalTab151 (built specifically for multi-hop questions). They compared it with 12 methods: pretrained models (TAPEX, OmniTab), fine-tuned LLMs (TableLlama, TableGPT2), and prompt-based approaches (Chain-of-Table, TabSQLify, MIX-SC).
Why build their own dataset? Existing datasets have "leaked" into LLM training data: the models have seen these examples and post inflated scores. CalTab151 fixes that: they took 151 tables, shifted the numbers by ±3-5%, added noise (currency symbols, footnotes), shuffled rows, and replaced cells with null. The questions are new multi-hop ones, written from scratch and checked by humans.
The results produced three insights: (1) TABDSR delivers +8.79%, +6.08%, +19.87% accuracy on the three datasets, and even a 7B model beats 13B competitors; (2) the sanitizer is critical: without table cleanup accuracy drops by 10-20%; (3) the decomposer helps, but not always: on "clean" tables it sometimes gets in the way (an extra step), but on dirty data it consistently improves results. The method works on GPT-4o and DeepSeek-V3 too, so it's not just a crutch for weak models.
Original Prompts from the Paper
Context: The authors published the prompts for each agent in the appendix. Here are the key excerpts.
Query Decomposer Prompt
You are tasked with analyzing a user query to identify the number of sub-questions it contains. Your objectives are to:
1. Identify Sub-Questions: Split complex or compound questions into independent, self-contained sub-questions.
2. Determine the Count: Count the total number of sub-questions identified.
Guidelines:
- Look for conjunctions like "and", "or", or punctuation such as commas that may indicate multiple questions.
- Treat each distinct inquiry or request for information as a separate sub-question.
### Input Format:
**Query**: [User's compound or complex query]
### Output Format:
**Number of Sub-Questions**: [Count]
**Sub-Questions**:
1. [First sub-question]
2. [Second sub-question]
...
### Example:
**Query**: What is the capital of France, and what is its population?
**Number of Sub-Questions**: 2
**Sub-Questions**:
1. What is the capital of France?
2. What is the population of the capital of France?
Table Sanitizer Prompt
You are a table formatting assistant. Your task is to clean up table data and convert it into a format that can be read correctly by the pandas library.
## Requirements:
1. Structural Optimization:
- Reconstruct Nested Tables: Merge multi-level headers based on semantic similarity
- Reconstruct Segmented Tables: Identify and remove separation rows
2. Content Optimization:
- Remove extraneous symbols: %, $, €, commas in numbers
- Remove explanatory notes in parentheses: (approx), (estimated)
- Convert numerical data to int or float
- Standardize blank cells to "null": -, N/A, ???, None, empty string
## Output Format:
{"columns": [...], "data": [[...], [...]]}
PoT-based Reasoner Prompt
Given a table in DataFrame format and a list of sub-questions, generate Python code to answer each sub-question.
Requirements:
1. Load the sanitized table into a Pandas DataFrame
2. For each sub-question:
- Extract relevant data
- Generate Python code for calculation
- Execute and store result
3. Combine results for final answer
4. Use only stable Pandas methods to avoid version inconsistenciesAdaptations and Extrapolations
💡 Adaptation: Decomposition WITHOUT the table as a standalone principle
TABDSR's key insight: take the table out of the context while analyzing the question. This works for any task with a long context + a short request.
First, analyze ONLY my question (ignore the document):
- How many sub-tasks does it contain?
- What data does each one need?
Question: {question}
Now that the structure is clear, I'll give you the document.
Applies to: long documents, reports, contracts, anywhere a question can "get lost" in a big context.
🔧 Technique: Reflection for data cleanup
The sanitizer uses reflection: if the cleaned table doesn't parse, the error goes back to the model to fix.
Clean the table: {table}
[model returns the result]
Check: try loading the result as JSON.
If there's an error, show it and fix it.
Maximum 2 attempts.
💡 Adaptation: The "clean data → code" principle without the full framework
If you don't have Code Interpreter, you can apply the principle by hand:
- Ask the model to describe which cells are "dirty"
- Clean them manually in Excel
- Paste the clean table
- Ask it to do the math
That's not the full TABDSR, but it uses its main insight: data quality determines answer quality.
Resources
Paper: TABDSR: Decompose, Sanitize, and Reason for Complex Numerical Reasoning in Tabular Data
Authors: Changjiang Jiang, Fengchang Yu, Haihua Chen, Wei Lu, Jin Zeng
Institutions: Wuhan University, University of North Texas, Hubei University of Economics
Contact: [email protected]
CalTab151 dataset: available from the authors on request