我有一个类似的数据框:
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
答案 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+)'
)表示
和 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|
+----+--------------------+--------+
regexp_extract(col('Notes'), '.by\s+(\w+)', 1))
似乎更清晰,check the Regex in use here
答案 1 :(得分:1)
以最简单的形式,根据提供的示例,这个答案应该足够了,尽管OP应该发布更多的样本,如果存在其他样本,其名称前面应该是除by
以外的任何单词。
<强>正则表达式
^(\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)