Basit ikili verilerin verimli şekilde sıkıştırılması


27

- 2 n - 1 arası sıralı ikili sayıları içeren bir dosyam var :02n1

0000000000
0000000001
0000000010
0000000011
0000000100
...
1111111111

Şekil 7z bu dosyayı çok verimli bir şekilde sıkıştırmamıştır (n = 20 için, 22 MB, 300 kB'ye sıkıştırılmıştır).

Çok basit veri yapısını tanıyan ve dosyayı birkaç bayta sıkıştıran algoritmalar var mı? Ayrıca CS'nin veya bilgi teorisinin hangi alanını böyle akıllı algoritmalar üzerinde çalıştığını bilmek istiyorum. "AI" çok geniş olurdu, lütfen daha somut anahtar kelimeler önerin.
Simetri kavramı, veri sıkıştırma işleminde temel bir rol oynamalıdır;


11
Bir anlamda en uygun sıkıştırma olan Kolmogorov karmaşıklığını inceleyin (ilave sabite kadar). Ne yazık ki, Kolmogorov karmaşıklığı hesaplanamaz ...
Yuval Filmus

12
Bu verileri neden sıkıştırmanız gerekiyor? İhtiyacın olduğunda istediğin zaman yenileyemez misin? (@YuvalFilmus'un bahsettiği Kolmogorov karmaşıklığı yaklaşımı ile yakından ilgilidir: Kolmogorov karmaşıklığı, esas olarak çıktıyı üreten en kısa programın uzunluğudur).
David Richerby

7
20 yıl önce lisede böyle bir algoritma yazdım. Girişiniz göz önüne alındığında, "birkaç bayta" kadar sıkıştırılmış olacaktı (optimal senaryoda yaklaşık 3.500.000: 1). Ancak, veriler nadiren hiç bu şekilde görünmez, bu nedenle böyle bir algoritmaya sahip olmak pratik değildir. Genel sıkıştırma algoritmaları basit modellerle değil karmaşık modellerle uğraşmak zorundadır. Herkes doğrusal verileri depolamak için bir algoritma yazabilir, ancak ilginç verileri saklamak zordur.
phyrfox

3
N = 20 size 22 MB'ı nasıl veriyor? 4 bayt tamsayıları kullanıyorsanız 4,2 MB
alıyorum

3
@JiK oh, tamam. tek bir biti temsil etmek için 8 bit kullanmak yerine, ilk sıkıştırma kavramı olacaktır.
njzk2

Yanıtlar:


27

n

0
1
1
1
1
...

O(n)O(1)

nNn

DW'nun “hepsi ya da hiçbiri” önerisinden farklı olarak, çalışma uzunluğu kodlamasıyla delta sıkıştırma aslında düşük çözünürlüklü ses gibi bazı basit gerçek dünyadaki içerik türleri için makul sıkıştırma oranları sağlayabilir. (Bu nedenle düşük kaliteli, çok düşük gecikmeli ve düşük güçlü ses sıkıştırması için uygundur.)


44

Elbette, algoritmalar var. İşte algoritmam:

  1. 02n1nn

  2. Değilse, 1 bit yazın, ardından dosyanın 7z sıkıştırmasını yazın.

Bu, belirli bir yapının dosyaları için son derece verimlidir.

Mesele şu ki: veri sıkıştırmada bedava öğle yemeği yok. Diğerlerini daha kötü sıkıştırma pahasına, bir tür dosyayı iyi sıkıştıran bir sıkıştırma algoritması oluşturabilirsiniz. Ancak, priori ile sıkıştıracağınız dosyaların yapıları hakkında bir şey biliyorsanız, algoritmanızı o belirli dosya türü için optimize edebilirsiniz.

Alan "veri sıkıştırma" dir. etiketimize bakın ve veri sıkıştırma hakkındaki kitapları okuyun.


5
Kompresörün görevi ortak kalıpları tanımak ve bunlardan yararlanmaktır. Bu model nadir değildir veya belirsiz değildir. Bu yüzden neden sömürülmediğini sormak doğal bir soru. Ona bir takas olduğunu söylemek ya da ona bu model dışında her şeyde başarısız olan bir algoritma vermek, tam bir sonuçtur.
Mehrdad,

17
Bana çok nadir görünüyor. Bu, gerçek hayattaki verilerde nadiren ortaya çıkar, iyi kompresörlerin beklediği kalıp türlerine kıyasla.
amalloy

17
@Mehrdad Bu keskin bir koparma değil: tüm mesele . Basit bir şekilde oluşturulan ve basit bir şekilde kontrol edilen X kalıpları için, bu kalıbı arayan ve onunla ilgilenen bir sıkıştırma algoritması vardır. Yani bu, "Böyle bir X ile ilgilenen bir sıkıştırma algoritması var mı?" Elbette, her zaman biraz daha karmaşık kalıpları arayan bir algoritma vardır. Ve bir tane var bu, bir de biraz daha karmaşık modeller için görünüyor sonsuza . İtirazınız köklü değil.
David Richerby

Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
Gilles 'SO- kötülük'

Bu ilkenin aşırı bir uygulaması, herhangi bir boyuttaki herhangi bir dosya veya koleksiyonun basit bir şekilde 160 bit veri verisi ile temsil edildiği (sıkıştırıldığı) acı mıknatıs bağlantılarıdır. Elbette karmaşanın oluşma riski vardır.
slebetman

17

BWT (Burrows – Wheeler dönüşümü) kullanan herhangi bir şey, bunu oldukça iyi sıkıştırabilir.

Hızlı Python sınavım:

>>> import gzip
>>> import lzma
>>> import zlib
>>> import bz2
>>> import time
>>> dLen = 16
>>> inputData = '\n'.join('{:0{}b}'.format(x, dLen) for x in range(2**dLen))
>>> inputData[:100]
'0000000000000000\n0000000000000001\n0000000000000010\n0000000000000011\n0000000000000100\n000000000000010'
>>> inputData[-100:]
'111111111111010\n1111111111111011\n1111111111111100\n1111111111111101\n1111111111111110\n1111111111111111'
>>> def bwt(text):
    N = len(text)
    text2 = text * 2
    class K:
        def __init__(self, i):
            self.i = i
        def __lt__(a, b):
            i, j = a.i, b.i
            for k in range(N): # use `range()` in Python 3
                if text2[i+k] < text2[j+k]:
                    return True
                elif text2[i+k] > text2[j+k]:
                    return False
            return False # they're equal

    inorder = sorted(range(N), key=K)
    return "".join(text2[i+N-1] for i in inorder)

>>> class nothing:
    def compress(x):
        return x

>>> class bwt_c:
    def compress(x):
        return bwt(x.decode('latin_1')).encode('latin_1')

>>> for first in ('bwt_c', 'nothing', 'lzma', 'zlib', 'gzip', 'bz2'):
    fTime = -time.process_time()
    fOut = eval(first).compress(inputData)
    fTime += time.process_time()
    print(first, fTime)
    for second in ('nothing', 'lzma', 'zlib', 'gzip', 'bz2'):
        print(first, second, end=' ')
        sTime = -time.process_time()
        sOut = eval(second).compress(fOut)
        sTime += time.process_time()
        print(fTime + sTime, len(sOut))

bwt_c 53.76768319200005
bwt_c nothing 53.767727423000224 1114111
bwt_c lzma 53.83853460699993 2344
bwt_c zlib 53.7767307470001 5930
bwt_c gzip 53.782549449000044 4024
bwt_c bz2 54.15730512699997 237
nothing 6.357100005516259e-05
nothing nothing 0.0001084830000763759 1114111
nothing lzma 0.6671195740000258 27264
nothing zlib 0.05987233699988792 118206
nothing gzip 2.307255977000068 147743
nothing bz2 0.07741139000017938 187906
lzma 0.6767229399999906
lzma nothing 0.6767684639999061 27264
lzma lzma 0.6843232409999018 27324
lzma zlib 0.6774435929999072 27280
lzma gzip 0.6774431810001715 27292
lzma bz2 0.6821310499999527 27741
zlib 0.05984937799985346
zlib nothing 0.05989508399989063 118206
zlib lzma 0.09543156799986718 22800
zlib zlib 0.06264000899977873 24854
zlib gzip 0.0639041649999399 24611
zlib bz2 0.07275534999985211 21283
gzip 2.303239570000187
gzip nothing 2.303286251000145 147743
gzip lzma 2.309592880000082 1312
gzip zlib 2.3042639900002087 2088
gzip gzip 2.304663197000309 1996
gzip bz2 2.344431411000187 1670
bz2 0.07537686600016968
bz2 nothing 0.07542737000017041 187906
bz2 lzma 0.11371452700018381 22940
bz2 zlib 0.0785322910001014 24719
bz2 gzip 0.07945505000020603 24605
bz2 bz2 0.09332576600013454 27138

(Buradaki sayılar 'first_compressor second_compressor time_taken bytes_out' şeklindedir)

(BWT buradan alındı )

Bu hala 'sadece bir kaç bayt değil', fakat yine de sadece gzipten daha iyidir. Örneğin, BWT + bz2, 1114111'den 237 bayta kadar iniyor.

Ne yazık ki, BWT'ler çok yavaş ve birçok uygulama için hafızada aç. Özellikle bu Python'da saf bir uygulama olduğu için - makinemde 2 ** 20'den önce RAM'im bitiyor.

Pypy ile tam 2 ** 20 girişi çalıştırabildim ve bunu BWT ve ardından bz2 ile 2611 bayta sıkıştırıyor. Ancak 3 dakikadan fazla süren ve 4GB'tan fazla RAM kullanılmışken ...

Ayrıca maalesef, bu yaklaşım hala O (2 ^ n) çıktı alanıdır, görünecektir - en azından eğri uydurma 1..20.


evalYaparak kurtulabilirsin : for first in (bwt_c, nothing, lzma, zlib, gzip, bz2):ve fOut = first.compress(inputData).
kasperd

@ kasperd - bu durumda isimleri nasıl yazdırabilirim? Şahsen, bir değerlendirme yapmak isimleri ve referansları senkronize etmeyi denemekten daha basit (ve daha az hataya eğilimli).
TLW

5
Önce bwt, sonra bz2 bunu aşırı derecede sıkıştırır. Bu son derece garip bir davranış ve muhtemelen bu kesin kalıptan kaynaklanıyor. Bwt'yi iki kez yaptığınızı (bz2, BWT'yi temel alır), genellikle daha kötü bir sıkıştırma ile sonuçlandığını unutmayın . Ayrıca, bwt'nin bugün genellikle 4 times block sizebellekte (örneğin bunun için ~ 4MB) çalıştığını ve >10 MB/sbirçok uygulama için oldukça kullanışlı olan (böyle bir bwt kütüphanesi / sıkıştırma algoritmasının yazarıyım ) hızlarında çalıştığını unutmayın . Gzip'in bile çok iyi sıkıştırılabilir sonuçlar ürettiğini unutmayın. Paylaşım için teşekkürler, iki kez bwt kullanımı ile ilgili herhangi bir araştırma bilmiyorum.
Christoph

3
@Christoph - bz2'nin BWT'ye dayandığını biliyorum ... Ben aslında 'sadece bz2'yi kullan' etkisine bir cevap yazmaya başladım, ancak neredeyse beklediğim kadar sıkışmadığını gördüm, ha ' 've kendi BWT'm daha iyisini yapıp yapmayacağını görmeye karar verdim. Sadece çıktı için bir kompresöre ihtiyacım vardı ve 'ne olacağını görmek için farklı kompresörler deneyebilir' diye gitti.
TLW

1
@ Christoph - Başka bir baktım. Bu verilerin 2 bwt'lik kısmı RLE kodlamasına son derece uygun bir şey üretir . Eğer gerekli RLE çiftlerinin sayısını ise, olduğu gibi 0, 1, 2, ... 16 bit girişinde iç içe BWTs, sen 622.591 1.081.343 83 olsun ...
TLW

10

PNG kodlaması tam olarak istediğiniz şeyi yapar. Sadece son derece organize veriler değil, gerçek hayat verileri üzerinde de çalışır.

PNG'de, her satır 4'ü belirtilen bir filtre ile kodlanmıştır. Bunlardan biri "bu pikseli, değeri ile üstündeki pikselin değeri arasındaki fark olarak kodlayın." Filtrelemeden sonra, veriler DEFLATE kullanılarak sıkıştırılır.

Bu filtreleme, cevabında soldabounda tarafından belirtilen Delta Kodlamanın spesifik bir örneğidir , daha uzun DEFLATE algoritmasıyla takip ettiğiniz Çalıştırma Uzunluğu Kodlaması ile izlemek yerine. Aynı hedefi gerçekleştirir, yalnızca DEFLATE hala istenen sıkıştırma oranlarını sağlarken daha geniş bir girdi yelpazesini idare eder.

Bilimsel verilerde sıklıkla kullanılan + DEFLATE filtresinin etkili olmadığı başka bir araç ise RICE kodlamasıdır. RICE'ta, önce bir değer bloğu alırsınız, önce en önemsiz bitlerin hepsini, ardından en önemsiz bitlerin hepsini, en az anlamlı bitlere kadar. Sonra sonucu sıkıştırırsınız. PNG stil filtreleme kadar etkili olmayacak verileriniz için (verileriniz PNG filtreleme için mükemmel olduğundan ), ancak birçok bilimsel veri için iyi sonuçlara yol açma eğilimindedir. Pek çok bilimsel veride, en önemli bitin yavaş yavaş değişme eğiliminde olduğunu, en düşük değerin ise neredeyse rasgele olduğunu görüyoruz. Bu, yüksek oranda öngörülebilir verileri yüksek düzeyde entropik verilerden ayırır.

0000000000       00000  most significant bits
0000000001       00000
0000000010  =>   00000
0000000011       00000
0000000100       00000
                 00000
                 00000
                 00001
                 00110
                 01010 least significant bits

5

Belirli yapıları arayan herhangi bir pratik algoritma, yalnızca içine kodlanan yapılarla sınırlı olacaktır. Bu özel sekansı tanımak için 7z'yi kullanabilirsiniz, ancak bu spesifik yapının gerçek hayatta ne sıklıkla gerçekleşeceği? Bu giriş için girişleri kontrol etmek için gereken süreyi garanti etmek yeterli değildir.

Bir kenara pratikler, mükemmel bir kompresör verilen bir çıktı üreten en kısa programı oluşturmaya çalışan bir algoritma olarak algılanabilir. Söylemeye gerek yok, bunu yapmanın pratik bir yolu yoktur. Tüm olası programların kaba kuvvetli bir numaralandırmasını denediyseniz ve istenen çıktının üretilip üretilmediğini kontrol etseniz bile ( tamamen delice bir fikir değil ), belirli bir sayıdan sonra deneme çalışmalarını iptal etmeniz gerekeceği anlamına gelen Halting sorunuyla karşılaşacaksınız. Yürütme adımlarının, bu programın istenen çıktıları kesinlikle üretip üretemediğini bilmeden önce.

Böyle bir kaba kuvvet yaklaşımı için arama ağacı, program uzunluğu ile üssel olarak büyür ve en basit programlar dışında (5-7 talimat uzunluğunda bir şey gibi) herkes için pratik değildir.


n

1
nnn+1n1

Eh, Mathematica gibi araçlar için fonksiyonları bulmak pek ... dizilerinin
Raphael

3

Sıkıştırma oranları tamamen hedeflenen dekompresöre bağlıdır. Dekompresör, sıralı 4 bayt sayıları sayı başına 4 bayttan daha kompakt olarak çözemezse, siz SOL'sunuz.

Sıralı sayıların kodlanmasına izin verebilecek çeşitli şeyler vardır. Örneğin bir diferansiyel kodlama. Bir seferde n bayt alırsınız, sonra bitlerin farkını veya xor değerini alırsınız ve sonucu sıkıştırırsınız. Bu, her bayt sayımı için denemek için buraya 4 seçenek ekler: kimlik a'[i] = a[i]; fark a'[i] = a[i-1]-a[i]; ters fark a'[i] = a[i]-a[i-1]; ve xor a'[i] = a[i]^a[i-1]. Bu, yöntemleri seçmek için 2 bit eklemek ve 4 seçeneğin 3'ü için bir bayt sayısı anlamına gelir.

Ancak, tüm veriler sabit uzunluklu kayıtların bir sırası değildir. Diferansiyel kodlama bunun için bir anlam ifade etmemektedir (kompresör ampirik olarak bir miktar veri için çalıştığını ispat edemediği sürece).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.