web-dev-qa-db-fra.com

Groupe Pyspark Dataframe par filtrage

J'ai une trame de données comme ci-dessous

cust_id   req    req_met
-------   ---    -------
 1         r1      1
 1         r2      0
 1         r2      1
 2         r1      1
 3         r1      1
 3         r2      1
 4         r1      0
 5         r1      1
 5         r2      0
 5         r1      1

Je dois regarder les clients, voir combien d'exigences ils ont et voir s'ils ont satisfait au moins une fois. Il peut y avoir plusieurs enregistrements avec le même client et la même exigence, l'un avec satisfait et non satisfait. Dans le cas ci-dessus, ma sortie devrait être

cust_id
-------
  1
  2
  3

Ce que j'ai fait c'est

# say initial dataframe is df
df1 = df\
    .groupby('cust_id')\
    .countdistinct('req')\
    .alias('num_of_req')\
    .sum('req_met')\
    .alias('sum_req_met')

df2 = df1.filter(df1.num_of_req == df1.sum_req_met)

Mais dans certains cas, les résultats ne sont pas corrects

Comment cela peut-il être fait ?

7
Lijju Mathew

Tout d'abord, je vais simplement préparer un ensemble de données de jouets à partir de ce qui précède,

from pyspark.sql.functions import col
import pyspark.sql.functions as fn

df = spark.createDataFrame([[1, 'r1', 1],
 [1, 'r2', 0],
 [1, 'r2', 1],
 [2, 'r1', 1],
 [3, 'r1', 1],
 [3, 'r2', 1],
 [4, 'r1', 0],
 [5, 'r1', 1],
 [5, 'r2', 0],
 [5, 'r1', 1]], schema=['cust_id', 'req', 'req_met'])
df = df.withColumn('req_met', col("req_met").cast(IntegerType()))
df = df.withColumn('cust_id', col("cust_id").cast(IntegerType()))

Je fais la même chose par groupe par cust_id et req puis comptez le req_met. Après cela, je crée une fonction pour fixer ces exigences à seulement 0, 1

def floor_req(r):
    if r >= 1:
        return 1
    else:
        return 0
udf_floor_req = udf(floor_req, IntegerType())
gr = df.groupby(['cust_id', 'req'])
df_grouped = gr.agg(fn.sum(col('req_met')).alias('sum_req_met'))
df_grouped_floor = df_grouped.withColumn('sum_req_met', udf_floor_req('sum_req_met'))

Maintenant, nous pouvons vérifier si chaque client a satisfait à toutes les exigences en comptant le nombre distinct d'exigences et le nombre total d'exigences satisfaites.

df_req = df_grouped_floor.groupby('cust_id').agg(fn.sum('sum_req_met').alias('sum_req'), 
                                                 fn.count('req').alias('n_req'))

Enfin, il suffit de vérifier si deux colonnes sont égales:

df_req.filter(df_req['sum_req'] == df_req['n_req'])[['cust_id']].orderBy('cust_id').show()
12
titipata
 select cust_id from  
(select cust_id , MIN(sum_value) as m from 
( select cust_id,req ,sum(req_met) as sum_value from <data_frame> group by cust_id,req )
 temp group by cust_id )temp1 
where m>0 ;

Cela donnera le résultat souhaité

1
Ashish Singh