Existe-t-il des méthodes de compression sans perte pouvant être appliquées aux données de série temporelle à virgule flottante, et surperformera considérablement, par exemple, l'écriture des données sous forme binaire dans un fichier et leur exécution via gzip?
Une réduction de la précision peut être acceptable, mais cela doit se faire de manière contrôlée (c’est-à-dire que je dois pouvoir définir une limite sur le nombre de chiffres à conserver).
Je travaille avec des fichiers de données volumineux qui sont des séries de double
s corrélées, décrivant une fonction du temps (c'est-à-dire que les valeurs sont corrélées). Je n’ai généralement pas besoin de la précision double
complète, mais il se peut que j’ai besoin de plus de float
.
Puisqu'il existe des méthodes spécialisées sans perte d'images/audio, je me demandais s'il existait quelque chose de spécialisé pour cette situation.
Précision: Je recherche des outils pratiques existants plutôt qu’un document décrivant comment mettre en œuvre quelque chose comme ceci. Quelque chose de comparable à gzip en vitesse serait excellent.
Vous voudrez peut-être consulter ces ressources:
Vous voudrez peut-être aussi essayer TIFF Logluv-compressé pour cela, pensais que je ne les avais pas utilisés moi-même.
Voici quelques idées si vous souhaitez créer votre propre algorithme simple:
Puisque vous indiquez que vous avez besoin d'une précision quelque part entre «float» et «double»: vous pouvez mettre à zéro un nombre quelconque de bits les moins significatifs dans les floats à simple et double précision. Les nombres à virgule flottante IEEE-754 sont représentés binaires à peu près comme seeefffffffff
, ce qui représente la valeur
signe * 1.fffffff * 2 ^ (eee).
Vous pouvez mettre à zéro les bits de fraction (f) les moins significatifs. Pour les flotteurs à simple précision (32 bits), il existe 23 fractions de bits dont vous pouvez mettre à zéro jusqu'à 22. Pour les systèmes à double précision (64 bits), il s'agit de 52 et jusqu'à 51. (Si vous mettez à zéro tous les bits , alors les valeurs spéciales NaN et +/- inf seront perdues).
Surtout si les données représentent des valeurs décimales telles que 1.2345, cela aidera à la compression des données. En effet, 1.2345 ne peut pas être représenté exactement comme une valeur à virgule flottante binaire, mais plutôt comme 0x3ff3c083126e978d
, ce qui n’est pas favorable à la compression de données. Si vous coupez les 24 bits les moins significatifs, vous obtiendrez 0x3ff3c08312000000
, qui est toujours précis à environ 9 chiffres décimaux (dans cet exemple, la différence est de 1,6e à 9).
Si vous faites cela sur les données brutes, puis que vous stockez les différences entre les nombres sous-séquentiels, la compression (via gzip) sera encore plus conviviale si les données brutes varient lentement.
Voici un exemple en C:
#include <inttypes.h>
double double_trunc(double x, int zerobits)
{
// mask is e.g. 0xffffffffffff0000 for zerobits==16
uint64_t mask = -(1LL << zerobits);
uint64_t floatbits = (*((uint64_t*)(&x)));
floatbits &= mask;
x = * ((double*) (&floatbits));
return x;
}
Et un en python/numpy:
import numpy as np
def float_trunc(a, zerobits):
"""Set the least significant <zerobits> bits to zero in a numpy float32 or float64 array.
Do this in-place. Also return the updated array.
Maximum values of 'nzero': 51 for float64; 22 for float32.
"""
at = a.dtype
assert at == np.float64 or at == np.float32 or at == np.complex128 or at == np.complex64
if at == np.float64 or at == np.complex128:
assert nzero <= 51
mask = 0xffffffffffffffff - (1 << nzero) + 1
bits = a.view(np.uint64)
bits &= mask
Elif at == np.float32 or at == np.complex64:
assert nzero <= 22
mask = 0xffffffff - (1 << nzero) + 1
bits = a.view(np.uint32)
bits &= mask
return a
Puisque vous demandez des outils existants, peut-être que zfp fera l'affaire.
Méthodes possibles pouvant être utilisées pour la compression en virgule flottante:
Transposer 4xN pour float et 8xN pour double + lz77
Mise en oeuvre: Compression à virgule flottante dans TurboTranspose
voir aussi la compression avec perte liée par l'erreur
Prédicteur (ex. Méthode de contexte fini) + encodage (ex. "Compression d’entier").
Mise en oeuvre: Compression à virgule flottante dans TurboPFor
si possible, convertissez tous les nombres à virgule flottante en nombres entiers (ex. 1.63 -> 163),
puis utilisez la compression entière
Implémentation: Compression entière
Vous pouvez tester toutes ces méthodes, avec vos données, en utilisant l’outil icapp pour Linux et Windows.
Une technique utilisée par les utilisateurs de HDF5 est la "réorganisation", dans laquelle vous regroupez chaque octet pour N valeurs à virgule flottante. Ceci est plus susceptible de vous donner des séquences d'octets répétitives qui compresseront mieux avec gzip, par exemple .
Une deuxième méthode que j'ai trouvée et qui réduit considérablement la taille des données compressées en gzip consiste à convertir d'abord les données au format float16 (demi-précision) , puis à nouveau en float32. Cela produit beaucoup de zéros dans le flux de sortie, ce qui peut réduire la taille des fichiers de 40 à 60% environ après la compression. Une des subtilités est que la valeur float16 maximale est plutôt basse, vous pouvez donc commencer par redimensionner vos données, par exemple. en python
import numpy as np
import math
input = np.array(...)
# format can only hold 65504 maximum, so we scale input data
log2max = int(math.log(np.nanmax(input), 2))
scale = 2**(log2max - 14)
scaled = input * (1./scale)
# do the conversion to float16
temp_float16 = np.array(scaled, dtype=np.float16)
# convert back again and rescale
output = np.array(temp_float16, dtype=np.float32) * scale
Certains tests suggèrent que la différence fractionnaire absolue moyenne entre entrée et sortie pour certaines données est d'environ 0,00019 avec un maximum de 0,00048. Cela correspond à la précision 2 ** 11 de la mantisse.
Vous pouvez utiliser l'algorithme de lissage exponentiel de Holt (qui est un algorithme de compression basé sur la prédiction). Initialement, attribuez un poids aux données et prédisez la valeur suivante. Si les deux données sont identiques, le MSB génère de nombreux zéros en effectuant l'opération XOR