I'm a newbie in PySpark, and I want to add a new column that contains/reports normalized statistic frequency of features for each record/row/event in PySpark on synthetic data. (Columns Type & Encoding_type are categorical) At first, I have Spark data frame so-called sdf including 5 columns:
Below is the example:
from pyspark.sql.types import StructType,StructField, StringType, IntegerType
data2 = [("Sentence",92,6,"False",49),
("Sentence",17,3,"False",15),
("Sentence",17,3,"False",15),
(0 , 0,0,"False", 0),
(0 , 0,0,"False", 0),
(0 , 0,0,"False", 0)
]
schema = StructType([ \
StructField("Type", StringType(), True), \
StructField("Length", IntegerType(), True), \
StructField("Token_number", IntegerType(), True), \
StructField("Encoding_type", StringType(), True), \
StructField("Character_feature", IntegerType(), True) \
])
sdf = spark.createDataFrame(data=data2,schema=schema)
sdf.printSchema()
sdf.show(truncate=False)
#root
# |-- Type: string (nullable = true)
# |-- Length: integer (nullable = true)
# |-- Token_number: integer (nullable = true)
# |-- Encoding_type: string (nullable = true)
# |-- Character_feature: integer (nullable = true)
#+--------+------+------------+-------------+-----------------+
#|Type |Length|Token_number|Encoding_type|Character_feature|
#+--------+------+------------+-------------+-----------------+
#|Sentence|92 |6 |False |49 |
#|Sentence|17 |3 |False |15 |
#|Sentence|17 |3 |False |15 |
#|0 |0 |0 |False |0 |
#|0 |0 |0 |False |0 |
#|0 |0 |0 |False |0 |
#+--------+------+------------+-------------+-----------------+
Now I want to allocate statistic frequency of features and map them to the main frame sdf as follows:
#Statistical Preprocessing
def add_freq_to_features_(df):
sdf_pltc = sdf.select('Type', 'Length', 'Token_number', 'Encoding_type', 'Character_feature')
#sdf_pltc.show(truncate=0)
sdf2 = (
sdf_pltc
.groupBy(sdf_pltc.columns)
.agg(F.count('*').alias('Freq'))
# .withColumn('Freq' , (col('Freq') / col('Freq').sum())) # Normalzing between 0 & 1
.withColumn('Encoding_type', F.col('Encoding_type').cast('string'))
)
sdf2.show()
return new_df
# Apply frequency allocation and merge with extracted features df
features_df = add_freq_to_features_(df)
features_df
#+--------+------+------------+-------------+-----------------+----+
#| Type|Length|Token_number|Encoding_type|Character_feature|Freq|
#+--------+------+------------+-------------+-----------------+----+
#|Sentence| 92| 6| False| 49| 1|
#| 0| 0| 0| False| 0| 3|
#|Sentence| 17| 3| False| 15| 2|
#+--------+------+------------+-------------+-----------------+----+
So as it can be seen compared with the pythonic version due to groupby() mechanism, it is framed as below:
import pandas as pd
data = {'Type': ["Sentence" , "Sentence" ,"Sentence" , "-", "-", "-"],
'Length': [92, 17,17,0,0,0],
'Token_number': [6, 3,3,0,0,0],
'Encoding_type': ["False" , "False" ,"False" , "False", "False", "False"],
'Character_feature': [49, 15,15,0,0,0],
}
# pass column names in the columns parameter
df = pd.DataFrame(data)
#df
#Statistical Preprocessing
def add_freq_to_features(df):
frequencies_df = df.groupby(list(df.columns)).size().to_frame().rename(columns={0: "Freq"})
# frequencies_df["Freq"] = frequencies_df["Freq"] / frequencies_df["Freq"].sum() # Normalzing 0 & 1
new_df = pd.merge(df, frequencies_df, how='left', on=list(df.columns))
return new_df
features_df = add_freq_to_features(df)
features_df
#+----------+------+------------+-------------+-----------------+-----+
#|Type |Length|Token_number|Encoding_type|Character_feature|Freq |
#+----------+------+------------+-------------+-----------------+-----+
#|Sentence |92 |6 |False |49 |1 |
#|Sentence |17 |3 |False |15 |2 |
#|Sentence |17 |3 |False |15 |2 |
#|- |0 |0 |False |0 |3 |
#|- |0 |0 |False |0 |3 |
#|- |0 |0 |False |0 |3 |
#+----------+-----+-------------+-------------+-----------------+-----+
I couldn't figure out how I could reach the Pythonic frame in PySpark. I might mess up in something in functions.
So I kindly provided a colab notebook for quick debugging and commenting.