What is a Python Class and How Do You Use It? | Towards Data Science

When working on data science projects or any Python programming project, you will most likely find yourself utilizing plenty of self-made functions and variables. You may have even create an entire script filled with functions you created in order to streamline the process of your project.
The purpose of these functions can be for numerous things within your code. From cleaning your DataFrame to training a machine learning model. It’s useful to create a ton of functions in order to organize your Python code but there is another way to make your code look and act more presentable — By using a Python Class!
A Python class is like an outline for creating a new object. An object is anything that you wish to manipulate or change while working through the code. Every time a class object is instantiated, which is when we declare a variable, a new object is initiated from scratch. Class objects can be used over and over again whenever needed.
In our case, in our previous articles, we have been writing a series about the creation of a dating algorithm that clusters and sorts dating profiles by using machine learning. See here:
towardsdatascience.com
In the article above, we go through the entire process of data preprocessing in order to have our data become AI friendly, such as transforming the dating profiles into an array of numbers. The objects, in this case, are the dating profiles that need to be manipulated in order for all of this to happen.
This data preprocessing step is achieved through the use of numerous functions. It is not organized in the best way but it gets the job done. However, we can improve the process by utilizing a Python Class.
Sign up for a Medium Membership here to gain unlimited access and support content like mine! With your support I earn a small portion of the membership fee. Thanks!
In order to learn more about class objects and utilizing them, we will be implementing a class object for our AI Dating Algorithm. Let’s organize and clean up the code we used into a Class object.
First, we must ask ourselves — What do we want this class object to do? We want it to:
Create a new dating profile.Add that new profile to a larger pool of dating profiles.Scale or vectorize that profile in order for it to be machine learning model friendly.
Create a new dating profile.
Add that new profile to a larger pool of dating profiles.
Scale or vectorize that profile in order for it to be machine learning model friendly.
Basically, we will want it to condense the entire data preprocessing step into a Class object which we can then use for every new dating profile we wish to add. We can use this class object whenever we need to create a new dating profile.
Before you create the class, we suggest you import the necessary libraries. For our class, we will be using the following libraries in order to format the new dating profile:
import pandas as pdfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.preprocessing import MinMaxScaler
To begin, in order to create a class object, all you have to do is type the following:
class CreateProfile:
The name of the class is subjective but the general rule regarding the format of the name is to follow something called camelCase. This is the start of our class object from which we will begin building off of.
Within the class, tab over to start defining our first function. Usually, when creating a class, you will have to define a function called __init__ with self as the initial argument.
class CreateProfile:    def __init__(self):
An __init__ function is called when a class is instantiated. By instantiate, we mean when you declare the class, which can happen either by itself or by assigning it to a variable. Here are some quick examples of instantiating a class object:
CreateProfile()# ORprofile = CreateProfile()
Here we are instantiating the class object and by doing so, we are implicitly calling the __init__ function. Any arguments within the __init__ function will also be the same arguments when instantiating the class object. These initial arguments can be the data we wish to manipulate throughout the class object. But in regards to the self argument, it will not be necessary to replace when instantiating the class object.
The self argument will only appear when constructing the Python class. It is used throughout the class and will usually be the first argument for any functions you create within that class. However, whenever you use the class object after instantiating, self will not be an argument you need to fill.
The self argument is an implicit argument that will always be called when instantiating the class or when you use a custom function within that class. The self refers to the object it is manipulating. In our case, the new dating profile we want to create.
To further understand the usage of self, we will continue constructing our class. Let’s fill in some other arguments that our __init__ function will take:
class CreateProfile:    def __init__(self,                  dataset=None,                 profile=None):        self.dataset = dataset        self.profile = profile
As you can see here, we are adding some arguments after self. These arguments are empty for now but we will be using a Pandas DataFrame to create a new dating profile. In order for these DFs to be used throughout the class, we must assign them to the object or self that we will manipulate with functions later on.
When assigning these DFs in our __init__ we are effectively creating class attributes. They can be called upon after instantiating the class and they will return whatever variable we assigned to the object (self):
# Instantiating the classnew_profile = CreateProfile()# Calling the class attributenew_profile.dataset 
This will return to us whatever dataset we provided when we instantiated the class. In this case, running this code will return nothing because None was the default argument established in the __init__ function.
We can also run new_profile.profile to return the profile we are creating and manipulating. This created profile will be empty for now but we will fill it with new information and format it by using some custom functions within the class that we will construct later on.
In order to progress to the next step, let’s establish all the class attributes to create our final __init__ function. We will need them for future custom functions within the class:
Functions that we create within a class are called methods. Functions and methods are essentially the same thing but in the context of class objects, functions are referred to as methods. We will need to create some methods for our class in order to manipulate and utilize the data given.
In this case, we will be using a synthetic dataset of dating profiles we created earlier before. See the following article to see the creation of this dataset:
towardsdatascience.com
This dataset will give us the context from which we will create a new dating profile.
One of the first things we want our class to do is to create a brand new profile if it wasn’t already provided with one. To do this we can create a new method below the __init__ method:
class createProfile:    def __init__(self,                  dataset=None,                 profile=None):        self.dataset = dataset        self.profile = profile    # Here we add another function    def enter_info(self):        # Code goes here
As you can see, we are still using the self argument. We will need it as we type in the rest of the code seen below:
The above method uses self throughout the code. When we use self.profile, we are referring to the attribute we had assigned in the __init__ method. First, we are checking to see if it is an empty DataFrame, which it is. Next, we will use the self.dataset variable we had also assigned in the __init__ method and use its features to create the new profile.
We allow the option to either use random information from the larger dataset to fill in the new profile or enter information manually. After having the profile information entered, the method overwrites the self.profile attribute with the new profile information. If you were to try to run this method again, it will return the string: “Data already contained in the profile.”
If you wanted to enter new information, you’ll have to reinstantiate the class and run it again from the top. Instantiating the class starts the whole process all over again.
Here is how we run this method starting from the instantiation step:
# Instantiating with the data from the DF of synthetic profilesnew_profile = createProfile(dataset=data)# Running the methodnew_profile.enter_info()
That is really all we need. Just the two lines of code. When we run this it will either enter random information for the profile, which is the function’s default behavior, or it will prompt us to enter information manually like so:
Either way, the class method will have created a brand new profile for us to manipulate in the form of a DataFrame:
For us to create a well-rounded class, it must do more than just create a new dating profile. In that case, we will add the methods that were previously stated in the __init__ method. Here are the methods that we will add to the class to work with our new profile:
Each method in the class performs a specific function. Given the attributes created in the self, these methods will replace the class’s attributes with the resulting value of each method.
add_profile_to_dataset() — This method assumes that there is already a dating profile with information. It compares the features from the profile and the larger dataset to see if they match. If they match, then it will add the new profile to the dataset and return the larger dataset with the new profile added. Otherwise, it will inform the user that the dataset’s features do not match with the profile’s features.
vect_text() — With new profile data, this method instantiates CountVectorizer() to create an array of numbers for each word used in the profile’s Bios. It then creates a DF of that array of numbers and returns it.
scale_profile() — Given the new profile data, this method uses the MinMaxScaler() fitted to the larger dataset of profiles to scale the new profile data. Also, in the arguments for the method, there is a list of excluded features or columns to not scale. It then uses the self.scaled_profile attribute and reassigns it with a new DF containing the scaled values and returns that DF.
format_profile()— This method basically combines the previous two methods: vect_text() and scale_profile(). If the returned attributes from running the two methods are already there then it will just concatenate the two DFs and return the resulting DF. If not, then it runs the methods anyways and returns the concatenated result of the two DFs.
Running each method is the same as running the enter_info() method before:
# Running each method after having ran enter_info()new_profile.add_profile_to_dataset()new_profile.vect_text()new_profile.scale_profile()new_profile.format_profile()
Now that we have run all the methods in our class, we can check the results by looking at the new class attributes that each method used.
# Running each attribute to check their resultsnew_profile.combined_df.tail(5)new_profile.vectorized_textnew_profile.scaled_profilenew_profile.formatted_profile
If you were to run this code you will be able to see the class attributes that each method dealt with and their final result (in order):
As you can see, the new profile has an index value of 6600 and it is shown how each method manipulated it. We can now refer to each attribute in the class whenever we want and it will contain these results.
One thing that is also really useful when creating a class is that we can import the class we create into other Python files or notebooks. Just save the Python class in a .py file and you can import it later on. Just make sure it is in the same directory. You can import the class like any other Python library:
from your_file_name import CreateProfile
Now you can use your Python class whenever you want without copy/pasting the code.
Using class to streamline our data preprocessing step is extremely useful for anyone starting a data science project. In our case, we needed a way to handle the creation of a new profile and format it as well. The great thing about Python’s class is we can reuse it anytime we want. If we wanted to add another dating profile, then all we have to do is instantiate another class object. This can go on and on until we are satisfied with the amount of new profiles created.
Overall, class objects can be utilized to organize your code in your coding projects. Here we only covered the basics of Python’s class and there is still some more concepts to learn. If you want to know more about Python’s class, then click here.
Check out the Github in the resources below for the full code if you need to. By now you can probably see the value in creating a Python class for your projects.