Skip to content
Back to skills

Negative Sample Downsampling

ASecurity

Downsamples documents with no entity labels while keeping all positive samples, balancing class distribution in NER training without discarding entity-bearing examples.

  • 61 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 12, 2026
datapython

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add wenmin-wu/ds-skills --skill negative-sample-downsampling --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Negative Sample Downsampling?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Negative Sample Downsampling
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wenmin-wu-negative-sample-downsampling/badge)](https://www.skillsdirectory.com/skills/wenmin-wu-negative-sample-downsampling)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: nlp-negative-sample-downsampling
description: >
  Downsamples documents with no entity labels while keeping all positive samples, balancing class distribution in NER training without discarding entity-bearing examples.
---
# Negative Sample Downsampling

## Overview

In NER datasets, most documents contain no entities — in PII detection, 70-90% of essays are clean. Training on all of them wastes compute on easy negatives and biases the model toward predicting O (non-entity). Downsampling negative documents to 20-33% of their original count while keeping all positive documents rebalances the training set. This is simpler than token-level class weighting and more effective — the model sees more entity examples per epoch, improving recall by 2-5%.

## Quick Start

```python
import random

def downsample_negatives(data, keep_ratio=0.2, entity_label='O'):
    """Keep all positive docs, downsample negative docs."""
    positives = []
    negatives = []
    for doc in data:
        labels = doc['labels'] if isinstance(doc['labels'], list) else doc['labels'].tolist()
        if set(labels) != {entity_label}:
            positives.append(doc)
        else:
            negatives.append(doc)

    n_keep = int(len(negatives) * keep_ratio)
    random.shuffle(negatives)
    sampled_negatives = negatives[:n_keep]

    print(f"Positives: {len(positives)}, Negatives: {len(negatives)} -> {n_keep}")
    return positives + sampled_negatives

# Alternative: filter function for HuggingFace datasets
def filter_no_entity(example, keep_ratio=0.2):
    has_entity = set(example['labels']) != {'O'}
    return has_entity or (random.random() < keep_ratio)

dataset = dataset.filter(filter_no_entity)
```

## Workflow

1. Split documents into positive (contains entities) and negative (all O)
2. Keep all positive documents
3. Randomly sample `keep_ratio` of negative documents
4. Combine and shuffle for training

## Key Decisions

- **keep_ratio**: 0.2-0.33 is typical; too low causes false positives on clean documents
- **Per-epoch resampling**: Resample negatives each epoch for diversity
- **vs class weights**: Downsampling is simpler and works at document level; class weights work at token level
- **Validation**: Do NOT downsample validation set — evaluate on the true distribution

## References

- [DeBERTa3base Training](https://www.kaggle.com/code/valentinwerner/915-deberta3base-training)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.