Data Compression Basics
Compression shrinks data by removing redundancy, split into lossless and lossy families.
Why compression is possible
Real data is rarely random: letters, pixels, and samples follow patterns and repeat. Compression exploits this redundancy, encoding predictable parts with fewer bits. The source entropy bounds how far lossless compression can go.
Lossless compression
Lossless methods reconstruct the original exactly. They combine modeling (predicting the next symbol) with entropy coding (spending bits in proportion to surprise). Examples include Huffman coding, arithmetic coding, and dictionary methods like LZ77.
Lossy compression
Lossy methods discard information the human eye or ear will not miss, achieving far smaller sizes. JPEG, MP3, and video codecs transform data, quantize the less important components, then entropy-code what remains.
Two-stage structure
Most compressors have a modeling stage that finds structure — repeated strings, smooth gradients, silence — and a coding stage that turns the model's predictions into a compact bitstream. Better models yield smaller output.
No free lunch
No lossless algorithm can shrink every possible input; by counting, some inputs must grow. Compression works only because real data occupies a small, structured corner of the space of all possible bit strings.
Measuring it
The compression ratio compares original to compressed size. For lossy formats, ratio trades against fidelity, measured by metrics or by perceptual quality, and the right point depends on the use.
import zlib
data = b'aaaaaaaaaabbbbbbbbbb' * 100
c = zlib.compress(data)
print(len(data), '->', len(c)) # large -> small