Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 23

Data Transformation: Functions & New Columns

Recommended resources

Hello! Welcome to your next lesson on data manipulation with Pandas.

In our previous session, you learned the essential skills of filtering and sorting data. You now know how to select specific rows that meet your criteria and how to order them to make your dataset more interpretable. These are the foundational skills for exploring any new dataset.

Today, we move from selecting data to transforming it. This lesson will teach you how to modify your data by applying functions and how to create new columns from existing ones. This is a critical step in data cleaning and, more importantly for your goals, in feature engineering—the process of creating new, informative features for machine learning models. We'll explore several methods, from lightning-fast vectorized operations to the flexible but slower .apply() method, and learn when to use each one.

1. The Fastest Way: Vectorized Operations

Before reaching for more complex functions, you should always see if you can accomplish your goal with direct, or "vectorized," operations. Since your background is in computer science, you can think of this as similar to how NumPy leverages low-level, compiled code (C or Fortran) to perform operations on entire arrays at once, rather than iterating in Python. Pandas is built on NumPy and inherits this power.

If you want to create a new column by performing a simple arithmetic operation on other columns, this is the best and most efficient approach.

Pandas .apply(): What It Does, When It Helps, and Faster ...

This article from DataCamp provides a great overview of data transformation methods. Let's start by looking at their primary recommendation: vectorized operations.

Read the section "Recommended First Choice: Vectorized Operations". The code example shows how to create a 'RunDiff' column by simply subtracting one column from another. This is the 'Pandas-idiomatic' way to do things.

Let's solidify this with an example. Imagine a DataFrame grades:

import pandas as pd

grades_df = pd.DataFrame({
    'student': ['Alice', 'Bob', 'Charlie'],
    'midterm_score': [85, 91, 78],
    'final_score': [92, 88, 81]
})

To create a total_score column, you don't need a loop or a special function. You can just write:

grades_df['total_score'] = grades_df['midterm_score'] + grades_df['final_score']
print(grades_df)

Output:

   student  midterm_score  final_score  total_score
0    Alice             85           92          177
1      Bob             91           88          179
2  Charlie             78           81          159

This is clean, readable, and performs extremely well. Always try this first.


2. Transforming a Single Column: .map() and .apply()

What if your transformation isn't a simple arithmetic operation? For transformations on a single column (a Pandas Series), you have two main tools: .map() and .apply().

Using .map() for Value Substitution

The .map() method is perfect for substituting each value in a column with another value. It's most powerful when you provide a dictionary for the mapping. This is extremely common in machine learning for encoding categorical variables into numbers.

Python Pandas functions - map, apply and applymap

This video gives a clear, practical demonstration of using .map() to convert a categorical 'gender' column into numerical values (0 and 1).

Watch from 00:32 to 02:26. Notice how a Python dictionary is used to define the mapping from string categories to integer values. This is a very common preprocessing step.

As you saw, .map() is ideal for this kind of direct replacement. While you could achieve this with .apply(), .map() is significantly faster for this specific task.

Pandas: apply, map or transform?

This article from Towards Data Science provides a detailed comparison of these functions and includes performance benchmarks. Let's look at what it says about .map() vs. .apply().

Read the section titled "map". Pay close attention to the code example for encoding the 'gender' column and the subsequent performance comparison. A 10x speedup is significant!

Using .apply() for Custom Functions on a Series

When your transformation on a single column is more complex than a simple dictionary mapping, Series.apply() is your tool of choice. It takes a function (which can be a lambda function) and applies it to each element in the column.

Pandas Functions: Apply vs. Map vs. Applymap

This video provides a great visual and practical breakdown of how apply, map, and applymap differ. Let's focus on how apply works on a single column (a Series).

First, watch from the beginning to 01:53 to get a high-level visual overview of the different methods. Then, watch the practical example from 02:31 to 03:50, where a custom function is defined and then applied to the 'civil service title' column to change its case.


3. Creating New Columns from Multiple Columns: DataFrame.apply()

