Python Data Analysis with Pandas Functions¶

Writing Parquet Files in Python with Pandas, PySpark, and Koalas

This notebook demonstrates selected Pandas functions. The text and code ideas below are selectively obtained from an article by Aryan Garg in the KDnuggets Newsletter.

List of Built-in Datasets from seaborn¶

In [28]:
import seaborn as sns
# Print without brackets and quotes:
dataset = sns.get_dataset_names()
print(", ".join(datasets))
anagrams, anscombe, attention, brain_networks, car_crashes, diamonds, dots, dowjones, exercise, flights, fmri, geyser, glue, healthexp, iris, mpg, penguins, planets, seaice, taxis, tips, titanic
In [ ]:
import seaborn as sns
# Print the dataset names as a vertical list
datasets = list(sns.get_dataset_names())
for i, name in enumerate(datasets, 1):
    print(f"{i}. {name}")

A. Data Viewing¶

1.	df.head() displays the first five rows of the sample data.
2.	df.tail() displays the last five rows of the sample data.
3.	df.sample(n) displays the random n number of rows in the sample data.
4.	df.shape displays the sample data's rows and columns (dimensions).
In [34]:
# import seaborn as sns
df = sns.load_dataset("titanic")
df.head()
Out[34]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
0 0 3 male 22.0 1 0 7.2500 S Third man True NaN Southampton no False
1 1 1 female 38.0 1 0 71.2833 C First woman False C Cherbourg yes False
2 1 3 female 26.0 0 0 7.9250 S Third woman False NaN Southampton yes True
3 1 1 female 35.0 1 0 53.1000 S First woman False C Southampton yes False
4 0 3 male 35.0 0 0 8.0500 S Third man True NaN Southampton no True
In [32]:
df.tail()
Out[32]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
886 0 2 male 27.0 0 0 13.00 S Second man True NaN Southampton no True
887 1 1 female 19.0 0 0 30.00 S First woman False B Southampton yes True
888 0 3 female NaN 1 2 23.45 S Third woman False NaN Southampton no False
889 1 1 male 26.0 0 0 30.00 C First man True C Cherbourg yes True
890 0 3 male 32.0 0 0 7.75 Q Third man True NaN Queenstown no True
In [36]:
df.sample(10)
Out[36]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
664 1 3 male 20.0 1 0 7.9250 S Third man True NaN Southampton yes False
106 1 3 female 21.0 0 0 7.6500 S Third woman False NaN Southampton yes True
494 0 3 male 21.0 0 0 8.0500 S Third man True NaN Southampton no True
511 0 3 male NaN 0 0 8.0500 S Third man True NaN Southampton no True
623 0 3 male 21.0 0 0 7.8542 S Third man True NaN Southampton no True
555 0 1 male 62.0 0 0 26.5500 S First man True NaN Southampton no True
855 1 3 female 18.0 0 1 9.3500 S Third woman False NaN Southampton yes False
127 1 3 male 24.0 0 0 7.1417 S Third man True NaN Southampton yes True
304 0 3 male NaN 0 0 8.0500 S Third man True NaN Southampton no True
282 0 3 male 16.0 0 0 9.5000 S Third man True NaN Southampton no True
In [38]:
df.shape
Out[38]:
(891, 15)

B. Statistics¶

1. df.describe() provides the basic statistics of each column of the sample data
2. df.info() provides information about the various data types used and the non-null count of each column.
3. df.corr(numeric_only=True) gives you the correlation matrix between all numeric columns in the data frame.
4. df.memory_usage() tells you how much memory is being consumed by each column.
In [43]:
df.describe()
Out[43]:
survived pclass age sibsp parch fare
count 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200
In [45]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
 #   Column       Non-Null Count  Dtype   
