如何添加数据框的一列的字符串,并形成另一列将具有原始列的增量值的列

时间:2018-04-26 16:03:00

标签: python apache-spark dataframe pyspark

我有一个DataFrame,我在下面粘贴数据:

+---------------+--------------+----------+------------+----------+
|name           |      DateTime|       Seq|sessionCount|row_number|
+---------------+--------------+----------+------------+----------+
|            abc| 1521572913344|        17|           5|         1|
|            xyz| 1521572916109|        17|           5|         2|
|           rafa| 1521572916118|        17|           5|         3|
|             {}| 1521572916129|        17|           5|         4|
|     experience| 1521572917816|        17|           5|         5|
+---------------+--------------+----------+------------+----------+

'name'的类型为字符串。我想要一个新列"effective_name",其中包含"name"的增量值,如下所示:

+---------------+--------------+----------+------------+----------+-------------------------+
|name          | DateTime |sessionSeq|sessionCount|row_number |effective_name|
+---------------+--------------+----------+------------+----------+-------------------------+
|abc            |1521572913344 |17        |5           |1         |abc                      |
|xyz            |1521572916109 |17        |5           |2         |abcxyz                   |
|rafa           |1521572916118 |17        |5           |3         |abcxyzrafa               |
|{}             |1521572916129 |17        |5           |4         |abcxyzrafa{}             |
|experience     |1521572917816 |17        |5           |5         |abcxyzrafa{}experience   |
+---------------+--------------+----------+------------+----------+-------------------------+

新列包含其先前name列值的增量串联。

2 个答案:

答案 0 :(得分:1)

您可以使用pyspark.sql.WindowclientDateTimepyspark.sql.functions.concat_wspyspark.sql.functions.collect_list排序来实现此目的:

import pyspark.sql.functions as f
from pyspark.sql import Window

w = Window.orderBy("DateTime")  # define Window for ordering

df.drop("Seq", "sessionCount", "row_number").select(
    "*",
    f.concat_ws(
        "",
        f.collect_list(f.col("name")).over(w)
    ).alias("effective_name")
).show(truncate=False)
#+---------------+--------------+-------------------------+
#|name           |      DateTime|effective_name           |
#+---------------+--------------+-------------------------+
#|abc            |1521572913344 |abc                      |
#|xyz            |1521572916109 |abcxyz                   |
#|rafa           |1521572916118 |abcxyzrafa               |
#|{}             |1521572916129 |abcxyzrafa{}             |
#|experience     |1521572917816 |abcxyzrafa{}experience   |
#+---------------+--------------+-------------------------+

我放弃了"Seq""sessionCount""row_number"以使输出显示更友好。

如果您需要为每个组执行此操作,则可以向partitionBy添加Window。在这种情况下,您希望按sessionSeq进行分组,您可以执行以下操作:

w = Window.partitionBy("Seq").orderBy("DateTime")

df.drop("sessionCount", "row_number").select(
    "*",
    f.concat_ws(
        "",
        f.collect_list(f.col("name")).over(w)
    ).alias("effective_name")
).show(truncate=False)
#+---------------+--------------+----------+-------------------------+
#|name           |      DateTime|sessionSeq|effective_name           |
#+---------------+--------------+----------+-------------------------+
#|abc            |1521572913344 |17        |abc                      |
#|xyz            |1521572916109 |17        |abcxyz                   |
#|rafa           |1521572916118 |17        |abcxyzrafa               |
#|{}             |1521572916129 |17        |abcxyzrafa{}             |
#|experience     |1521572917816 |17        |abcxyzrafa{}experience   |
#+---------------+--------------+----------+-------------------------+

如果您更喜欢使用withColumn,则上述内容相当于:

df.drop("sessionCount", "row_number").withColumn(
    "effective_name",
    f.concat_ws(
        "",
        f.collect_list(f.col("name")).over(w)
    )
).show(truncate=False)

<强>解释

您希望在多行上应用函数,这称为聚合。使用任何聚合,您需要定义要聚合的行和顺序。我们使用Window执行此操作。在这种情况下,w = Window.partitionBy("Seq").orderBy("DateTime")会按Seq对数据进行分区,并按DateTime排序。

我们首先在窗口上应用聚合函数collect_list("name")。这会收集name列中的所有值,并将它们放在列表中。插入顺序由Window的顺序定义。

例如,此步骤的中间输出将是:

df.select(
    f.collect_list("name").over(w).alias("collected")
).show()
#+--------------------------------+
#|collected                       |
#+--------------------------------+
#|[abc]                           |
#|[abc, xyz]                      |
#|[abc, xyz, rafa]                |
#|[abc, xyz, rafa, {}]            |
#|[abc, xyz, rafa, {}, experience]|
#+--------------------------------+

既然列表中有适当的值,我们可以将它们连接在一起,并将空字符串作为分隔符。

df.select(
    f.concat_ws(
        "",
        f.collect_list("name").over(w)
    ).alias("concatenated")
).show()
#+-----------------------+
#|concatenated           |
#+-----------------------+
#|abc                    |
#|abcxyz                 |
#|abcxyzrafa             |
#|abcxyzrafa{}           |
#|abcxyzrafa{}experience |
#+-----------------------+

答案 1 :(得分:0)

<强>解决方案:

将pyspark.sql.functions导入为f

w = Window.partitionBy(&#34; Seq&#34;)。orderBy(&#34; DateTime&#34;)

df.select(     &#34; *&#34 ;,     f.concat_ws(         &#34;&#34 ;,         f.collect_set(f.col(&#34;名称&#34))。在(w)的     ).alias(&#34; cummuliative_name&#34) ).show()

<强>解释

collect_set() - 此函数返回的值类似于[[&#34; abc&#34;,&#34; xyz&#34;,&#34; rafa&#34;,{},&#34;经验&# 34;]]。

concat_ws() - 此函数将collect_set()的输出作为输入并将其转换为abc,xyz,rafa,{},体验

注意: 如果您没有重复项,请使用 collect_set(),否则请使用 collect_list()