PySpark - ciągi znaków do tworzenia nowej kolumny


Mam ramkę danych taką jak:
ID Notes
2345 Checked by John
2398 Verified by Stacy
3983 Double Checked on 2/23/17 by Marsha

Powiedzmy, że trzeba sprawdzić tylko 3 pracowników: John, Stacy lub Marsha. Chciałbym stworzyć nową kolumnę w ten sposób:
ID Notes Employee
2345 Checked by John John
2398 Verified by Stacy Stacy
3983 Double Checked on 2/23/17 by Marsha Marsha

Czy regex czy grep są tutaj lepsze? Którą funkcję powinienem wypróbować? Podziękować!
Edytuj: Próbowałem kilka rozwiązań, ale wydaje się, nic nie działa. Powinienem się poddać i zamiast tego tworzyć kolumny dla każdego pracownika z wartością binarną? TO ZNACZY:
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

Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


W skrócie:
>
regexp_extract(col('Notes'), '(.)(by)(\s+)(\w+)', 4))
>
To wyrażenie wyodrębnia
imię i nazwisko pracownika


z

dowolna pozycja

gdzie to jest


po

Spacje w kolumnie tekstowej (
col('Notes')
)


Szczegółowo:
>
Utwórz przykładową ramkę danych
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...|
+----+--------------------+

Dokonaj niezbędnego importu
from pyspark.sql.functions import regexp_extract, col

W
df
wyodrębnij nazwę
Employee
z kolumny za pomocą
regexp_extract (nazwa_kolumny, wyrażenie regularne, numer_grupy)
.
Tutaj

regex

(
'(.) (by) (\ s +) (\ w +)'
) oznacza
  • (.) -dowolny znak (z wyjątkiem nowej linii)
  • (od) - Słowo w tekście
  • (\s+) - jeden lub więcej luk
  • (\w+) - znaki alfanumeryczne lub podkreślenia o długości jeden

i

group_number

równa się 4, ponieważ grupa
(\ w +)
znajduje się na czwartej pozycji w wyrażeniu
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|
+----+--------------------+--------+

Notatnik Databricks
https://databricks-prod-cloudf ... .html

Uwaga:
>
regexp_extract (col ('Notes'), '.by \ s + (\ w +)', 1))
wydaje się być znacznie czystszą wersją i

sprawdź Regex w użyciu tutaj
https://regex101.com/r/2lk6eV/3
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Krótki
>
W najprostszej formie i zgodnie z podanym przykładem, ta odpowiedź powinna wystarczyć, chociaż OP powinien wysłać więcej próbek, jeśli istnieją inne próbki, w których nazwa musi poprzedzać jakiekolwiek inne słowo niż
przez
.

Kod
>
Zobacz sekcję używanego kodu tutaj
https://regex101.com/r/Qxfx0B/3

Regex

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


Zastąpienie

\1\t\2\t\3


wyniki
>

Wejście
>
2345 Checked by John
2398 Verified by Stacy
3983 Double Checked on 2/23/17 by Marsha


Wyjście
>
2345 Checked by John John
2398 Verified by Stacy Stacy
3983 Double Checked on 2/23/17 by Marsha Marsha


Uwaga:

powyższe dane wyjściowe oddzielają każdą kolumnę znakiem tabulacji
\ t
, więc gołym okiem może się to wydawać niewłaściwe, ale po prostu używając parsera wyrażeń regularnych online i wstawiając
\ t
do Sekcja dopasowania wyrażeń regularnych, powinieneś pokazać, gdzie znajduje się każda kolumna z początkiem/końcem.

Wyjaśnienie
>

Regex
>
  • ^
    potwierdź pozycję na początku wiersza
  • (\ w +)
    przechwyć jeden lub więcej znaków słowa (
    a-zA-Z0-9_
    ) do grupy 1
  • [\ t] *
    odpowiada dowolnej liczbie spacji lub tabulatorów (
    [\ t]
    można zastąpić
    \ h
    w niektórych wyrażeniach regularnych warianty takie jak PCRE)
  • (. * \ bby [\ t] + (\ w +) [\ t] *. *)
    przenieś następujące elementy do grupy 2 [list][*]
    . *
    pasuje do dowolnego znaku (oprócz nowej linii, chyba że zastosowano modyfikator
    s
    )
  • \ bby
    dopasowuje słowo boundary
    \ b
    , po którym następuje dosłownie
    przez
  • [\ t] +
    dopasowuje co najmniej jedną spację lub tabulator
  • (\ w +)
    przechwyć jeden lub więcej znaków słowa (
    a-zA-Z0-9_
    ) do grupy 3
  • [\ t] *
    odpowiada dowolnej liczbie spacji lub tabulatorów
  • . *
    dopasuj dowolny znak dowolną liczbę razy

[/*]
[*]
$
potwierdź pozycję na końcu wiersza
[/*]
[/list]

Zastąpienie
>
  • \ 1
    pasuje do tego samego tekstu, który był ostatnio dopasowany przez pierwszą grupę przechwytywania
  • Znak tabulacji
  • \ t
  • \ 1
    pasuje do tego samego tekstu, który był ostatnio dopasowany przez drugą grupę przechwytywania
  • Znak tabulacji
  • \ t
  • \ 1
    pasuje do tego samego tekstu, który był ostatnio dopasowany przez trzecią grupę przechwytywania
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Kiedy ponownie przeczytam pytanie, PO może mówić o ustalonej liście pracowników („powiedzmy na przykład, że jest

tylko 3 pracowników

sprawdzić: John, Stacy lub Marsha ”).
Jeśli jest to naprawdę znana lista, najłatwiej jest sprawdzić tę listę granic słów:
regexp_extract(col('Notes'), '\b(John|Stacy|Marsha)\b', 1)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Coś takiego powinno działać
import org.apache.spark.sql.functions._
dataFrame.withColumn("Employee", substring_index(col("Notes"), "\t", 2))

W przypadku, gdy chcesz użyć REGEX, aby wyodrębnić poprawną wartość, potrzebujesz czegoś podobnego
dataFrame.withColumn("Employee", regexp_extract(col("Notes"), 'regex', <groupId>)

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się