About this course
<p>Data analysis might sound complicated when you first encounter it. You might imagine large databases, advanced mathematics, and complicated machine learning algorithms.</p>
<p>But many useful data analysis tasks start with something much simpler: loading a dataset, asking questions about it, and using Python to find the answers.</p>
<p>In this tutorial, you'll build a simple data analyzer using Python and pandas. You'll work with a fictional student performance dataset and learn how to load data, inspect it, calculate statistics, filter records, group information, and create a basic visualization.</p>
<p>By the end, you'll have a reusable foundation for analyzing many types of CSV datasets.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before following this tutorial, you should have a few basic Python skills and tools ready. You don't need advanced programming or data analysis experience, but you should be familiar with:</p>
<ul>
<li>Python variables and basic data types, such as strings and numbers.</li>
<li>Importing libraries and calling functions.</li>
<li>Working with lists and basic operations on data.</li>
</ul>
<p>If you're new to Python, consider learning these fundamentals before continuing. Here's an i<a href="https://www.freecodecamp.org/news/learn-python-interactively/">nteractive Python course to get you started</a> if you want to go deep.</p>
<p>Also, make sure you have the following installed:</p>
<ul>
<li><strong>Python:</strong> Python 3 or a compatible Python installation.</li>
<li><strong>pandas:</strong> The Python library we'll use to load, filter, group, and analyze data.</li>
<li><strong>Matplotlib:</strong> The library we'll use to create visualizations.</li>
<li><strong>A code editor or IDE:</strong> Such as VS Code, PyCharm, or a simple text editor, along with access to a terminal.</li>
</ul>
<p>You can install pandas and Matplotlib by running the following command in your terminal:</p>
<pre><code class="language-bash">pip install pandas matplotlib
</code></pre>
<p>You'll also need a folder where you can save your Python script and the <code>students.csv</code> dataset we'll create in this tutorial.</p>
<p>Once everything is ready, you can start analyzing data with Python!</p>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ul>
<li><a href="#heading-setting-up-your-environment">Setting Up Your Environment</a></li>
<li><a href="#heading-creating-the-dataset">Creating the Dataset</a></li>
<li><a href="#heading-loading-the-dataset-with-pandas">Loading the Dataset with Pandas</a></li>
<li><a href="#heading-exploring-the-data">Exploring the Data</a></li>
<li><a href="#heading-calculating-basic-statistics">Calculating Basic Statistics</a></li>
<li><a href="#heading-filtering-data">Filtering Data</a></li>
<li><a href="#heading-finding-specific-students">Finding Specific Students</a></li>
<li><a href="#heading-grouping-data">Grouping Data</a></li>
<li><a href="#heading-analyzing-study-time">Analyzing Study Time</a></li>
<li><a href="#heading-creating-a-visualization">Creating a Visualization</a></li>
<li><a href="#heading-building-the-complete-analyzer">Building the Complete Analyzer</a></li>
<li><a href="#heading-making-the-analyzer-more-reusable">Making the Analyzer More Reusable</a></li>
<li><a href="#heading-handling-missing-data">Handling Missing Data</a></li>
<li><a href="#heading-exporting-results">Exporting Results</a></li>
<li><a href="#heading-common-mistakes-to-avoid">Common Mistakes to Avoid</a></li>
<li><a href="#heading-where-to-go-from-here">Where to Go From Here</a></li>
<li><a href="#heading-final-thoughts">Final Thoughts</a></li>
</ul>
<h2 id="heading-setting-up-your-environment">Setting Up Your Environment</h2>
<h3 id="heading-installing-pandas">Installing pandas</h3>
<p>If you don't already have pandas installed, open your terminal and run:</p>
<pre><code class="language-python">pip install pandas matplotlib
</code></pre>
<p>We'll use pandas for data analysis and Matplotlib for a simple visualization.</p>
<p>You can verify the installation with:</p>
<pre><code class="language-python">import pandas as pd
import matplotlib.pyplot as plt
print(pd.__version__)
</code></pre>
<p>If Python prints a version number, you're ready to go.</p>
<h2 id="heading-creating-the-dataset">Creating the Dataset</h2>
<h3 id="heading-creating-a-csv-file">Creating a CSV File</h3>
<p>We'll start by creating a file called <code>students.csv</code> and adding some data.</p>
<p>The dataset we'll be working with here is fictional and contains 12 student records across grades 9 through 12. Each row represents one student, and each column describes a different attribute:</p>
<ul>
<li><code>name</code>: The student's first name.</li>
<li><code>grade</code>: The student's current grade level in school.</li>
<li><code>study_hours</code>: The number of hours the student studied.</li>
<li><code>attendance</code>: The student's attendance percentage.</li>
<li><code>score</code>: The student's test score, recorded on a 0–100 scale.</li>
</ul>
<p>For example, Ava is in grade 9, studied for 4.5 hours, has 95% attendance, and received a test score of 82. These sample records let us explore questions such as whether study time is associated with test scores and how average scores compare across grade levels.</p>
<p>Because the data is fictional and small, any patterns we observe are only illustrative, and we shouldn't treat them as evidence about students in general.</p>
<p>But our data will give us enough information to perform several useful analyses. Here it is:</p>
<pre><code class="language-csv">name,grade,study_hours,attendance,score
Ava,9,4.5,95,82
Liam,9,6.0,98,91
Sophia,10,3.5,89,76
Noah,10,7.0,99,94
Emma,11,5.5,93,88
Oliver,11,8.0,97,96
Mia,12,4.0,91,79
Ethan,12,6.5,96,90
Isabella,9,7.5,100,97
Lucas,10,2.5,85,68
Amelia,11,6.0,94,92
James,12,5.0,90,84
</code></pre>
<h2 id="heading-loading-the-dataset-with-pandas">Loading the Dataset with Pandas</h2>
<h3 id="heading-reading-the-csv-file">Reading the CSV File</h3>
<p>Start your Python program by importing pandas:</p>
<pre><code class="language-python">import pandas as pd
</code></pre>
<p>Then load the CSV file:</p>
<pre><code class="language-python">data = pd.read_csv("students.csv")
</code></pre>
<p>The <code>read_csv()</code> function reads the CSV file and converts it into a pandas DataFrame.</p>
<p>A DataFrame is a table-like data structure with rows and columns. You can think of it as a programmable spreadsheet.</p>
<p>Let's display the dataset:</p>
<pre><code class="language-python">print(data)
</code></pre>
<p>You should see the student records printed in your terminal.</p>
<h2 id="heading-exploring-the-data">Exploring the Data</h2>
<p>Before analyzing a dataset, it's useful to understand what you're working with.</p>
<h3 id="heading-viewing-the-first-rows">Viewing the First Rows</h3>
<p>The <code>head()</code> method displays the first five rows:</p>
<pre><code class="language-python">print(data.head())
</code></pre>
<p>You can also specify how many rows you want:</p>
<pre><code class="language-python">print(data.head(3))
</code></pre>
<h3 id="heading-checking-the-dataset-size">Checking the Dataset Size</h3>
<p>Use <code>shape</code> to find the number of rows and columns:</p>
<pre><code class="language-python">print(data.shape)
</code></pre>
<p>The result will be:</p>
<pre><code class="language-text">(12, 5)
</code></pre>
<p>That means our dataset contains 12 rows and 5 columns.</p>
<h3 id="heading-examining-column-names">Examining Column Names</h3>
<p>You can view the column names with:</p>
<pre><code class="language-python">print(data.columns)
</code></pre>
<p>This is useful when you need to reference columns later in your program.</p>
<h3 id="heading-checking-data-types">Checking Data Types</h3>
<p>Use <code>info()</code> to see information about each column:</p>
<pre><code class="language-python">data.info()
</code></pre>
<p>This helps you identify whether columns contain integers, decimal numbers, text, or other types of data.</p>
<h2 id="heading-calculating-basic-statistics">Calculating Basic Statistics</h2>
<p>Pandas makes it easy to calculate statistics without manually writing the mathematical formulas.</p>
<h3 id="heading-finding-the-average-score">Finding the Average Score</h3>
<p>We can calculate the average score using:</p>
<pre><code class="language-python">average_score = data["score"].mean()
print(f"Average score: {average_score:.2f}")
</code></pre>
<p>The <code>mean()</code> method calculates the arithmetic average.</p>
<p>The <code>:.2f</code> formatting tells Python to display the result with two decimal places.</p>
<h3 id="heading-finding-the-highest-and-lowest-scores">Finding the Highest and Lowest Scores</h3>
<p>Use <code>max()</code> and <code>min()</code>:</p>
<pre><code class="language-python">highest_score = data["score"].max()
lowest_score = data["score"].min()
print(f"Highest score: {highest_score}")
print(f"Lowest score: {lowest_score}")
</code></pre>
<p>You can also find the median:</p>
<pre><code class="language-python">median_score = data["score"].median()
print(f"Median score: {median_score}")
</code></pre>
<p>The median is the middle value when the scores are ordered.</p>
<h3 id="heading-generating-a-statistical-summary">Generating a Statistical Summary</h3>
<p>Pandas also provides a convenient <code>describe()</code> method:</p>
<pre><code class="language-python">print(data["score"].describe())
</code></pre>
<p>This produces statistics such as:</p>
<ul>
<li>Count</li>
<li>Mean</li>
<li>Standard deviation</li>
<li>Minimum</li>
<li>25th percentile</li>
<li>Median</li>
<li>75th percentile</li>
<li>Maximum</li>
</ul>
<p>You can generate a summary for all numerical columns:</p>
<pre><code class="language-python">print(data.describe())
</code></pre>
<p>This is often one of the first commands you'll use when exploring an unfamiliar dataset.</p>
<h2 id="heading-filtering-data">Filtering Data</h2>
<p>One of the most useful features of pandas is the ability to select rows based on conditions.</p>
<h3 id="heading-finding-students-with-high-scores">Finding Students With High Scores</h3>
<p>Suppose we want to find students who scored at least 90:</p>
<pre><code class="language-python">high_scores = data[data["score"] >= 90]
print(high_scores)
</code></pre>
<p>The expression:</p>
<pre><code class="language-python">data["score"] >= 90
</code></pre>
<p>creates a Boolean condition for every row. Pandas then keeps only the rows where that condition is <code>True</code>.</p>
<h3 id="heading-finding-students-who-study-more-than-five-hours">Finding Students Who Study More Than Five Hours</h3>
<p>We can perform the same operation using study time:</p>
<pre><code class="language-python">frequent_studiers = data[data["study_hours"] > 5]
print(frequent_studiers)
</code></pre>
<p>You can combine multiple conditions as well.</p>
<p>For example, suppose we want students who study more than five hours and have an attendance rate above 95 percent:</p>
<pre><code class="language-python">students = data[
(data["study_hours"] > 5) &
(data["attendance"] > 95)
]
print(students)
</code></pre>
<p>When combining conditions in pandas, use <code>&</code> for AND and <code>|</code> for OR. Each condition should be enclosed in parentheses.</p>
<h2 id="heading-finding-specific-students">Finding Specific Students</h2>
<h3 id="heading-using-idxmax">Using <code>idxmax()</code></h3>
<p>Sometimes you don't just want the highest value. You want to know which record contains it.</p>
<p>For example:</p>
<pre><code class="language-python">top_student_index = data["score"].idxmax()
top_student = data.loc[top_student_index]
print(top_student)
</code></pre>
<p><code>idxmax()</code> returns the index of the row containing the largest value.</p>
<p>We can do the same for study hours:</p>
<pre><code class="language-python">most_studious_index = data["study_hours"].idxmax()
most_studious_student = data.loc[most_studious_index]
print(most_studious_student)
</code></pre>
<p>This lets you connect a statistic back to the original record.</p>
<h2 id="heading-grouping-data">Grouping Data</h2>
<p>Grouping becomes particularly useful when your dataset contains categories.</p>
<p>In our dataset, students belong to different grades.</p>
<h3 id="heading-average-score-by-grade">Average Score by Grade</h3>
<p>We can calculate the average score for each grade:</p>
<pre><code class="language-python">average_by_grade = data.groupby("grade")["score"].mean()
print(average_by_grade)
</code></pre>
<p>This tells us how the average score differs between grades.</p>
<p>We can make the output easier to read:</p>
<pre><code class="language-python">average_by_grade = (
data.groupby("grade")["score"]
.mean()
.round(2)
)
print(average_by_grade)
</code></pre>
<h3 id="heading-multiple-statistics">Multiple Statistics</h3>
<p>You can calculate several statistics at once:</p>
<pre><code class="language-python">grade_summary = data.groupby("grade")["score"].agg(
["mean", "min", "max", "count"]
)
print(grade_summary)
</code></pre>
<p>This produces a summary for each grade containing the average, minimum, maximum, and number of students.</p>
<h2 id="heading-analyzing-study-time">Analyzing Study Time</h2>
<p>We can also investigate the relationship between study hours and scores.</p>
<h3 id="heading-calculating-correlation">Calculating Correlation</h3>
<p>Pandas provides a <code>corr()</code> method:</p>
<pre><code class="language-python">correlation = data["study_hours"].corr(data["score"])
print(f"Correlation: {correlation:.2f}")
</code></pre>
<p>The correlation value generally ranges from -1 to 1.</p>
<p>A value closer to 1 indicates a stronger positive linear relationship, while a value closer to -1 indicates a stronger negative linear relationship. A value near 0 indicates little linear relationship.</p>
<p>However, correlation does <strong>not</strong> prove that one variable causes another. For example, if study hours and scores are correlated in this dataset, that doesn't prove that studying more directly caused higher scores.</p>
<h2 id="heading-creating-a-visualization">Creating a Visualization</h2>
<p>Numbers are useful, but visualizations can make patterns easier to recognize.</p>
<h3 id="heading-creating-a-scatter-plot">Creating a Scatter Plot</h3>
<p>We'll create a scatter plot showing study hours and test scores:</p>
<pre><code class="language-python">import matplotlib.pyplot as plt
plt.scatter(data["study_hours"], data["score"])
plt.xlabel("Study Hours")
plt.ylabel("Test Score")
plt.title("Study Hours vs. Test Scores")
plt.show()
</code></pre>
<p>Each point represents one student.</p>
<p>The x-axis represents study hours, while the y-axis represents test scores.</p>
<p>You may notice whether the points appear to generally move upward as study time increases.</p>
<p>This is what it should look like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/0c26d632-eaa4-4d4e-b6c2-b0bfb2d1f240.png" alt="Matplotlib Scatterplot Output" style="display: block;" width="838" height="679" loading="lazy">
<h3 id="heading-creating-a-bar-chart">Creating a Bar Chart</h3>
<p>We can also visualize the average score for each grade:</p>
<pre><code class="language-python">average_by_grade = data.groupby("grade")["score"].mean()
average_by_grade.plot(kind="bar")
plt.xlabel("Grade")
plt.ylabel("Average Score")
plt.title("Average Score by Grade")
plt.show()
</code></pre>
<p>A bar chart makes it easier to compare the averages between groups.</p>
<p>This is what the bar chart should look like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/64871076-8748-415f-addf-2707543e8861.png" alt="Matplotlib Bar Chart Output" style="display: block;" width="841" height="682" loading="lazy">
<h2 id="heading-building-the-complete-analyzer">Building the Complete Analyzer</h2>
<p>Now let's combine the main ideas into one program.</p>
<pre><code class="language-python">import pandas as pd
import matplotlib.pyplot as plt
# Load the dataset
data = pd.read_csv("students.csv")
# Basic information
print("Dataset shape:")
print(data.shape)
print("\nFirst five rows:")
print(data.head())
# Score statistics
average_score = data["score"].mean()
median_score = data["score"].median()
highest_score = data["score"].max()
lowest_score = data["score"].min()
print("\nScore Statistics")
print(f"Average: {average_score:.2f}")
print(f"Median: {median_score:.2f}")
print(f"Highest: {highest_score}")
print(f"Lowest: {lowest_score}")
# Students with scores of 90 or higher
high_scores = data[data["score"] >= 90]
print("\nStudents with scores of 90 or higher:")
print(high_scores[["name", "score"]])
# Average score by grade
average_by_grade = (
data.groupby("grade")["score"]
.mean()
.round(2)
)
print("\nAverage Score by Grade:")
print(average_by_grade)
# Study hours and score correlation
correlation = data["study_hours"].corr(data["score"])
print(f"\nStudy Hours vs. Score Correlation: {correlation:.2f}")
# Scatter plot
plt.scatter(data["study_hours"], data["score"])
plt.xlabel("Study Hours")
plt.ylabel("Test Score")
plt.title("Study Hours vs. Test Scores")
plt.show()
</code></pre>
<p>This program now performs a small but complete data analysis workflow.</p>
<h2 id="heading-making-the-analyzer-more-reusable">Making the Analyzer More Reusable</h2>
<p>A useful next step is turning repeated operations into functions.</p>
<h3 id="heading-creating-an-analysis-function">Creating an Analysis Function</h3>
<p>Instead of writing everything directly in the main program, we can create a function:</p>
<pre><code class="language-python">def analyze_scores(data):
average = data["score"].mean()
median = data["score"].median()
highest = data["score"].max()
lowest = data["score"].min()
print(f"Average score: {average:.2f}")
print(f"Median score: {median:.2f}")
print(f"Highest score: {highest}")
print(f"Lowest score: {lowest}")
</code></pre>
<p>Then call it with:</p>
<pre><code class="language-python">analyze_scores(data)
</code></pre>
<p>This makes the code easier to reuse with another DataFrame.</p>
<h3 id="heading-creating-a-function-for-top-students">Creating a Function for Top Students</h3>
<p>We can also create a function that returns the highest-scoring students:</p>
<pre><code class="language-python">def get_top_students(data, minimum_score=90):
return data[data["score"] >= minimum_score][
["name", "grade", "score"]
]
</code></pre>
<p>Now we can change the threshold whenever we want:</p>
<pre><code class="language-python">print(get_top_students(data, 95))
</code></pre>
<p>Functions like these become especially valuable when your analyzer grows.</p>
<h2 id="heading-handling-missing-data">Handling Missing Data</h2>
<p>Real-world datasets are rarely as clean as our example. You may encounter missing values sometimes.</p>
<p>You can check for missing values with:</p>
<pre><code class="language-python">print(data.isnull().sum())
</code></pre>
<p>This tells you how many missing values exist in each column.</p>
<p>For example, you could remove rows containing missing values with:</p>
<pre><code class="language-python">clean_data = data.dropna()
</code></pre>
<p>Or, depending on the dataset and what the missing value means, you might replace missing values:</p>
<pre><code class="language-python">data["score"] = data["score"].fillna(data["score"].mean())
</code></pre>
<p>You should not automatically replace every missing value with an average. The appropriate approach depends on what the missing data represents and what you're trying to analyze.</p>
<h2 id="heading-exporting-results">Exporting Results</h2>
<p>After analyzing a dataset, you may want to save your results.</p>
<p>For example:</p>
<pre><code class="language-python">average_by_grade.to_csv("average_scores_by_grade.csv")
</code></pre>
<p>You can also save filtered records:</p>
<pre><code class="language-python">high_scores.to_csv("high_scoring_students.csv", index=False)
</code></pre>
<p>The <code>index=False</code> argument prevents pandas from adding the DataFrame's index as an extra column.</p>
<h2 id="heading-common-mistakes-to-avoid">Common Mistakes to Avoid</h2>
<h3 id="heading-forgetting-to-import-libraries">Forgetting to Import Libraries</h3>
<p>Make sure the required libraries are imported:</p>
<pre><code class="language-python">import pandas as pd
import matplotlib.pyplot as plt
</code></pre>
<p>Otherwise, Python won't know what <code>pd</code> or <code>plt</code> means.</p>
<h3 id="heading-using-the-wrong-column-name">Using the Wrong Column Name</h3>
<p>Column names must match your dataset.</p>
<p>For example, if the column is called <code>study_hours</code>, this won't work:</p>
<pre><code class="language-python">data["study time"]
</code></pre>
<p>You can always check the actual column names with:</p>
<pre><code class="language-python">print(data.columns)
</code></pre>
<h3 id="heading-confusing-correlation-with-causation">Confusing Correlation With Causation</h3>
<p>A correlation can identify a relationship between variables, but it doesn't establish that one variable caused another.</p>
<p>This distinction becomes increasingly important as you work with larger and more complicated datasets.</p>
<h3 id="heading-analyzing-before-understanding-the-data">Analyzing Before Understanding the Data</h3>
<p>It's tempting to immediately calculate statistics. But first inspect the dataset.</p>
<p>Useful starting commands include:</p>
<pre><code class="language-python">data.head()
data.shape
data.info()
data.describe()
data.isnull().sum()
</code></pre>
<p>Understanding the structure and quality of your data helps prevent incorrect conclusions.</p>
<h2 id="heading-where-to-go-from-here">Where to Go From Here</h2>
<p>The analyzer you've built is intentionally simple, but the same workflow can be applied to much larger datasets.</p>
<p>You could extend it to:</p>
<ul>
<li>Analyze sales data</li>
<li>Track website traffic</li>
<li>Study survey responses</li>
<li>Analyze marketing campaigns</li>
<li>Examine sports statistics</li>
<li>Explore financial datasets</li>
<li>Track application or customer data</li>
</ul>
<p>You could also add more advanced features such as interactive charts, command-line arguments, automated reports, or machine learning models.</p>
<p>For example, instead of hard-coding the CSV filename, you could let the user provide one:</p>
<pre><code class="language-python">filename = input("Enter the CSV filename: ")
data = pd.read_csv(filename)
print(data.head())
</code></pre>
<p>Now the same program can analyze different CSV files.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>You don't need complicated algorithms to start working with data. With Python, pandas, and a relatively small dataset, you can already perform meaningful analysis.</p>
<p>In this tutorial, you learned how to:</p>
<ul>
<li>Load CSV data with pandas</li>
<li>Explore a DataFrame</li>
<li>Calculate statistics</li>
<li>Filter rows</li>
<li>Find specific records</li>
<li>Group data</li>
<li>Calculate correlations</li>
<li>Create visualizations</li>
<li>Handle missing values</li>
<li>Export analysis results</li>
<li>Organize analysis with functions</li>
</ul>
<p>The most important next step is to practice with different datasets. Once you're comfortable loading, exploring, cleaning, and analyzing data with pandas, you can start building much more sophisticated data-analysis projects.</p>
<p>Happy coding!</p>