Creating Environnment with Python 3.7 and Installing Libreries.

  • Create a conda environment :

    conda create -n music python=3.7 -y

  • Activate the conda environment :

    conda activate music

  • Now install following libraries :

    pip install tensorflow

    pip install sklearn

    pip install matplotlib

    pip install pandas

    pip install numpy

    pip install opencv-python

    pip install lightgbm

  • After installing you are good to proceed further to importing required modules.

  • You can get the data for this project from here.

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import lightgbm
import time
import cv2
from sklearn.model_selection import train_test_split
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from lightgbm import LGBMClassifier
from tensorflow.keras.utils import img_to_array
from keras.preprocessing import image
from keras.models import load_model
import os
import tensorflow as tf
import time
import imutils
import argparse
from imutils.video import VideoStream

Performing basic preprocessing on the data.

  • Importing data using pandas method.
df = pd.read_csv('./Spotify Dataset Analysis/data.csv')
df.drop_duplicates(inplace=True, subset=['name'])
name = df['name']
  • We are choosing "danceability", "energy", "valence", "loudness" columns since they are the most important features for our model from data analysis.
column_feat = ["danceability", "energy", "valence", "loudness"]
scaler = MinMaxScaler().fit_transform(df[column_feat])

Applying KNN algorithm to the data.

  • We are creating 3 clusters and saving the labels in a separate column kmeans and setting a new column to store songs name.
kmeans = KMeans(init="k-means++",
                n_clusters=3, random_state=15).fit(scaler)
df['kmeans']= kmeans.labels_

# Setting up new column song_name
df['song_name'] = name
cluster = df.groupby(by=df['kmeans'])

Data preparation for train test split and performing model training with Lightgbm Classifier to check the feature importace.

X = df.drop(columns=['name','artists','id','release_date','song_name'])
Y = df.pop('kmeans')
X_train,X_test,y_train,y_test = train_test_split(X,
                                                 Y, test_size=0.25)
model = LGBMClassifier().fit(X_train,y_train)
model.score(X_train,y_train)
1.0
model.score(X_test,y_test)
1.0
  • We can see our training and testing score of the model is quite good.

  • Now visualizing feature importance of the model.

    • We can see clearly that energy is the most important feature for our model.
ax = lightgbm.plot_importance(model,
                              max_num_features=10,
                              figsize=(15,10))
plt.show()
  • Here we are sorting the cluster dataframe by papularity of the music and resetting the index.
data=cluster.apply(lambda x: x.sort_values(["popularity"],ascending=False))
data.reset_index(level=0, inplace=True)

Emotion Detection Starts.

  • Loading Required model that is haarcascade_frontalface_default.xml for detecting face and epoch_75.hdf5 is for detecting emotion which I have already trained.
  • Also giving the labels for different emotions.
  • You can download a pretrained model from here
detector = cv2.CascadeClassifier(cv2.data.haarcascades + './haarcascade_frontalface_default.xml')
model = load_model("./epoch_75.hdf5")
EMOTIONS = ["Angry", "Scared", "Happy", "Sad", "Surprised", "Neutral"]

We are applying OpenCV to read a frame from a video and predicting using pre trained model.

def emotion_testing():
    global label
    cap = cv2.VideoCapture(0)
    time.sleep(2.0)
    while True:
        # grab the current Frame.
        _, frame = cap.read()

        # resize the frame and convert it to grayscale
        frame = imutils.resize(frame, width=300)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # initialize the canvas for the visualization, then clone
        # the frame so we can draw on it.
        canvas = np.zeros((220, 300, 3), dtype="uint8")
        frameClone = frame.copy()

        # Detect faces in the input frame, then clone the frame so that
        # we can draw on it
        rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags = cv2.CASCADE_SCALE_IMAGE)

        # Ensure at least one face was found before continuing.
        if len(rects) > 0:
            # determine the largest face area
            rect = sorted(rects, reverse=True,
                          key=lambda x: (x[2] - x[0]) * (x[3] - x[1]))[0]
            (fX, fY, fW, fH) = rect

            # extract the face ROI from the image, then preprocess
            # it for the network
            roi = gray[fY:fY + fH, fX:fX + fW]
            roi = cv2.resize(roi, (48, 48))
            roi = roi.astype("float") / 255.0
            roi = tf.keras.preprocessing.image.img_to_array(roi)
            roi = np.expand_dims(roi, axis=0)

            # Make a prediction on the ROI,then lookup the class
            # label
            preds = model.predict(roi)[0]
            label = EMOTIONS[preds.argmax()]
            #print(label)

            # Loop over the labels + probabilities and draw them
            for (i, (emotion, prob)) in enumerate(zip(EMOTIONS, preds)):
                # Construct the label text
                text = "{}: {:.2f}%".format(emotion, prob * 100)

                # Draw the label + probability bar on the canvas
                w = int(prob * 300)
                cv2.rectangle(canvas, (5, (i * 35) + 5),
                              (w, (i * 35) + 35), (0, 0, 255), -1)
                cv2.putText(canvas, text, (10, (i * 35) + 23),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.45,
                            (2, 180, 48), 2)

                # draw the label on the frame
                cv2.putText(frameClone, label, (fX, fY - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.45, (252, 247, 48), 2)
                cv2.rectangle(frameClone, (fX, fY), (fX + fW, fY + fH),
                              (0, 0, 255), 2)

        # show our classifications + probabilities
        cv2.imshow("Face", frameClone)
        # cv2.imshow("Probabilities", canvas)

        # if the ’q’ key is pressed, stop the loop
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
            
    return label
  • Here following function generatesemotion code for each detected emotion. They are :
    • 0 : Neutral
    • 1 : Happy
    • 2 : Sad
def code():
    emotion_word = emotion_testing()
    if emotion_word == 'Neutral':
        emotion_code = 0
        print("Neutral detected ")
    elif emotion_word == 'Happy':
        emotion_code = 1
        print("Happy Detected..")
    elif emotion_word == 'Sad':
        emotion_code = 2
        print("Sad Detected..")
    else:
        print("Hi Deep!!")
    return emotion_code
  • Following function is recommending songs according to the generated emotion code and kmeans labels.
def get_results():
    emotion_code = code()
    NUM_RECOMMEND=10
    happy_set=[]
    neutral_set=[]
    sad_set=[]
    if emotion_code==0:
        happy_set.append(data[data['kmeans']==0]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(happy_set).T
    elif emotion_code == 1:
        neutral_set.append(data[data['kmeans']==1]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(neutral_set).T
    else:
        sad_set.append(data[data['kmeans']==2]['song_name'].head(NUM_RECOMMEND))
        return pd.DataFrame(sad_set).T
  • Here this function is to run whole model.
get_results()
1/1 [==============================] - 2s 2s/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 20ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 19ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 22ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 22ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 18ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 18ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 14ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 16ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 19ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 15ms/step
1/1 [==============================] - 0s 15ms/step
Happy Detected..
song_name
87941 THE SCOTTS
87852 ily (i love you baby) (feat. Emilee)
87951 GOOBA
87952 Rain On Me (with Ariana Grande)
87970 Yo Perreo Sola
87977 Safaera
87540 goosebumps
87945 Blueberry Faygo
87742 SICKO MODE
87969 Boss Bitch