---  ------       --------------  -----   
 0   survived     891 non-null    int64   
 1   pclass       891 non-null    int64   
 2   sex          891 non-null    object  
 3   age          714 non-null    float64 
 4   sibsp        891 non-null    int64   
 5   parch        891 non-null    int64   
 6   fare         891 non-null    float64 
 7   embarked     889 non-null    object  
 8   class        891 non-null    category
 9   who          891 non-null    object  
 10  adult_male   891 non-null    bool    
 11  deck         203 non-null    category
 12  embark_town  889 non-null    object  
 13  alive        891 non-null    object  
 14  alone        891 non-null    bool    
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.7+ KB
In [55]:
df.corr(numeric_only=True)
Out[55]:
survived pclass age sibsp parch fare adult_male alone
survived 1.000000 -0.338481 -0.077221 -0.035322 0.081629 0.257307 -0.557080 -0.203367
pclass -0.338481 1.000000 -0.369226 0.083081 0.018443 -0.549500 0.094035 0.135207
age -0.077221 -0.369226 1.000000 -0.308247 -0.189119 0.096067 0.280328 0.198270
sibsp -0.035322 0.083081 -0.308247 1.000000 0.414838 0.159651 -0.253586 -0.584471
parch 0.081629 0.018443 -0.189119 0.414838 1.000000 0.216225 -0.349943 -0.583398
fare 0.257307 -0.549500 0.096067 0.159651 0.216225 1.000000 -0.182024 -0.271832
adult_male -0.557080 0.094035 0.280328 -0.253586 -0.349943 -0.182024 1.000000 0.404744
alone -0.203367 0.135207 0.198270 -0.584471 -0.583398 -0.271832 0.404744 1.000000
In [49]:
df.memory_usage()
Out[49]:
Index           132
survived       7128
pclass         7128
sex            7128
age            7128
sibsp          7128
parch          7128
fare           7128
embarked       7128
class          1023
who            7128
adult_male      891
deck           1247
embark_town    7128
alive          7128
alone           891
dtype: int64

C. Data Selection¶

Filtering Dataframes

1.	df.iloc[row_num] will select a particular row based on its index.
2.	df[col_name] will select the particular column.
3.	df[[‘col1’, ‘col2’]] will select multiple columns given.

In [62]:
df.iloc[1]
Out[62]:
survived               1
pclass                 1
sex               female
age                 38.0
sibsp                  1
parch                  0
fare             71.2833
embarked               C
class              First
who                woman
adult_male         False
deck                   C
embark_town    Cherbourg
alive                yes
alone              False
Name: 1, dtype: object
In [66]:
df['embark_town'] 
Out[66]:
0      Southampton
1        Cherbourg
2      Southampton
3      Southampton
4      Southampton
          ...     
886    Southampton
887    Southampton
888    Southampton
889      Cherbourg
890     Queenstown
Name: embark_town, Length: 891, dtype: object
In [72]:
df[['embark_town', 'embarked']] 
Out[72]:
embark_town embarked
0 Southampton S
1 Cherbourg C
2 Southampton S
3 Southampton S
4 Southampton S
... ... ...
886 Southampton S
887 Southampton S
888 Southampton S
889 Cherbourg C
890 Queenstown Q

891 rows × 2 columns

D. Data Cleaning¶

1. df.isnull() will identify the missing values in your dataframe.
2.df.dropna() will remove the rows containing missing values in any column.
3. df.fillna(val) will fill the missing values with val given in the argument.
4. df[‘col’].astype(new_data_type) can convert the data type of selected columns to a different data type.
5. wadf[‘col’].astype(new_data_type)can convert the data type of selected columns to a different data type.

df.isnull() checks every cell in the DataFrame for a missing value (NaN). It returns a DataFrame of True and False values:

  • True → the value is missing
  • False → the value is not missing
In [75]:
df.isnull()
Out[75]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
0 False False False False False False False False False False False True False False False
1 False False False False False False False False False False False False False False False
2 False False False False False False False False False False False True False False False
3 False False False False False False False False False False False False False False False
4 False False False False False False False False False False False True False False False
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
886 False False False False False False False False False False False True False False False
887 False False False False False False False False False False False False False False False
888 False False False True False False False False False False False True False False False
889 False False False False False False False False False False False False False False False
890 False False False False False False False False False False False True False False False

891 rows × 15 columns

df.dropna() removes rows that contain one or more missing values (NaN) from the DataFrame.

In [78]:
df.dropna()
Out[78]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
1 1 1 female 38.0 1 0 71.2833 C First woman False C Cherbourg yes False
3 1 1 female 35.0 1 0 53.1000 S First woman False C Southampton yes False
6 0 1 male 54.0 0 0 51.8625 S First man True E Southampton no True
10 1 3 female 4.0 1 1 16.7000 S Third child False G Southampton yes False
11 1 1 female 58.0 0 0 26.5500 S First woman False C Southampton yes True
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
871 1 1 female 47.0 1 1 52.5542 S First woman False D Southampton yes False
872 0 1 male 33.0 0 0 5.0000 S First man True B Southampton no True
879 1 1 female 56.0 0 1 83.1583 C First woman False C Cherbourg yes False
887 1 1 female 19.0 0 0 30.0000 S First woman False B Southampton yes True
889 1 1 male 26.0 0 0 30.0000 C First man True C Cherbourg yes True

