EnsekiTT Blog

EnsekiTTが書くブログです。

Pythonでデータを圧縮する話

こんにちは、えんせきです。
このあと先輩の車で雪山に出発して、スキーをしてきます。最近ボードよりスキーをやる機会が多いです。

つまりなにしたの?

Pythonで何かを何処かに送る時、データを圧縮したい。ただ、今回扱うのはZipファイルにするとかではなく、バイナリデータを圧縮したバイナリデータに変換する処理。何でやりたかったかというとストリーミング的な配信をする時に圧縮するとした効果があるのか?みたいなのを確かめたかった。
f:id:ensekitt:20180212130550j:plain

今回扱う圧縮方式

zlib, gzip, bz2のPythonに標準で入っている圧縮アルゴリズム

圧縮したデータ

  • 文章データ(TXT長いものと短いもの)
  • 画像データ(PNGのみんな大好きLenna)
  • 音声データ(PCMのクラシック音楽

*1

計測項目

CPU時間と圧縮率

構成

  • インポート
import zlib
import gzip
import bz2

− データの読み込み
− プレビュー(テキスト以外)
− 圧縮
− 結果の確認

短い文章データの圧縮

# 短い文章データの圧縮
s = b'witch which has which witches wrist watch'
print("圧縮前: " + str(len(s)))

t = zlib.compress(s)
%time print("zlib 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = gzip.compress(s)
%time print("gzip 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = bz2.compress(s)
%time print("bz2 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")
圧縮前: 41
zlib 圧縮後: 37, 圧縮率: 10%
CPU times: user 1.95 ms, sys: 1.97 ms, total: 3.92 ms
Wall time: 2.35 ms
gzip 圧縮後: 49, 圧縮率: -20%
CPU times: user 370 µs, sys: 129 µs, total: 499 µs
Wall time: 388 µs
bz2 圧縮後: 62, 圧縮率: -51%
CPU times: user 93 µs, sys: 27 µs, total: 120 µs
Wall time: 127 µs

長い文章データの圧縮

s = open('wagahai.txt', 'rb').read()

print("圧縮前: " + str(len(s)))

t = zlib.compress(s)
%time print("zlib 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = gzip.compress(s)
%time print("gzip 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = bz2.compress(s)
%time print("bz2 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")
圧縮前: 1046582
zlib 圧縮後: 371278, 圧縮率: 65%
CPU times: user 68 µs, sys: 30 µs, total: 98 µs
Wall time: 103 µs
gzip 圧縮後: 366791, 圧縮率: 65%
CPU times: user 67 µs, sys: 35 µs, total: 102 µs
Wall time: 107 µs
bz2 圧縮後: 256755, 圧縮率: 75%
CPU times: user 53 µs, sys: 27 µs, total: 80 µs
Wall time: 103 µs

画像データの圧縮

from PIL import Image
import matplotlib.pyplot as plt

img = Image.open('lena_std.png')
plt.imshow(img)
plt.show()

s = open("lena_std.png", "rb").read()

print("圧縮前: " + str(len(s)))

t = zlib.compress(s)
%time print("zlib 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = gzip.compress(s)
%time print("gzip 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = bz2.compress(s)
%time print("bz2 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")
圧縮前: 625665
zlib 圧縮後: 625702, 圧縮率: 0%
CPU times: user 372 µs, sys: 165 µs, total: 537 µs
Wall time: 933 µs
gzip 圧縮後: 625714, 圧縮率: 0%
CPU times: user 63 µs, sys: 31 µs, total: 94 µs
Wall time: 98.9 µs
bz2 圧縮後: 628505, 圧縮率: 0%
CPU times: user 72 µs, sys: 22 µs, total: 94 µs
Wall time: 98 µs

f:id:ensekitt:20180212130627p:plain

音声データの圧縮 (実行すると音が鳴ります)

import wave
import pyaudio
CHUNK = 1024

wf = wave.open('J.S.Bach-G-air.wav')
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
               channels=wf.getnchannels(),
               rate=wf.getframerate(),
               output=True)

data = wf.readframes(CHUNK)

while len(data)>0:
    
    stream.write(data)
    data = wf.readframes(CHUNK)
    
stream.stop_stream()
stream.close()

p.terminate()

s = open("J.S.Bach-G-air.wav", "rb").read()

print("圧縮前: " + str(len(s)))

t = zlib.compress(s)
%time print("zlib 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = gzip.compress(s)
%time print("gzip 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")

t = bz2.compress(s)
%time print("bz2 圧縮後: " + str(len(t)) + ", 圧縮率: " + str(round((len(s) - len(t))/len(s)*100)) + "%")
圧縮前: 57508096
zlib 圧縮後: 51550956, 圧縮率: 10%
CPU times: user 93 µs, sys: 30 µs, total: 123 µs
Wall time: 127 µs
gzip 圧縮後: 51544949, 圧縮率: 10%
CPU times: user 70 µs, sys: 30 µs, total: 100 µs
Wall time: 106 µs
bz2 圧縮後: 49188258, 圧縮率: 14%
CPU times: user 69 µs, sys: 30 µs, total: 99 µs
Wall time: 104 µs

長い文章は圧倒的な圧縮率でした。
画像や音声はやはり専用のコーデックで不可逆圧縮するとストリーミングには良いとは思うけど、
今回のような可逆圧縮の場合は実はあんまり変わらないのかもしれない。

*1:動画は圧縮済のものが多くてどういう形式をいれるのが適切かよくわからないので除外