#apache-spark #pyspark #apache-spark-sql
#apache-spark #pyspark #apache-spark-sql
Вопрос:
Мой df содержит названия продуктов и соответствующую информацию. Здесь уместны имя и страна, в которую продано:
-------------------- -------------------------
| Product_name|collect_set(Countries_en)|
-------------------- -------------------------
| null| [Belgium,United K...|
| #5 pecan/almond| [Belgium]|
| #8 mango/strawberry| [Belgium]|
|amp; Sully A Mild Th...| [Belgium,France]|
|amp;quot;70CL Liqueu...| [Belgium,France]|
|amp;quot;Gingembreamp;q...| [Belgium]|
|amp;quot;Les Schtrou...| [Belgium,France]|
|amp;quot;Sho-keyamp;quo...| [Belgium]|
|amp;quot;mini Chupa ...| [Belgium,France]|
| 'S Lands beste| [Belgium]|
|'T vlierbos confi...| [Belgium]|
|(H)eat me - Spagh...| [Belgium]|
| -cheese flips| [Belgium]|
| .soupe cerfeuil| [Belgium]|
|1 1/2 Minutes Bas...| [Belgium,Luxembourg]|
| 1/2 Reblochon AOP| [Belgium]|
| 1/2 nous de jambon| [Belgium]|
|1/2 tarte cerise ...| [Belgium]|
|10 Original Knack...| [Belgium,France,S...|
| 10 pains au lait| [Belgium,France]|
-------------------- -------------------------
пример входных данных:
[Row(code=2038002038.0, Product_name='Formula 2 men multi vitaminic', Countries_en='France,Ireland,Italy,Mexico,United States,Argentina-espanol,Armenia-pyсский,Aruba-espanol,Asia-pacific,Australia-english,Austria-deutsch,Azerbaijan-русский,Belarus-pyсский,Belgium-francais,Belgium-nederlands,Bolivia-espanol,Bosnia-i-hercegovina-bosnian,Botswana-english,Brazil-portugues,Bulgaria-български,Cambodia-english,Cambodia-ភាសាខ្មែរ,Canada-english,Canada-francais,Chile-espanol,China-中文,Colombia-espanol,Costa-rica-espanol,Croatia-hrvatski,Cyprus-ελληνικά,Czech-republic-čeština,Denmark-dansk,Ecuador-espanol,El-salvador-espanol,Estonia-eesti,Europe,Finland-suomi,France-francais,Georgia-ქართული,Germany-deutsch,Ghana-english,Greece-ελληνικά,Guatemala-espanol,Honduras-espanol,Hong-kong-粵語,Hungary-magyar,Iceland-islenska,India-english,Indonesia-bahasa-indonesia,Ireland-english,Israel-עברית,Italy-italiano,Jamaica-english,Japan-日本語,Kazakhstan-pyсский,Korea-한국어,Kyrgyzstan-русский,Latvia-latviešu,Lebanon-english,Lesotho-english,Lithuania-lietuvių,Macau-中文,Malaysia-bahasa-melayu,Malaysia-english,Malaysia-中文,Mexico-espanol,Middle-east-africa,Moldova-roman,Mongolia-монгол-хэл,Namibia-english,Netherlands-nederlands,New-zealand-english,Nicaragua-espanol,North-macedonia-македонски-јазик,Norway-norsk,Panama-espanol,Paraguay-espanol,Peru-espanol,Philippines-english,Poland-polski,Portugal-portugues,Puerto-rico-espanol,Republica-dominicana-espanol,Romania-romană,Russia-русский,Serbia-srpski,Singapore-english,Slovak-republic-slovenčina,Slovenia-slovene,South-africa-english,Spain-espanol,Swaziland-english,Sweden-svenska,Switzerland-deutsch,Switzerland-francais,Taiwan-中文,Thailand-ไทย,Trinidad-tobago-english,Turkey-turkce,Ukraine-yкраї́нська,United-kingdom-english,United-states-english,United-states-espanol,Uruguay-espanol,Venezuela-espanol,Vietnam-tiếng-việt,Zambia-english', Traces_en=None, Additives_tags=None, Main_category_en='Vitamins', Image_url='https://static.openfoodfacts.org/images/products/203/800/203/8/front_en.12.400.jpg', Quantity='60 compresse', Packaging_tags='barattolo,tablet', )]
Поскольку я хочу выяснить, в какие страны, кроме Бельгии, продаются продукты, я разделил столбец страны, чтобы показать каждую страну по отдельности, используя приведенный ниже код
#create df with grouped products
countriesDF = productsDF
.select("Product_name", "Countries_en")
.groupBy("Product_name")
.agg(F.collect_set("Countries_en").cast("string").alias("Countries"))
.orderBy("Product_name")
#split df to show countries the product is sold to in a seperate column
countriesDF = countriesDF
.where(col("Countries")!="null")
.select("Product_name",
F.split("Countries", ",").alias("Countries"),
F.posexplode(F.split("Countries", ",")).alias("pos", "val")
)
.drop("val")
.select(
"Product_name",
F.concat(F.lit("Countries"),F.col("pos").cast("string")).alias("name"),
F.expr("Countries[pos]").alias("val")
)
.groupBy("Product_name").pivot("name").agg(F.first("val"))
.show()
Однако в этой таблице теперь более 400 столбцов только для стран, что непрезентабельно. Итак, мой вопрос:
- правильно ли я выполняю разделение / взрыв?
- могу ли я разделить df, чтобы я получал страны в качестве имен столбцов (например, «Франция» вместо «страны1» и т. Д.), Подсчитывая количество раз, Когда продукт продается в этой стране?
Комментарии:
1. Какова ваша конечная цель? Чтобы вычислить количество
Product_name
для каждой страны? или вы действительно хотите отобразить этуcount( Product_name X COUNTRY)
матрицу?2. Вопрос в том, в какие страны (кроме Бельгии) продаются продукты. Поскольку их так много, если смотреть на весь df, я пытаюсь использовать второй из ваших вариантов. Таким образом, они сгруппированы по названию продукта в 1-м столбце и количеству продуктов, проданных в каждой стране.
Ответ №1:
Некоторые примеры данных :
val sampledf = Seq(("p1","BELGIUM,GERMANY"),("p1","BELGIUM,ITALY"),("p1","GERMANY"),("p2","BELGIUM")).toDF("Product_name","Countries_en")
Преобразовать в требуемый df :
df = sampledf
.withColumn("country_list",split(col("Countries_en"),","))
.select(col("Product_name"), explode(col("country_list")).as("country"))
------------ -------
|Product_name|country|
------------ -------
| p1|BELGIUM|
| p1|GERMANY|
| p1|BELGIUM|
| p1| ITALY|
| p1|GERMANY|
| p2|BELGIUM|
------------ -------
Если вам нужно только количество для каждой страны :
countDF = df.groupBy("Product_name","country").count()
countDF.show()
------------ ------- -----
|Product_name|country|count|
------------ ------- -----
| p1|BELGIUM| 2|
| p1|GERMANY| 1|
| p2|BELGIUM| 1|
------------ ------- -----
Кроме Бельгии :
countDF.filter(col("country") =!="BELGIUM").show()
------------ ------- -----
|Product_name|country|count|
------------ ------- -----
| p1|GERMANY| 1|
------------ ------- -----
И если вы действительно хотите, чтобы страны были столбцами :
countDF.groupBy("Product_name").pivot("country").agg(first("count"))
------------ ------- -------
|Product_name|BELGIUM|GERMANY|
------------ ------- -------
| p2| 1| null|
| p1| 2| 1|
------------ ------- -------
И вы можете .drop("BELGIUM")
этого добиться.
Комментарии:
1. поскольку столбцы «Countries_en» содержат несколько таких стран,
|Belgium,France|
это не решает мою проблему. Также причина, по которой сначала нужно разделить этот столбец2. Не могли бы вы опубликовать исходный входной фрейм данных smaple, о котором идет речь?
3. @JackSomeone теперь обработал эту
Belgium,France
часть. Пожалуйста, проверьте4. добавлен образец. Я думаю, что ваше добавление идет в правильном направлении, но когда вы смотрите на результат, он определяет каждую строку как одно, а не несколько событий, верно?
5. может быть, проще просто получить список стран =! Бельгия?
Ответ №2:
Используемый окончательный код:
#create df where countries are split off
df = productsDF
.withColumn("country_list",split(col("Countries_en"),","))
.select(col("Product_name"), explode(col("country_list")).alias("Country"))
#create count and filter out Country Belgium, Product Name can be changed as needed
countDF = df.groupBy("Product","Country").count()
.filter(col("Country") !="Belgium")
.filter(col('Product') == 'Café').show()