0

我想从子字符串列表和相应的频率列表中创建一个字符串。例如我的df_in样子如下:

+-------------------------+-----------+
|         substr          | frequency |
+-------------------------+-----------+
| ['ham', 'spam', 'eggs'] | [1, 2, 3] |
| ['foo', 'bar']          | [2, 1]    |
+-------------------------+-----------+

我希望我df_out看起来像这样:

+--------------------------------+
|             output             |
+--------------------------------+
| 'ham spam spam eggs eggs eggs' |
| 'foo foo bar'                  |
+--------------------------------+

由于数据集非常大(~22Mio 行),我想尽可能避免 for 循环。有什么优雅的方法可以实现这一目标吗?

非常感谢!

编辑:我目前的做法:

import pyspark.sql.functions as F
import pyspark.sql.types as T

def create_text(l_sub, l_freq):
    l_str = [(a+' ')*b if isinstance(b, int) else (a+' ') for a, b in zip(l_sub, l_freq)]
    return ''.join(l_str)

create_str = F.udf(lambda x, y: create_text(x, y), T.StringType())
df = df.withColumn('output', create_str(df_in.sbustr, df_in.frequency))

问题:

我读到为了加快计算速度,UDF 应该以 pyspark 方式重写。我不知道如何做到这一点。我还发现dtypedf_in.frequencyis array<decimal(4.0)>。所以我试图将这些值转换为intfirst 或int在运行时将它们转换为。

4

1 回答 1

0

检查以下是否适合您:

from pyspark.sql.functions import expr

df.withColumn('output', expr('''
        array_join(flatten(zip_with(`substr`, `frequency`, (x,y) -> array_repeat(x,int(y)))), ' ')
    ''')).show(truncate=False)
+-----------------+---------+----------------------------+
|substr           |frequency|output                      |
+-----------------+---------+----------------------------+
|[ham, spam, eggs]|[1, 2, 3]|ham spam spam eggs eggs eggs|
|[foo, bar]       |[2, 1]   |foo foo bar                 |
+-----------------+---------+----------------------------+

下面是它的工作原理:

  • 用于并排zip_with迭代两个数组substr(as )xfrequency(as ) 并在每个组合上运行以创建.yarray_repeat(x, int(y))yx
  • 展平数组的数组
  • 用空格连接 StringType 的一维数组
于 2019-10-11T11:32:46.477 回答