182 rows × 15 columns

In [83]:
df['survived'].astype(bool)
Out[83]:
0      False
1       True
2       True
3       True
4      False
       ...  
886    False
887     True
888    False
889     True
890    False
Name: survived, Length: 891, dtype: bool

E. Data Analysis¶

1.	Aggregation Functions group a column by its name and then apply some aggregation functions like sum, min/max, mean, etc.
2.	Filtering Data:  You can filter the data in rows based on a specific value or a condition.
3.	Sorting Data: You can sort the data based on a specific column in ascending or descending order.
4.	Pivot Tables: You can create pivot tables that summarize the data using specific columns. This type of tables is very useful in analyzing the data when you only want to consider the effect of particular columns.
5.	Combining Data Frames: We can combine and merge several data frames horizontally or vertically. It will concatenate two data frames and return a single merged data frame.
6.	Applying Custom Functions: Depending on your needs, you can apply custom functions in either a row or a column.
7.	Applymap: We can also apply a custom function to every element of the dataframe in a single line of code. But remember that it applies to all the dataframe elements.

8. Time Series Analysis: In mathematics, time series analysis means analyzing the data collected over a specific time interval, and pandas have functions to perform this type of analysis.
9. Cross Tabulation: We can perform cross-tabulation between two table columns. It is generally a frequency table that shows the frequency of occurrences of various categories. It can help you to understand the distribution of categories across different regions.
10. Handling Outliers: Outliers in data means a particular point goes far beyond the average range.

1. Python aggregation functions ¶

You can group data by one or more columns and then apply functions such as sum(), min(), max(), and mean() to summarize the data.

In [88]:
df.groupby('sex')['fare'].mean()
Out[88]:
sex
female    44.479818
male      25.523893
Name: fare, dtype: float64

2. Filtering Data¶

You can filter rows in a DataFrame based on a specific value or condition.

In [ ]:
df[df['sex'] == 'female']
In [ ]:
df[df['age'] > 50]
In [92]:
df[(df['sex'] == 'female') & (df['age'] > 60)]
Out[92]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
275 1 1 female 63.0 1 0 77.9583 S First woman False D Southampton yes False
483 1 3 female 63.0 0 0 9.5875 S Third woman False NaN Southampton yes True
829 1 1 female 62.0 0 0 80.0000 NaN First woman False B NaN yes True

3a. Sorting Data¶

You can sort the data based on a specific column in ascending or descending order.

In [ ]:
df.sort_values('age')
df.sort_values('age', ascending=False)
df.sort_values(['sex', 'age'])

3b. Filtering and Sorting Data¶

You can filter rows based on specific conditions and then sort the resulting data by one or more columns.

In [ ]:
df[df['age'] > 50].sort_values('age')
df[df['age'] > 50].sort_values('age', ascending=False)

4. Pivot Tables¶

Use pivot_table() to summarize data by specific columns and apply aggregation functions such as mean(), sum(), and count().

Example: Mean age by sex¶

In [106]:
df.pivot_table(
    values='age',
    index='sex',
    aggfunc='mean'
)
Out[106]:
age
sex
female 27.915709
male 30.726645

Example: Average fare by sex and passenger class¶

In [111]:
df.pivot_table(
    values='fare',
    index='sex',
    columns='class',
    aggfunc='mean',
    observed=False
)
Out[111]:
class First Second Third
sex
female 106.125798 21.970121 16.118810
male 67.226127 19.741782 12.661633

5. Combining Data Frames¶

You can combine and merge several data frames horizontally or vertically. It will concatenate two data frames and return a single merged data frame.

  • Use pd.concat() to combine DataFrames vertically or horizontally
  • Use pd.merge() to combine DataFrames based on a common column or key

Concatenate vertically¶

Stack DataFrames row by row:

This is useful when df1 and df2 have the same or similar columns.

df_combined = pd.concat([df1, df2], ignore_index=True)

Concatenate horizontally¶

Place DataFrames side by side:

df_combined = pd.concat([df1, df2], axis=1)

This combines columns from both DataFrames based on their index.

Merge DataFrames¶

Use merge() when two DataFrames have a common column (key):

