Условное разделение на основе списка столбцов

У меня есть фрейм данных, имеющий два столбца: «id» (int) и «values» (список структур). Мне нужно разделить имя. У меня есть список имен столбцов в качестве разделителя. Мне нужно проверить появление имен столбцов в списке, если присутствует одно из имен столбцов, а затем разделить фрейм данных.

from pyspark.sql import SparkSession
from pyspark.sql.functions import col, explode
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, ArrayType

value_schema = ArrayType(
    StructType([
        StructField("name", StringType(), True),
        StructField("location", StringType(), True)
    ])
)

data = [
    (1, [
        {"name": "col1_US", "location": "usa"},
        {"name": "col2_name_plex", "location": "usa"},
        {"name": "col4_false", "location": "usa"},
        {"name": "col3_name_is_fantasy", "location": "usa"}
    ])
]


df = spark.createDataFrame(data, ["id", "values"])

df = df.withColumn("values", explode(col("values")).alias("values"))
df = df.select(col("id"),col("values.name").alias("name"))
df.display()


col_names = ["col1","col2_name","col3_name_is","col4"]

for c in col_names:
    #if (df["name"].contains(c)):  # this is not working
    split_data = split(df["name"], f'{c}_')
    df = df.withColumns({
        "new_name": lit(c),
        "new_value": split_data.getItem(1)
        })
df.display()

Данные после очистки:

id  name
1   col1_US
1   col2_name_plex
1   col4_false_val
1   col3_name_is_fantasy

Окончательные данные из приведенного выше сценария:

# returning unexpected data

id    name                new_name  new_value
1   col1_US               col4      null
1   col2_name_plex        col4      null
1   col4_false_val        col4      false
1   col3_name_is_fantasy  col4      null

Ожидаемый результат:

id    name                new_name          new_value
1   col1_US               col1              US
1   col2_name_plex        col2_name         plex
1   col4_false_val        col4              false_val
1   col3_name_is_fantasy  col3_name_is      fantasy
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мы можем использовать регулярное выражение, чтобы создать поле new_name из вашего списка желаемых col_names:

col_names = ["col1","col2_name","col3_name_is","col4"]
pattern = "|".join(col_names)

df = df.withColumn("new_name", regexp_extract("name", pattern, 0))

+---+--------------------+------------+
| id|                name|    new_name|
+---+--------------------+------------+
|  1|             col1_US|        col1|
|  1|      col2_name_plex|   col2_name|
|  1|          col4_false|        col4|
|  1|col3_name_is_fantasy|col3_name_is|
+---+--------------------+------------+

Затем мы можем разделить, используя другое регулярное выражение, где мы передаем new_name в качестве шаблона, который мы хотим сопоставить, и после этого получать только буквенно-цифровые символы (чтобы мы не добавляли «_»).

df.withColumn(
    "new_value", 
    expr("regexp_replace(split(name, new_name)[1], '[^a-zA-Z0-9]+', '')")
)

+---+--------------------+------------+---------+
| id|                name|    new_name|new_value|
+---+--------------------+------------+---------+
|  1|             col1_US|        col1|       US|
|  1|      col2_name_plex|   col2_name|     plex|
|  1|          col4_false|        col4|    false|
|  1|col3_name_is_fantasy|col3_name_is|  fantasy|
+---+--------------------+------------+---------+

Спасибо. это работает в большинстве случаев. Я пропустил один случай, когда часть значения может иметь несколько пробелов. например, «col3_name_is_fantasy_val», здесь new_name — это «col3_name_is», а new_value — это «fantasy_val». Приведенный выше код обрабатывает new_name, но new_value имеет значение «fantasyval». Как справиться с такими случаями, я попробовал что-то вроде `split(df['name'], concat(df['new_name'],lit('_')))[1] ` но получаю ошибку. Столбец не повторяется .

steve 26.06.2024 06:26

также попробовал код ниже, столкнулся с той же ошибкой df = df.withColumn( "new_value", split(df['name'], concat(df['new_name'], lit('_')))[1] )

steve 26.06.2024 06:58

опубликовано stackoverflow.com/questions/78671358/…

steve 26.06.2024 11:02

Другие вопросы по теме