PySpark - 用于创建新列的字符串匹配

时间:2017-09-25 17:27:26

标签: python regex apache-spark pyspark databricks

我有一个类似的数据框:

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

这里的正则表达式还是grep更好?我应该尝试什么样的功能?谢谢!

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

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

4 个答案:

答案 0 :(得分:14)

简而言之:

  

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

     

此表达式从任意位置中提取 员工姓名 ,在之后然后空格( s)在文本列(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在列中Employee提取regexp_extract(column_name, regex, group_number)名称。

此处正则表达式'(.)(by)(\s+)(\w+)')表示

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

group_number 为4,因为组(\w+)在表达式中位于第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))似乎更清晰,check the Regex in use here

答案 1 :(得分:1)

以最简单的形式,根据提供的示例,这个答案应该足够了,尽管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]可以替换为某些正则表达式中的\h,例如PCRE)
  • (.*\bby[ \t]+(\w+)[ \t]*.*)将以下内容捕获到第2组
    • .*匹配任何字符(换行符除外,除非使用s修饰符)
    • \bby匹配字边界\b,后跟by字面意思
    • [ \t]+匹配一个或多个空格或制表符
    • (\w+)将一个或多个单词字符(a-zA-Z0-9_)捕获到第3组
    • [ \t]*匹配任意数量的空格或制表符
    • .*多次匹配任何字符
  • $断言行尾的位置

替换

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

答案 2 :(得分:0)

这样的事情应该有效

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

如果你想使用正则表达式来提取正确的值,你需要像

这样的东西
 dataFrame.withColumn("Employee", regexp_extract(col("Notes"), 'regex', <groupId>)

答案 3 :(得分:0)

当我再次阅读问题时,OP可能会谈到一份固定的员工名单(“比方说,只有只有3名员工来检查:John,Stacy或Marsha”)。 如果这确实是一个已知列表,那么最简单的方法是检查带有字边界的名称列表:

regexp_extract(col('Notes'), '\b(John|Stacy|Marsha)\b', 1)