This is where the real power of .apply() on a DataFrame comes in. When you need to create a new column whose value depends on complex logic involving multiple other columns in the same row, and this logic can't be easily vectorized, DataFrame.apply() with axis=1 is the way to go.

When you use .apply(axis=1), Pandas iterates through each row of the DataFrame and passes the row (as a Series object) to your custom function. Your function can then access the values of that row using column names, perform its logic, and return a single value for the new column.

Applying Functions to Multiple Columns in Pandas
This diagram illustrates the concept of using `.apply(axis=1)`. A function takes values from columns in a row (like Latitude and Longitude) to compute a new value (like country) for that same row.

Let's see a concrete example.

Python Pandas functions - map, apply and applymap

Here's a perfect example of creating a 'total_experience' column by applying a function row by row to sum up values from three other columns.

Watch from 02:26 to 04:06. Notice how the custom function calculate_total_experience takes a row as input. Inside the function, you access the data for that specific row using row['column_name']. The axis=1 argument is what tells Pandas to operate row by row.

A Word on Performance: While incredibly flexible, DataFrame.apply(axis=1) is essentially a loop at the Python level. It can be slow on very large datasets. That's why it's important to always prefer vectorized operations when possible. Use .apply(axis=1) when your logic is too complex to be vectorized.

Test your understanding!

Given the grades_df from earlier:

grades_df = pd.DataFrame({
    'student': ['Alice', 'Bob', 'Charlie'],
    'midterm_score': [85, 91, 78],
    'final_score': [92, 88, 81]
})

Write a line of code using .apply() with axis=1 and a lambda function to create a new column called 'passed' which contains True if the student's final_score is greater than 85, and False otherwise.

Show answer
grades_df['passed'] = grades_df.apply(lambda row: row['final_score'] > 85, axis=1)
print(grades_df)

The output should be:

   student  midterm_score  final_score  passed
0    Alice             85           92    True
1      Bob             91           88    True
2  Charlie             78           81   False

(Note: A more efficient vectorized solution would be grades_df['passed'] = grades_df['final_score'] > 85, but this exercise is to practice the .apply() syntax.)


4. Advanced Topic: Returning Multiple Columns from apply

What if your function calculates several new values at once? Instead of running .apply() multiple times, you can write a function that returns a list or a Pandas Series. This is a more advanced pattern but is very efficient from a coding perspective.

Pandas .apply(): What It Does, When It Helps, and Faster ...

The DataCamp article we looked at earlier has a section on this exact topic. It shows how you can make your functions more powerful.

Read the section "Control the Output Shape From .apply()". Pay attention to the two patterns: returning a list and using result_type='expand', and returning a Pandas Series to automatically name the new columns.


5. Quick Mention: .applymap()

For completeness, there is one other method, .applymap(). It is used to apply a function to every single element in an entire DataFrame. Its use cases are less common, but you might use it to, for example, format all numbers in a table to a certain number of decimal places if all columns were numeric.

Think of it this way:

  • .map(): Element-wise on a Series.
  • .applymap(): Element-wise on a DataFrame.
  • .apply(): Row/column-wise on a DataFrame or element-wise on a Series.

Conclusion

You've now learned the primary methods for transforming data and creating new columns in Pandas. This is a huge step towards preparing data for analysis and machine learning.

Key Takeaways:

  • Vectorized Operations: Always your first choice for speed and simplicity (e.g., df['C'] = df['A'] + df['B']).
  • Series.map(): The best tool for substituting values in a single column, especially with a dictionary. It's fast and purpose-built for this task.
  • Series.apply(): Use this to apply a custom function to each element of a single column when a dictionary mapping isn't sufficient.
  • DataFrame.apply(axis=1): Your powerful, flexible tool for creating new columns when the logic requires values from multiple columns in the same row. Use it when vectorization isn't possible.
  • Performance Matters: Remember the general hierarchy from fastest to slowest: Vectorized operations > .map() > .apply().

Preview of the Next Lesson:
Transforming data can sometimes introduce or reveal missing values (NaN). In our next lesson, we'll tackle this head-on by learning how to handle missing data using various strategies like removal and imputation. This is another non-negotiable step in building robust data pipelines.