def clean_data(df):
    """
        Takes a Dataframe and perform cleaning operations such as
        expanding the multiple categories into seperate columns, 
        extract categories values, replace the previous categories with new columns
        and removing duplicates
        Input: DataFrame
        Output: cleaned dataframe
    """
    # split categories into seperate categories
    categories = df.categories.str.split(';', expand=True)
    
    # select the first row of the categories dataframe
    row = categories.iloc[0]
    
    # use the first row to extract categories names
    category_colnames = row.apply(lambda x: x[:-2])
    
    # rename the columns of `categories`
    categories.columns = category_colnames
    
    #convert categories values to numeric instead of strings
    for column in categories:
        categories[column] = categories[column].str[-1]
        # convert column from string to numeric
        categories[column] = categories[column].astype(int)
    
    # replace categories column in df 
    df.drop(columns = ['categories'], inplace=True)
    # concatenate the original dataframe with the new `categories` dataframe
    df = df.join(categories)
    
    #drop duplicates
    df.drop_duplicates(inplace=True)
    
    return df