我使用python的sklearn包创建了一个随机森林模型,其中将种子设置为例如1234
。为了生产模型,我们使用pyspark。如果我要传递相同的超参数和相同的种子值,即1234
,它将得到相同的结果吗?
基本上,随机种子数在不同系统之间起作用吗?
答案 0 :(得分:3)
好吧,这正是真的可以通过提供的一些实验和代码段来解决的问题...
无论如何,似乎一般的答案是坚定的否:不仅在Python和Spark MLlib之间,甚至在Spark子模块之间,或者在Python和Numpy之间...
以下是一些可重现的代码,它们在Databricks community cloud中运行(其中pyspark
已被导入并且相关上下文已初始化):
import sys
import random
import pandas as pd
import numpy as np
from pyspark.sql.functions import rand, randn
from pyspark.mllib import random as r # avoid conflict with native Python random module
print("Spark version " + spark.version)
print("Python version %s.%s.%s" % sys.version_info[:3])
print("Numpy version " + np.version.version)
# Spark version 2.3.1
# Python version 3.5.2
# Numpy version 1.11.1
s = 1234 # RNG seed
# Spark SQL random module:
spark_df = sqlContext.range(0, 10)
spark_df = spark_df.select("id", randn(seed=s).alias("normal"), rand(seed=s).alias("uniform"))
# Python 3 random module:
random.seed(s)
x = [random.uniform(0,1) for i in range(10)] # random.rand() gives exact same results
random.seed(s)
y = [random.normalvariate(0,1) for i in range(10)]
df = pd.DataFrame({'uniform':x, 'normal':y})
# numpy random module
np.random.seed(s)
xx = np.random.uniform(size=10) # again, np.random.rand(10) gives exact same results
np.random.seed(s)
yy = np.random.randn(10)
numpy_df = pd.DataFrame({'uniform':xx, 'normal':yy})
# Spark MLlib random module
rdd_uniform = r.RandomRDDs.uniformRDD(sc, 10, seed=s).collect()
rdd_normal = r.RandomRDDs.normalRDD(sc, 10, seed=s).collect()
rdd_df = pd.DataFrame({'uniform':rdd_uniform, 'normal':rdd_normal})
这是结果:
Python原生3:
# df
normal uniform
0 1.430825 0.966454
1 1.803801 0.440733
2 0.321290 0.007491
3 0.599006 0.910976
4 -0.700891 0.939269
5 0.233350 0.582228
6 -0.613906 0.671563
7 -1.622382 0.083938
8 0.131975 0.766481
9 0.191054 0.236810
脾气暴躁:
# numpy_df
normal uniform
0 0.471435 0.191519
1 -1.190976 0.622109
2 1.432707 0.437728
3 -0.312652 0.785359
4 -0.720589 0.779976
5 0.887163 0.272593
6 0.859588 0.276464
7 -0.636524 0.801872
8 0.015696 0.958139
9 -2.242685 0.875933
Spark SQL:
# spark_df.show()
+---+--------------------+-------------------+
| id| normal| uniform|
+---+--------------------+-------------------+
| 0| 0.9707422835368164| 0.9499610869333489|
| 1| 0.3641589200870126| 0.9682554532421536|
| 2|-0.22282955491417034|0.20293463923130883|
| 3|-0.00607734375219...|0.49540111648680385|
| 4| -0.603246393509015|0.04350782074761239|
| 5|-0.12066287904491797|0.09390549680302918|
| 6| 0.2899567922101867| 0.6789838400775526|
| 7| 0.5827830892516723| 0.6560703836291193|
| 8| 1.351649207673346| 0.7750229279150739|
| 9| 0.5286035772104091| 0.6075560897646175|
+---+--------------------+-------------------+
Spark MLlib:
# rdd_df
normal uniform
0 -0.957840 0.259282
1 0.742598 0.674052
2 0.225768 0.707127
3 1.109644 0.850683
4 -0.269745 0.414752
5 -0.148916 0.494394
6 0.172857 0.724337
7 -0.276485 0.252977
8 -0.963518 0.356758
9 1.366452 0.703145
当然,即使以上结果相同,也不能保证scikit-learn中的Random Forest的结果与pyspark Random Forest的结果完全相同 ...
尽管答案是否定的,但我真的看不到它如何影响任何ML系统的部署,即,如果结果关键地取决于RNG,那么肯定可以不对...
答案 1 :(得分:2)
在过去,PRNG的可移植性是无法提供的。机器架构,溢出处理以及所用算法和所用语言所采用的实现方式方面的差异意味着,即使名义上基于相同的数学公式,结果也可能并且确实有所不同。 1979年,Schrage(请参阅第1194页,here)创建了一个便携式素模乘积线性同余生成器,并表明可以用与机器和语言无关的方式来实现它……“只要机器可以表示所有整数,在-2 31 到2 3 -1之间。”他给出了实施者可以用来测试其实现的特定检查,并指定应为第1000个 结果赋予特定的种子值。自Schrage开展工作以来,将算法设计为与平台和语言无关的做法已成为一种常态。
Python的默认生成器是梅森扭曲器,Mersenne Twister home page上提供了多种平台和语言无关的MT实现。如果Python将来会切换其默认生成器,那么除非您使用上面链接中提供的一种独立的Python实现,否则不能保证兼容性。
答案 2 :(得分:1)
是的,(伪)随机数生成器是完全确定性的,并且总是在给定相同输入的情况下返回相同的输出。当然,如果跨系统生成随机数的环境相同(不同版本可能会有所不同)。