PySpark-字符串匹配以创建新列

2024-05-13 11:53:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据框,比如:

ID             Notes
2345          Checked by John
2398          Verified by Stacy
3983          Double Checked on 2/23/17 by Marsha 

比如说,只有3名员工需要检查:John、Stacy或Marsha。我想制作一个新的专栏如下:

ID                Notes                              Employee
2345          Checked by John                          John
2398         Verified by Stacy                        Stacy
3983     Double Checked on 2/23/17 by Marsha          Marsha

这里是regex还是grep更好?我应该尝试什么样的功能?谢谢!

编辑:我一直在尝试一系列的解决方案,但似乎没有任何效果。我是否应该放弃并为每个员工创建一个具有二进制值的列?即:

ID                Notes                             John       Stacy    Marsha
2345          Checked by John                        1            0       0
2398         Verified by Stacy                       0            1       0
3983     Double Checked on 2/23/17 by Marsha         0            0       1

Tags: 数据idbyon员工employeejohnregex
3条回答

像这样的事情应该行得通

import org.apache.spark.sql.functions._
dataFrame.withColumn("Employee", substring_index(col("Notes"), "\t", 2))

如果您想使用regex来提取适当的值,您需要

 dataFrame.withColumn("Employee", regexp_extract(col("Notes"), 'regex', <groupId>)

简短的

按照最简单的形式,并且根据提供的示例,这个答案应该足够了,尽管如果存在其他示例,OP应该发布更多的示例,其中名称前面应该有任何单词,而不是by


代码

See code in use here

正则表达式

^(\w+)[ \t]*(.*\bby[ \t]+(\w+)[ \t]*.*)$

更换

\1\t\2\t\3

结果

输入

2345          Checked by John
2398          Verified by Stacy
3983          Double Checked on 2/23/17 by Marsha 

输出

2345    Checked by John John
2398    Verified by Stacy   Stacy
3983    Double Checked on 2/23/17 by Marsha     Marsha

注意:上面的输出通过制表符\t字符分隔每一列,因此肉眼可能看不出它是正确的,但是简单地使用在线正则表达式解析器并将\t插入到正则表达式匹配部分应该会显示每一列的开始/结束位置。


解释

正则表达式

  • ^在行首断言位置
  • (\w+)将一个或多个单词字符(a-zA-Z0-9_)捕获到组1中
  • [ \t]*匹配任意数量的空格或制表符([ \t]在某些regex风格(如PCRE)中可以用\h替换)
  • (.*\bby[ \t]+(\w+)[ \t]*.*)将以下内容捕获到组2中
    • .*匹配任何字符(除了换行符,除非使用s修饰符)
    • \bby匹配单词边界\b,后跟by字面意思
    • [ \t]+匹配一个或多个空格或制表符
    • (\w+)将一个或多个单词字符(a-zA-Z0-9_)捕获到组3中
    • [ \t]*匹配任意数量的空格或制表符
    • .*匹配任意字符任意次数
  • $在行尾断言位置

更换

  • \1匹配的文本与第一个捕获组最近匹配的文本相同
  • \t制表符
  • \1与第二个捕获组最近匹配的文本相同
  • \t制表符
  • \1与第三个捕获组最近匹配的文本匹配

简而言之:

regexp_extract(col('Notes'), '(.)(by)(\s+)(\w+)', 4))

This expression extracts employee name from any position where it is after by then space(s) in text column(col('Notes'))


详细说明:

创建示例数据帧

data = [('2345', 'Checked by John'),
('2398', 'Verified by Stacy'),
('2328', 'Verified by Srinivas than some random text'),        
('3983', 'Double Checked on 2/23/17 by Marsha')]

df = sc.parallelize(data).toDF(['ID', 'Notes'])

df.show()

+----+--------------------+
|  ID|               Notes|
+----+--------------------+
|2345|     Checked by John|
|2398|   Verified by Stacy|
|2328|Verified by Srini...|
|3983|Double Checked on...|
+----+--------------------+

做必要的进口

from pyspark.sql.functions import regexp_extract, col

df上,使用regexp_extract(column_name, regex, group_number)从列中提取Employee名称。

这里的regex是指

  • (.)-任何字符(换行符除外)
  • (by)-文本中的单词by
  • (\s+-一个或多个空格
  • (\w+-长度为1的字母数字或下划线字符

因为在表达式中,{}组位于第4位,所以组数是4

result = df.withColumn('Employee', regexp_extract(col('Notes'), '(.)(by)(\s+)(\w+)', 4))

result.show()

+----+--------------------+--------+
|  ID|               Notes|Employee|
+----+--------------------+--------+
|2345|     Checked by John|    John|
|2398|   Verified by Stacy|   Stacy|
|2328|Verified by Srini...|Srinivas|
|3983|Double Checked on...|  Marsha|
+----+--------------------+--------+

Databricks notebook

注:

regexp_extract(col('Notes'), '.by\s+(\w+)', 1)) seems much cleaner version and check the Regex in use here

相关问题 更多 >