2016-10-31 11 views
3

私は複数の文字列を持つデータセットを持っています。これらの文字列のそれぞれを[0:1]の範囲にランダムに分布させたフロートに関連付ける必要があります。例:それは入力/決定論的パラメータとして任意の文字列をとらないので、[0:1]で文字列を浮動小数点にハッシュする方法は?

>>> myfunction(string_1) 
0.26756754 
>>> myfunction(string_2) 
0.86764534 

randomは私のニーズを満たしていません。私はハッシュ関数のようなものを探しています。

答えて

2

あなたはこのような何かを試みることができる:

import random 
random.seed(hash(your_string)) 
random.random() 
+0

私はよく理解していれば、random.seed()のみジェネレータを初期化しますが、何も返しませんか? – Vincent

+0

@Vincentそれは正しいです。しかし、 'random.random()'によって返される値の順序に影響します。したがって、最初の乱数は種に直接依存します。 – Barmar

+1

この答えは興味深いですが、2つの制限があります。まず、 'hash'がPythonインストールで異なる結果を返す可能性があるため、Pythonのインストールによって異なる結果が返される可能性があります。第2に、共有ランダムシードを変更するので、プログラムの他の部分が乱数に依存する場合、これは悪い副作用を有する可能性があります。私は自分の答えを推奨するか、少なくとも 'random.seed(hash(your_string))'を 'rnd = random 'に置き換えることを推奨します。ランダム(your_string) '、次に' rnd.random() 'です。 – MiniQuark

3

迅速かつポータブルソリューション:

from zlib import crc32 

def bytes_to_float(b): 
    return float(crc32(b) & 0xffffffff)/2**32 

これは、0.0と1.0の間のfloatにバイト文字列に変換します。あなたは(のpython 3で例えば、)Unicode文字列を使用している場合は、それをエンコードする必要があります。

def str_to_float(s, encoding="utf-8"): 
    return bytes_to_float(s.encode(encoding)) 

>>> str_to_float(u"café") 
0.5963937465567142 

これは、任意のマシン上で同じ結果を与え、任意の必要がありますPythonのバージョン(Python 2.7と3.5でテスト済み)。

注:& 0xffffffffは、符号なしのint結果を保証するためのものです。これは、Pythonバージョンcrc32(b)に応じて、符号付きまたは符号なしintを返す可能性があるため必要です。

編集

あなたはCRC32よりも "ランダム" 何かが、あなたがそのようなSHA256として、代わりにハッシュ関数を使用することができますしたい場合:

from struct import unpack 
from hashlib import sha256 

def bytes_to_float(b): 
    return float(unpack('L', sha256(b).digest()[:8])[0])/2**64 

性能試験

  String length 
Function 7  70  700  7000 
b2f_crc32 0.34 0.38 0.87 5.59  
b2f_md5  0.96 1.08 2.11 11.13 
b2f_sha1 0.99 1.07 1.76 8.37  
b2f_sha256 1.11 1.20 2.60 16.44 
b2f_rnd  6.59 6.55 6.59 6.60  

基本的に、CRC32ソリューションは短い文字列ではるかに高速です(@ user3030010のランダム= RND解)。文字列の長さに関係なく、SHA256より約3倍高速です。 SHA256はMD5よりも遅く、SHA1よりも遅い(非常に短い文字列を除く)。しかし、RNDオプションは文字列の長さに依存しないので、文字列が非常に長い場合は、最も速いオプションになります(ただし、@ user3030010の答えを参照してください)。私のコンピュータでは、2500より長い文字列に対してSHA256 8000文字以上の文字列に対してはCRC32よりも優れています。ここで

timeit.timeit()を使用して、コードです:

from __future__ import print_function 
[...] # define b2f_crc32, b2f_md5 and so on. 
for func in ("b2f_crc32", "b2f_md5", "b2f_sha1", "b2f_sha256", "b2f_rnd"): 
    for length in (7, 70, 700, 7000): 
    t = timeit('b2f(b"%s")'%(b"x"*length), 
       'from __main__ import %s as b2f' % func) 
    print("%.2f"%t, end="\t") 
    print() 
関連する問題