df_combined = pd.merge(df1, df2, on='id')

For example:

df_combined = pd.merge(
    df1,
    df2,
    on='id',
    how='inner'
)

Common how options are:

  • inner — only matching rows
  • left — all rows from df1
  • right — all rows from df2
  • outer — all rows from both DataFrames

6. Applying Custom Functions¶

Depending on your needs, you can apply custom functions in either a row or a column.

Example 1: Custom function¶

def categorize_age(age):
    if age < 18:
        return 'Child'
    elif age < 60:
        return 'Adult'
    else:
        return 'Senior'

df['age_group'] = df['age'].apply(categorize_age)

This creates a new age_group column based on the passenger's age.

Example 2: Using a lambda function¶

df['fare_double'] = df['fare'].apply(lambda x: x * 2)

This creates a new column containing twice the original fare.

Example 3: Custom function with multiple conditions¶

def fare_category(fare):
    if fare < 20:
        return 'Low'
    elif fare < 50:
        return 'Medium'
    else:
        return 'High'

df['fare_category'] = df['fare'].apply(fare_category)

A concise description for your lesson:

Applying Custom Functions: Use .apply() to apply a custom function to each value in a pandas Series or DataFrame.

7. Applymap¶

You can also apply a custom function to every element of the dataframe in a single line of code. But remember that it applies to all the dataframe elements.

 df = df.map(lambda x: str(x).upper())

Important distinction¶

  • Every cell in a DataFrame: df.map(function)
  • Every value in one column: df['column'].map(function)
  • Every row: df.apply(function, axis=1)
  • Every column: df.apply(function, axis=0)

For example, to multiply every numeric value by 2:¶

df = df.map(lambda x: x * 2 if isinstance(x, (int, float)) else x)

8. Time Series Analysis¶

In mathematics, time series analysis means analyzing the data collected over a specific time interval, and pandas have functions to perform this type of analysis.

Code yet to be added.

9. Cross Tabulation¶

You can perform cross-tabulation between two table columns. It is generally a frequency table that shows the frequency of occurrences of various categories. It can help you to understand the distribution of categories across different regions.

Use pd.crosstab() to summarize the relationship between two categorical columns by displaying their frequency counts.

Basic example

Using the Titanic dataset, cross-tabulate sex and survived:

pd.crosstab(df['sex'], df['survived'])

In [134]:
import pandas as pd
pd.crosstab(df['sex'], df['survived'])
Out[134]:
survived 0 1
sex
female 81 233
male 468 109

This produces a table showing the number of passengers by sex and survival status.

In [137]:
pd.crosstab(
    df['sex'],
    df['survived'],
    margins=True
)
Out[137]:
survived 0 1 All
sex
female 81 233 314
male 468 109 577
All 549 342 891

Cross-tabulation with percentages¶

To show percentages by row:

In [141]:
pd.crosstab(
    df['sex'],
    df['survived'],
    normalize='index'
)
Out[141]:
survived 0 1
sex
female 0.257962 0.742038
male 0.811092 0.188908

10. Handling Outliers¶

An outlier is a data point that is unusually far from the other observations or falls outside the expected range of the data.

1. Using the IQR method¶

A common way to detect outliers is the Interquartile Range (IQR) method.

In [146]:
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)

IQR = Q3 - Q1

outliers = df[
    (df['age'] < Q1 - 1.5 * IQR) |
    (df['age'] > Q3 + 1.5 * IQR)
]

outliers
Out[146]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
33 0 2 male 66.0 0 0 10.5000 S Second man True NaN Southampton no True
54 0 1 male 65.0 0 1 61.9792 C First man True B Cherbourg no False
96 0 1 male 71.0 0 0 34.6542 C First man True A Cherbourg no True
116 0 3 male 70.5 0 0 7.7500 Q Third man True NaN Queenstown no True
280 0 3 male 65.0 0 0 7.7500 Q Third man True NaN Queenstown no True
456 0 1 male 65.0 0 0 26.5500 S First man True E Southampton no True
493 0 1 male 71.0 0 0 49.5042 C First man True NaN Cherbourg no True
630 1 1 male 80.0 0 0 30.0000 S First man True A Southampton yes True
672 0 2 male 70.0 0 0 10.5000 S Second man True NaN Southampton no True
745 0 1 male 70.0 1 1 71.0000 S First man True B Southampton no False
851 0 3 male 74.0 0 0 7.7750 S Third man True NaN Southampton no True