Data Analysis¶
Before deciding on filter thresholds, it helps to understand the statistical profile of your dataset. dj-analyze computes distributions and correlations for all operator-produced statistics, enabling data-driven threshold decisions.
For the full parameter list, see Global Configuration Reference.
CLI¶
Basic Usage¶
Run the analyzer with an existing recipe:
dj-analyze --config path/to/your-recipe.yaml
Auto Mode¶
No dedicated analysis recipe needed—automatically uses all stats-producing Filters on a dataset subset:
dj-analyze --auto --dataset_path your-dataset.jsonl --auto_num 1000
--auto_num: Number of samples to analyze (default 1000). Good for quick distribution overview.
Python API¶
Basic: Load Config and Run¶
from data_juicer.config import init_configs
from data_juicer.core import Analyzer
cfg = init_configs(args=['--config', 'my-recipe.yaml'])
analyzer = Analyzer(cfg)
dataset = analyzer.run()
# Access results
print(analyzer.overall_result)
Analyze an Existing Dataset¶
Wrap a Hugging Face Dataset in NestedDataset to use it with Analyzer:
from data_juicer.core import Analyzer, NestedDataset
from data_juicer.config import init_configs
cfg = init_configs(args=[
'--config', 'my-recipe.yaml',
'--export_path', './analysis-output/stats.jsonl',
])
analyzer = Analyzer(cfg)
dataset = NestedDataset(NestedDataset.from_json('my-data.jsonl'))
analyzed = analyzer.run(dataset=dataset)
Use Statistics in Memory¶
Call a Filter with reduce=False to compute per-row statistics, retain all input rows, and return a dataset for further use in your script. The caller controls dataset and report export; enabled dataset caching uses disk storage.
from data_juicer.core import NestedDataset
from data_juicer.ops.filter import TextLengthFilter
from data_juicer.utils.constant import Fields, StatsKeys
dataset = NestedDataset(NestedDataset.from_json('my-data.jsonl'))
analyzed = TextLengthFilter().run(dataset=dataset, reduce=False)
stats = analyzed[Fields.stats]
avg_len = sum(s[StatsKeys.text_len] for s in stats) / len(stats) if len(stats) else 0
print(f"Average text length: {avg_len:.2f}")
Manual Analysis Pipeline¶
For full control over the analysis logic, use the underlying components directly:
from data_juicer.ops.filter import LanguageIDScoreFilter, TextLengthFilter
from data_juicer.analysis import OverallAnalysis, ColumnWiseAnalysis
from data_juicer.core import NestedDataset
dataset = NestedDataset(NestedDataset.from_json('my-data.jsonl'))
# Compute stats only: reduce=False below disables filtering
filters = [
TextLengthFilter(min_len=0, max_len=999999),
LanguageIDScoreFilter(lang='en', min_score=0.0),
]
for f in filters:
dataset = f.run(dataset=dataset, reduce=False) # compute stats only, no filtering
# Run analysis
output_dir = './my-analysis'
overall = OverallAnalysis(dataset, output_dir)
result = overall.analyze()
print(result)
column_wise = ColumnWiseAnalysis(dataset, output_dir, overall_result=result)
column_wise.analyze()
Dynamic Analysis Dimensions¶
Programmatically choose analysis operators based on data modality—useful for automated pipelines:
from data_juicer.core import Analyzer, NestedDataset
from data_juicer.config import init_configs
dataset = NestedDataset(NestedDataset.from_json('input.jsonl'))
sample = dataset[0]
# Build analysis config based on data modality
process_config = []
# Text statistics
if 'text' in sample:
process_config.extend([
{'text_length_filter': {'min_len': 0, 'max_len': 999999}},
{'language_id_score_filter': {'lang': 'en', 'min_score': 0.0}},
{'alphanumeric_filter': {'min_ratio': 0.0}},
])
# Image statistics
if 'images' in sample and sample['images']:
process_config.extend([
{'image_shape_filter': {'min_width': 0, 'min_height': 0}},
{'image_aspect_ratio_filter': {'min_ratio': 0.0, 'max_ratio': 999}},
])
cfg = init_configs(args=[
'--auto',
'--dataset_path', 'input.jsonl',
'--export_path', './analysis/stats.jsonl',
], allow_auto=True)
cfg.process = process_config
# Auto mode analyzes at most auto_num rows (default 1000).
analyzer = Analyzer(cfg)
analyzed = analyzer.run(dataset=dataset)
Analysis Output¶
The analyzer produces:
Overall statistics table: count, mean, std, min, max for each metric
Distribution plots: histogram for each metric
Correlation analysis: heatmap of metric correlations
Plots and overall tables are saved in analyzer.analysis_path (<cfg.work_dir>/analysis); the resolved work_dir includes job_id. The statistics dataset is exported according to export_path.
Analyzer.run(..., skip_export=True) saves the statistics dataset and skips export of overall tables and plots. Analyzer creates the working directory and backs up the configuration during initialization.
Which Operators Participate¶
The Analyzer processes two types of operators:
Filter operators that produce stats in the
__dj__stats__field (most Filters do)Tagging operators that produce labels in the
__dj__meta__field
Registry markers:
NON_STATS_FILTERS: Filters that do NOT produce statsTAGGING_OPS: Operators that produce tags
Distributed Analysis¶
Set executor_type: ray to use RayAnalyzer with native Ray aggregation:
dj-analyze --config demos/analyze_simple/ray_analyzer.yaml
RayAnalyzer does not produce per-column distribution plots or correlation analysis. See Distributed Processing.
Font Configuration¶
If distribution plots show “Glyph missing” warnings:
export ANALYZER_FONT="Heiti SC" # default; supports CJK characters
Next Steps¶
Adjust thresholds interactively? Use Web Playground
Ready to process? See Processing Data
Large-scale analysis? See Distributed Processing