我想为字母数字的DataFrame列计算相对模数。
在纯Python中,我可以执行类似int(str, base)
的操作将其转换为数字值。然后只需应用模数%
。
例如:
>>> int('5c43466dc6d2870001fk8205', 24) % 64
5L
我当然想避免使用Python中的UDF,而可能仅使用Spark函数。
例如,我的数据源可以是这样的:
df = spark.createDataFrame(
[
'5c43466dc6d2870001fk8205',
'5c43466dc6d2870001fk8206',
'5c43466dc6d2870001fk8207'
],
StringType()
)
我想要一个新列,其值为[5L, 6L, 7L]
答案 0 :(得分:2)
与@EnzoBnl pointed out一样,有一个函数pyspark.sql.functions.conv
将:
将字符串列中的数字从一个基数转换为另一个基数。
但是正如他指出的那样,您的人数太大,无法正常使用此功能。
但是,您可以使用一些数学运算将计算简化为易于处理的内容。
可以显示 1 以24为基数的数字mod 64等于该数字模数64的最后两位。也就是说,您可以使用以下代码获得所需的输出:
from pyspark.sql.functions import conv, lit, substring
df.withColumn(
"mod",
conv(substring("value", -2, 2), 24, 10).cast("long") % lit(64).cast("bigint")
).show(truncate=False)
#+------------------------+---+
#|value |mod|
#+------------------------+---+
#|5c43466dc6d2870001fk8205|5 |
#|5c43466dc6d2870001fk8206|6 |
#|5c43466dc6d2870001fk8207|7 |
#+------------------------+---+
需要强制转换为long
,我有消息来源解释原因,但目前似乎找不到。
d
是数字的以24为底的表示形式,则为d % 64 = d_low % 64
,其中d_low
代表d
的两个最低有效数字。 让我们拨打我们的24号码d
。如果d
有n
位数字,则可以用十进制(以10为底)表示,如下所示:
d = sum( di * 24**i for i in range(n) )
其中di
代表以10为底的ith
中的d
位。
我们可以等效地将该总和写为低2位(2个最低有效数字)和高n-2
位(给定n > 2
)的总和:
d = sum( di * 24**i for i in range(2) ) + sum( di * 24**i for i in range(2, n) )
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# let's call this d_low let's call this d_high
d = d_low + d_high
请注意,通过排除d_high
可以简化24**2
d_high = (24**2) * sum( di * 24**(i-2) for i in range(2, n) )
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# for simplicity, let's call this x
d_high = (24**2) * x
因此我们有:
d = d_low + (24**2) * x
现在您要计算的数字为d % 64
。
d % 64 = (d_low + (24**2) * x) % 64
如here,(x + y) % z = ( x % z + y % z ) % z
所示,因此以上内容可以写为:
d % 64 = (d_low % 64 + ((24**2) * x) % 64) % 64
现在观察到24**2
是64
的偶数倍(因为它们都包含2**6
。
24**2=((2**3)*3)**2=((2**6)*(3**2))=64*9`.
因此(24**2) % 64 = 0
。然后是((24**2) * x) % 64 = 0
。
因此,我们现在可以编写:
d % 64 = (d_low % 64 + 0 % 64) % 64
= (d_low % 64 + 0) % 64
= d_low % 64
答案 1 :(得分:1)
有一个内置函数可以在两个碱基之间进行转换:conv(num, from_base, to_base)
,conv('100', 2, 10)
给出4
。我将其指向documentation。
假设您操作的是基数24,则可以使用n
实现“模substr(conv(value, 24, n), -1)
”的运算。
但是我认为事情将无法进行,因为在您的情况下,值要优于2^64-1
,即以24为底的l12ee5fn0ji1if
。