web-dev-qa-db-ja.com

PySpark-新しい列を作成するための文字列マッチング

私は次のようなデータフレームを持っています:

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

たとえば、John、Stacy、またはMarshaの3人の従業員しかチェックしないとします。次のような新しい列を作成したいと思います。

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
10
Ashley O

要するに:

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

この式は、employee name from any positionを抽出しますby then スペーステキスト列(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)(\s+)(\w+)')は

  • (。)-任意の文字(改行を除く)
  • (by)-テキストby
  • (\ s +)-1つまたは複数のスペース
  • (\ 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ノートブック

注意:

regexp_extract(col('Notes'), '.by\s+(\w+)', 1))はかなりクリーンなバージョンのようです 使用中の正規表現を確認してください

17
mrsrinivas

簡単な

by以外のWordが名前の前にある他のサンプルが存在する場合、OPはより多くのサンプルをポストする必要がありますが、最も単純な形式で、提供された例に従って、この回答で十分です。


コード

ここで使用中のコードを参照

正規表現

^(\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+) 1つ以上のWord文字(a-zA-Z0-9_)をグループ1にキャプチャします
  • [ \t]*任意の数のスペースまたはタブ文字と一致します([ \t]は、PCREなどの一部の正規表現フレーバーで\hに置き換えることができます)
  • (.*\bby[ \t]+(\w+)[ \t]*.*)次をグループ2 にキャプチャします。
    • .*任意の文字に一致します(s修飾子が使用されない限り改行を除く)
    • \bby単語の境界に一致\bに続いてbyがそのまま続く
    • [ \t]+ 1つ以上のスペースまたはタブ文字に一致
    • (\w+) 1つ以上のWord文字(a-zA-Z0-9_)をグループ3にキャプチャします
    • [ \t]*任意の数のスペースまたはタブ文字に一致
    • .*任意の文字と何度でも一致
  • $行末の位置をアサート

置換

  • \1最初のキャプチャグループで最後に一致したものと同じテキストに一致します
  • \tタブ文字
  • \1 2番目のキャプチャグループで最後に一致したものと同じテキストに一致します
  • \tタブ文字
  • \1 3番目のキャプチャグループで最後に一致したものと同じテキストに一致します
2
ctwheels

このような何かが動作するはずです

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

正規表現を使用して適切な値を抽出する場合は、次のようなものが必要です

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

私が質問をもう一度読んだとき、OPは従業員の固定リストについて話すかもしれません(「たとえば、人の従業員のみ確認するにはジョン、ステイシー、またはマーシャがある」)。これが実際に既知のリストである場合、最も簡単な方法は、Wordの境界を持つこの名前のリストに対してチェックすることです。

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