Pandas Notebook
Pandas Notebook
Pandas Series
Pandas Series is a one-dimensional labeled array/list capable of holding data of any type
(integer, string, float, python objects, etc.).
The labels are collectively called index.
Pandas Series can be thought as a single column of an excel spreadsheet and each entry
in a series corresponds to an individual row in the spreadsheet.
We can see that the list and array have been converted to a Pandas Series object.
We also see that the series has automatically got index labels. Let's see how these can be
modified.
In [3]: # changing the index of a series
med_price_list_labeled = pd.Series(med_price_list, index = ['Omeprazole','Azith
print(med_price_list_labeled)
Omeprazole 55
Azithromycin 25
Metformin 75
Ibuprofen 40
Cetirizine 90
dtype: int64
The price of each medicine was increased by $2.5. Let's add this to the existing price.
A new price list was released by vendors for each medicine. Let's find the difference
between new price and the old price
Pandas DataFrame
Pandas DataFrame is a two-dimensional tabular data structure with labeled axes (rows and
columns).
0 Mary
1 Peter
2 Susan
3 Toby
4 Vishal
0 Mary B-
1 Peter A+
2 Susan A-
3 Toby B+
4 Vishal C
The data for total energy consumption for the U.S. was collected from 2012 - 2018. Let's see
how this data can be presented in form of data frame.
In [9]: year = pd.Series([2012,2013,2014,2015,2016,2017,2018])
energy_consumption = pd.Series([2152,2196,2217,2194,2172,2180,2258])
df3 = pd.DataFrame({'Year':year,'Energy_Consumption(Mtoe)':energy_consumption}
df3
Out[9]: Year Energy_Consumption(Mtoe)
0 2012 2152
1 2013 2196
2 2014 2217
3 2015 2194
4 2016 2172
5 2017 2180
6 2018 2258
For encryption purposes a web browser company wants to generate random values which have
mean equal to 0 and variance equal to 1. They want 5 randomly generated numbers in 2
different trials.
0 0.740967 0.935937
1 1.519597 0.013860
2 0.259383 -0.824822
3 -0.744735 -0.039417
4 0.156586 -0.348059
Accessing Series
The revenue (in billion dollars) of different telecommunication operators in U.S. was collected for
the year of 2020. The following lists consist of the names of the telecommunication operators
and their respective revenue (in billion dollars).
In [11]: operators = ['AT&T', 'Verizon', 'T-Mobile US', 'US Cellular']
revenue = [171.76, 128.29, 68.4, 4.04]
#creating a Series from lists
telecom = pd.Series(revenue, index=operators)
telecom
Out[11]: AT&T 171.76
Verizon 128.29
T-Mobile US 68.40
US Cellular 4.04
dtype: float64
Accessing DataFrames
The data of the customers visiting 24/7 Stores from different locations was collected. The data
includes Customer ID, location of store, gender of the customer, type of product purchased,
quantity of products purchased, total bill amount. Let's create the dataset and see how to
access different entries of it.
loc method
loc is a method to access rows and columns on pandas objects. When using the loc
method on a dataframe, we specify which rows and which columns we want by using the
following format:
dataframe.loc[row selection, column selection]
DataFrame.loc[] method is a method that takes only index labels and returns row or
dataframe if the index label exists in the data frame.
In [24]: # accessing first index value using loc method (indexing starts from 0 in pytho
store_data.loc[1]
Out[24]: CustomerID CustID01
location Boston
gender M
type Food&Beverages
quantity 3
total_bill 75
Name: 1, dtype: object
Accessing selected rows and columns using loc method
In [25]: # accessing 1st and 4th index values along with location and type columns
store_data.loc[[1,4],['location','type']]
Out[25]: location type
1 Boston Food&Beverages
4 Austin Beauty
iloc method
The iloc indexer for Pandas Dataframe is used for integer location-based
indexing/selection by position. When using the loc method on a dataframe, we specify
which rows and which columns we want by using the following format:
dataframe.iloc[row selection, column selection]
1 CustID01 M
4 CustID04 F
loc is label-based, which means that you have to specify rows and columns based on their
row and column labels.
iloc is integer position-based, so you have to specify rows and columns by their integer
position values (0-based integer position).
/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py in __getitem__
(self, key)
923 with suppress(KeyError, IndexError):
924 return self.obj._get_value(*key, takeable=self._t
akeable)
--> 925 return self._getitem_tuple(key)
926 else:
927 # we by definition only have the 0th axis
/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py in _getitem_tu
ple(self, tup)
1504 def _getitem_tuple(self, tup: tuple):
1505
-> 1506 self._has_valid_tuple(tup)
1507 with suppress(IndexingError):
1508 return self._getitem_lowerdim(tup)
/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py in _has_valid_
tuple(self, key)
752 for i, k in enumerate(key):
753 try:
--> 754 self._validate_key(k, i)
755 except ValueError as err:
756 raise ValueError(
/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py in _validate_k
ey(self, key, axis)
1418 # check that the key has a numeric dtype
1419 if not is_numeric_dtype(arr.dtype):
-> 1420 raise IndexError(f".iloc requires numeric indexers, g
ot {arr}")
1421
1422 # check that the key does not exceed the maximum size of
the index
In [27]:
In [29]: store_data
In [31]: store_data['quantity']>1
Out[31]: 0 False
1 True
2 True
3 True
4 False
Name: quantity, dtype: bool
Wherever the condition of greater than 1 is satisfied in quantity column, 'True' is returned.
Let's retrieve the original values wherever the condition is satisfied.
In [32]: store_data.loc[store_data['quantity']>1]
In [33]: store_data
In [34]: # adding a new column in data frame store_data which is a rating (out of 5) giv
store_data['rating'] = [2,5,3,4,4]
store_data
Out[34]: CustomerID location gender type quantity total_bill rating
The CustomerID column is a unique identifier of each customer. This unique identifier will
not help 24/7 Stores in getting useful insights about their customers. So, they have decided
to remove this column from the data frame.
In [35]: store_data.drop('CustomerID',axis=1)
1 Boston M Food&Beverages 3 75 5
4 Austin F Beauty 1 80 4
We sucessfully removed the 'CustomerID' from dataframe. But this change is not
permanent in the dataframe, let's have a look at the store_data again.
In [36]: store_data
In [36]:
In [37]: store_data.drop('CustomerID',axis=1,inplace=True)
store_data
Out[37]: location gender type quantity total_bill rating
1 Boston M Food&Beverages 3 75 5
4 Austin F Beauty 1 80 4
Now the column has been permanently removed from the dataframe.
In [38]: # we can also remove multiple columns simultaneously
# it is always a good idea to store the new/updated data frames in new variable
# creating a copy of the existing data frame
new_store_data = store_data.copy()
store_data
Out[38]: location gender type quantity total_bill rating
1 Boston M Food&Beverages 3 75 5
4 Austin F Beauty 1 80 4
0 M Electronics 1 100
1 M Food&Beverages 3 75
2 F Food&Beverages 4 125
3 M Medicine 2 50
4 F Beauty 1 80
1 Boston M Food&Beverages 3 75 5
4 Austin F Beauty 1 80 4
4 Austin F Beauty 1 80 4
In [42]: store_data
Out[42]: location gender type quantity total_bill rating
1 Boston M Food&Beverages 3 75 5
4 Austin F Beauty 1 80 4
Notice that we used axis=0 to drop a row from a data frame, while we were using
axis=1 for dropping a column from the data frame.
Also, to make permanent changes to the data frame we will have to use inplace=True
parameter.
We also see that the index are not correct now as first row has been removed. So, we will
have to reset the index of the data frame. Let's see how this can be done.
4 Austin F Beauty 1 80 4
3 4 Austin F Beauty 1 80 4
We see that the index of the data frame is now resetted but the index has become a
column in the data frame. We do not need the index to become a column so we can simply
set the parameter drop=True in reset_index() function.
3 Austin F Beauty 1 80 4
1. concat
2. join
3. merge
In [47]: data_cust
Out[47]: customerID category first_visit sales
1 102 Medium no 52
4 101 12 123
5 103 9 214
6 104 44 663
7 105 21 331
In [49]: pd.concat([data_cust,data_cust_new],axis=0)
Out[49]: customerID category first_visit sales distance
In [50]: pd.concat([data_cust,data_cust_new],axis=1)
In [53]: pd.merge(data_cust,data_cust_new,how='right',on='customerID')
In [55]: data_quarters
Out[55]: Q1 Q2
I0 101 201
I1 102 202
I2 103 203
In [56]: data_quarters_new
Out[56]: Q3 Q4
I0 301 401
I2 302 402
I3 303 403
join behaves just like merge, except instead of using the values of one of the columns to
combine data frames, it uses the index labels
Note
In real-life scenario, we deal with much larger datasets that have thousands of rows and
multiple columns. It will not be feasible for us to create datasets using multiple lists, especially if
the number of columns and rows increases.
So, it is clear we need a more efficient way of handling the data simultaneously at the columns
and row levels. In Python, we can import dataset from our local system, from links, or from
databases and work on them directly instead of creating our own dataset.
When the data file and jupyter notebook are in the same folder.
In [58]: # Using pd.read_csv() function will work without any path if the notebook and d
# data = pd.read_csv('StockData.csv')
/usr/local/lib/python3.7/dist-packages/google/colab/drive.py in mount(mountpo
int, force_remount, timeout_ms, use_metadata_server)
111 timeout_ms=timeout_ms,
112 use_metadata_server=use_metadata_server,
--> 113 ephemeral=ephemeral)
114
115
/usr/local/lib/python3.7/dist-packages/google/colab/drive.py in _mount(mountp
oint, force_remount, timeout_ms, use_metadata_server, ephemeral)
134 if ephemeral:
135 _message.blocking_request(
--> 136 'request_auth', request={'authType': 'dfs_ephemeral'}, timeou
t_sec=None)
137
138 mountpoint = _os.path.expanduser(mountpoint)
/usr/local/lib/python3.7/dist-packages/google/colab/_message.py in blocking_r
equest(request_type, request, timeout_sec, parent)
173 request_id = send_request(
174 request_type, request, parent=parent, expect_reply=True)
--> 175 return read_reply_from_input(request_id, timeout_sec)
/usr/local/lib/python3.7/dist-packages/google/colab/_message.py in read_reply
_from_input(message_id, timeout_sec)
104 reply.get('colab_msg_id') == message_id):
105 if 'error' in reply:
--> 106 raise MessageError(reply['error'])
107 return reply.get('data', None)
108
Once we have access we can load files from google drive using read_csv() function.
In [ ]: # head() function helps us to see the first 5 rows of the data
data.head()
In [ ]: data_excel.head()
In [ ]:
In jupyter notebook, the dataset will be saved in the folder where the jupyter notebook is
located.
We can also save the dataset to a desired folder by providing the path/location of the folder.
In [ ]:
In [60]: data.head()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-60-304fa4ce4ebd> in <module>()
----> 1 data.head()
In [ ]: data.shape
In [ ]: data.info()
The price column is numeric in nature while the stock and date columns are of object types.
In [ ]: data['price'].min()
In [ ]: data['price'].max()
unique() - to check the number of unique values that are present in a column
In [ ]: data['stock'].unique()
value_counts() - to check the number of values that each unique quantity has in a
column
In [ ]: data['stock'].value_counts()
In [ ]: data['stock'].value_counts(normalize=True)
Statistical Functions
In [ ]: data['price'].mean()
median() - to check the median value of the column
In [ ]: data['price'].median()
In [ ]: data['stock'].mode()
To access a particular mode when the dataset has more than 1 mode
Group By function
Pandas dataframe.groupby() function is used to split the data into groups based on some
criteria.
In [ ]: data.groupby(['stock'])['price'].mean()
Here the groupby function is used to split the data into the 4 stocks that are present in the
dataset and then the mean price of each of the 4 stock is calculated.
Here the groupby function is used to split the data into the 4 stocks that are present in the
dataset and then the median price of each of the 4 stock is calculated.
The Pandas apply() function lets you to manipulate columns and rows in a DataFrame.
In [ ]: data['price'].apply(profit)
We observe that the date column is of object type whereas it should be of date time data
type.
In [ ]: data.info()
We observe that the date column has been converted to datetime format
In [ ]: data.head()
The column 'date' is now in datetime format. Now we can change the format of the date
to any other format
In [ ]: data['date'].dt.strftime('%m/%d/%Y')
In [ ]: data['date'].dt.strftime('%m-%d-%y')
In [ ]: data['date'].dt.year
Creating a new column and adding the extracted year values into the dataframe.
In [ ]: data['date'].dt.month
Creating a new column and adding the extracted month values into the dataframe.
In [ ]: data['date'].dt.day
Creating a new column and adding the extracted day values into the dataframe.
In [ ]: data.head()
We can see that year, month, and day columns have been added in the dataset.
In [ ]:
In [ ]: