ECDF сюжет из усеченного md5
В этом документе говорится, что усеченный MD5 распределен равномерно. Я хотел проверить это с помощью PySpark, и сначала я создал 1 000 000 UUID в Python, как показано ниже. Затем урезали первые три символа из MD5. Но график, который я получаю, не похож на кумулятивную функцию равномерного распределения. Я попытался с UUID1 и UUID4, и результаты похожи. Как правильно согласовать равномерное распределение усеченного MD5?
import uuid
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.distributions.empirical_distribution import ECDF
import pandas as pd
import pyspark.sql.functions as f
%matplotlib inline
### Generate 1,000,000 UUID1
uuid1 = [str(uuid.uuid1()) for i in range(1000000)] # make a UUID based on the host ID and current time
uuid1_df = pd.DataFrame({'uuid1':uuid1})
uuid1_spark_df = spark.createDataFrame(uuid1_df)
uuid1_spark_df = uuid1_spark_df.withColumn('hash', f.md5(f.col('uuid1')))\
.withColumn('truncated_hash3', f.substring(f.col('hash'), 1, 3))
count_by_truncated_hash3_uuid1 = uuid1_spark_df.groupBy('truncated_hash3').count()
uuid1_count_list = [row[1] for row in count_by_truncated_hash3_uuid1.collect()]
ecdf = ECDF(np.array(uuid1_count_list))
plt.figure(figsize = (14, 8))
plt.plot(ecdf.x,ecdf.y)
plt.show()
РЕДАКТИРОВАТЬ: я добавил гистограмму. Как вы можете видеть ниже, это больше похоже на нормальное распределение.
plt.figure(figsize = (14, 8))
plt.hist(uuid1_count_list)
plt.title('Histogram of counts in each truncated hash')
plt.show()
2 ответа
Вот быстрый и грязный способ продемонстрировать это:
import hashlib
import matplotlib.pyplot as plt
import numpy as np
import random
def random_string(n):
"""Returns a uniformly distributed random string of length n."""
return ''.join(chr(random.randint(0, 255)) for _ in range(n))
# Generate 100K random strings
data = [random_string(10) for _ in range(100000)]
# Compute MD5 hashes
md5s = [hashlib.md5(d.encode()).digest() for d in data]
# Truncate each MD5 to the first three characters and convert to int
truncated_md5s = [md5[0] * 0x10000 + md5[1] * 0x100 + md5[2] for md5 in md5s]
# (Rather crudely) compute and plot the ECDF
hist = np.histogram(truncated_md5s, bins=1000)
plt.plot(hist[1], np.cumsum([0] + list(hist[0])))
Проблема с моим анализом выше заключалась в том, что я строил гистограмму подсчета усеченного хэша. Правильный способ должен состоять в том, чтобы преобразовать усеченный хеш из шестнадцатеричного в десятичное и увидеть распределение десятичных дробей.
import uuid
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.distributions.empirical_distribution import ECDF
import pandas as pd
import pyspark.sql.functions as f
from pyspark.sql.types import IntegerType
%matplotlib inline
### Generate 1,000,000 UUID1
uuid1 = [str(uuid.uuid1()) for i in range(1000000)]
uuid1_df = pd.DataFrame({'uuid1':uuid1})
uuid1_spark_df = spark.createDataFrame(uuid1_df)
uuid1_spark_df = uuid1_spark_df.withColumn('hash', f.md5(f.col('uuid1')))\
.withColumn('truncated_hash3', f.substring(f.col('hash'), 1, 3))\
.withColumn('truncated_hash3_base10', f.conv('truncated_hash3', 16, 10).cast(IntegerType()))
truncated_hash3_base10_list = [row[0] for row in
uuid1_spark_df.select('truncated_hash3_base10').collect()]
pd_df = uuid1_spark_df.select('truncated_hash3_base10').toPandas()
ecdf = ECDF(truncated_hash3_base10_list)
plt.figure(figsize = (8, 6))
plt.plot(ecdf.x,ecdf.y)
plt.show()
plt.figure(figsize = (8, 6))
plt.hist(truncated_hash3_base10_list)
plt.show()