2883. Drop Missing Data


Problem Description

In this task, you are given a DataFrame students that consists of three columns: student_id, name, and age. The student_id column holds integer values representing the unique ID of each student, name holds object values representing the names of the students which can be strings, and age contains integer values representing the students' ages. It has been noted that some entries in the name column are missing. The goal is to write a Python function that will process this DataFrame and remove any rows where the name is missing.

A missing value in a DataFrame can cause issues in data analysis and may not be suitable for some types of computations or algorithms that expect non-null values. Handling missing data is therefore a common preprocessing step. The result after processing should only include rows where the name has a valid non-null value.

The expected output is a DataFrame that no longer contains the rows with the missing name values, preserving all the other rows.

Intuition

To solve this problem, we need to consider an operation that can filter out rows based on the presence of missing values.

Pandas (the library being used) provides several methods for handling missing data. One of those methods is notnull(), which returns a Boolean series indicating whether each value in a DataFrame is not null. By applying notnull() to the name column, we get a series where each row has either True if the name is present or False if the name is missing.

We then use this series to filter the original DataFrame by passing it inside the square brackets [ ]. This is known as boolean indexing and it will only select the rows from students where the corresponding value in the boolean series is True. As a result, all rows with True will be kept and those with False will be removed.

The provided function dropMissingData simply performs this operation. It returns a new DataFrame without those rows that had missing name values, thus achieving the desired preprocessing step needed to clean the data.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

Breadth first search can be used to find the shortest path between two nodes in a directed graph.

Solution Approach

The implementation of the solution utilizes the capabilities of the Pandas library, which is specifically designed for data manipulation and analysis in Python. The solution approach is straightforward and involves the following steps:

  1. Use the notnull() method provided by Pandas to check which rows in the name column have non-missing data. This method is applied column-wise and generates a boolean mask where each value corresponds to a row in the DataFrame.

  2. This boolean mask has True values for rows where name is not null (i.e., not missing) and False for rows where name is null.

  3. Apply the boolean mask to the DataFrame using the square bracket notation []. This is a form of boolean indexing, a powerful feature provided by Pandas that allows for selecting data based on actual values rather than relying on traditional index locations.

  4. The DataFrame gets filtered: only rows with True in the boolean mask will be kept, effectively dropping the rows where name is missing.

The key data structure used in this solution is the DataFrame, which can be imagined as a table or a spreadsheet-like structure where data is organized into rows and columns. Each column can be of a different type and can be accessed or modified easily using Pandas' methods.

The algorithm pattern utilized is known as filtering. The notnull() method is crucial in this pattern as it provides the essential step of distinguishing the data to keep from the data to discard.

In summary, here's the pseudocode for the implemented solution, translating the steps into code operations:

1def dropMissingData(students):
2    # Step 1: Generate a boolean mask for non-missing 'name' values
3    valid_names_mask = students['name'].notnull()
4  
5    # Step 2: Apply the mask to the DataFrame, keeping only valid rows
6    clean_students = students[valid_names_mask]
7  
8    return clean_students

This function dropMissingData() when called with a DataFrame as an argument, returns a new DataFrame devoid of any rows with missing name values. The returned DataFrame is suitable for further data processing steps where complete information is required.

Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Which one best describes the time complexity of the following code?

1int factorial(int n) {
2  if (n < 0) {
3    return -1;
4  } else if (n == 0) {
5    return 1;
6  } else {
7    return n * factorial(n - 1);
8  }
9}

Example Walkthrough

Let's walk through a small example to illustrate the solution approach described above.

Suppose we have the following students DataFrame:

student_idnameage
1Alice20
2Null22
3Charlie21
4Null23
5Eve20

In this DataFrame, we can see that the name field is missing for student_id 2 and 4 (represented by Null for visualization purposes).

Following the steps of the solution:

  1. We apply the notnull() method to the name column to create a boolean mask. This gives us:
student_idnameagename.notnull()
1Alice20True
2Null22False
3Charlie21True
4Null23False
5Eve20True
  1. Now we have a boolean mask that indicates True for rows with a valid name and False for rows with a missing name.

  2. Next, we filter the original DataFrame by applying this boolean mask with square bracket notation. This leaves us with only the rows that have True in the mask:

student_idnameage
1Alice20
3Charlie21
5Eve20
  1. The resultant filtered DataFrame clean_students contains only the rows where name is not null.

And here is the actual code that would perform this filtering:

1import pandas as pd
2
3# Assume students is a DataFrame initialized with the provided data
4valid_names_mask = students['name'].notnull()
5clean_students = students[valid_names_mask]
6
7print(clean_students)

The expected output after running the code would be the clean_students DataFrame, which no longer contains the rows where the name was missing:

1   student_id     name  age
20           1    Alice   20
32           3  Charlie   21
44           5      Eve   20

This cleaned DataFrame is now ready for further analysis or processing without the problem of handling missing name values.

Solution Implementation

1import pandas as pd
2
3def dropMissingData(students: pd.DataFrame) -> pd.DataFrame:
4    # Drop rows from the 'students' DataFrame where the 'name' column has missing values.
5    # notnull() is used to select the rows where 'name' column is not NA/NaN
6    clean_students = students[students['name'].notnull()]
7    return clean_students
8
1import java.util.ArrayList;
2import java.util.List;
3import java.util.Map;
4import java.util.stream.Collectors;
5
6// A class to demonstrate the equivalent operation in Java, albeit with plain data structures
7public class DataFrameUtils {
8
9    /**
10     * Drops rows from a list of rows where the 'name' column has missing values.
11     * @param students List of Map entries representing rows of a student DataFrame.
12     * @return List of Map entries after removing rows with missing 'name'.
13     */
14    public static List<Map<String, String>> dropMissingData(List<Map<String, String>> students) {
15        // Use stream to filter out any rows where the 'name' value is null or empty
16        List<Map<String, String>> cleanStudents = students.stream()
17                .filter(row -> row.get("name") != null && !row.get("name").isEmpty())
18                .collect(Collectors.toList());
19        return cleanStudents;
20    }
21  
22    // Usage example
23    public static void main(String[] args) {
24        List<Map<String, String>> students = new ArrayList<>();
25        // Populate the list 'students' with data
26        // ...
27
28        List<Map<String, String>> cleanStudents = dropMissingData(students);
29        // ...
30    }
31}
32
1#include <iostream>
2#include <vector>
3#include <optional>
4#include <algorithm>
5
6// Define a structure for Student which holds an optional name and other attributes
7struct Student {
8    std::optional<std::string> name;
9    // Add other attributes for Student if needed
10};
11
12// Function to drop rows from a vector of Student structs where the 'name' is missing
13std::vector<Student> DropMissingData(const std::vector<Student>& students) {
14    // Create a new vector to store students with valid names
15    std::vector<Student> cleanStudents;
16
17    // Use the copy_if algorithm to copy only those students whose name is present
18    std::copy_if(
19        students.begin(), students.end(), 
20        std::back_inserter(cleanStudents),
21        [](const Student& s) {
22            return s.name.has_value(); // Check if 'name' is not missing
23        }
24    );
25
26    // Return the new vector with all students that have a name
27    return cleanStudents;
28}
29
30// Assuming you have some method to populate the students vector
31std::vector<Student> populateStudents();
32
33int main() {
34    // Populate your students vector (assuming this function is implemented)
35    std::vector<Student> students = populateStudents();
36
37    // Use the DropMissingData function to remove students without a name
38    std::vector<Student> studentsWithNames = DropMissingData(students);
39
40    // Now studentsWithNames contains only students with non-missing names
41    // Process the clean list as required...
42
43    return 0;
44}
45
1interface Student {
2  name?: string; // The '?' denotes that the 'name' property is optional and can be undefined
3  // include other student properties as needed
4}
5
6function dropMissingData(students: Student[]): Student[] {
7  // Drop objects from the 'students' array where the 'name' property is missing or undefined
8  let cleanStudents: Student[] = students.filter(student => student.name != null);
9  // The 'filter' method goes through each student and keeps those where 'name' is not 'null' or 'undefined'
10
11  return cleanStudents;
12}
13
Not Sure What to Study? Take the 2-min Quiz:

In a binary min heap, the minimum element can be found in:

Time and Space Complexity

The given function dropMissingData is intended to remove rows from a pandas DataFrame where the values in the 'name' column are missing. Below is the time and space complexity of the provided function:

Time Complexity: The function uses notnull() method combined with the DataFrame indexing to filter out rows with non-null 'name' values. The time complexity of notnull() and the boolean indexing in pandas is linear with respect to the number of rows, n, since each element in the 'name' column needs to be checked once for a null condition. Therefore, the time complexity can be expressed as O(n).

Space Complexity: Since pandas often uses views instead of copies, the space complexity for the filtering operation is O(1). However, if a copy is created during the operation due to pandas internal optimizations based on the DataFrame size or data types, the space complexity could be O(n) as a new DataFrame object is created to hold the filtered data. In the worst case, we consider the space complexity to be O(n).

Fast Track Your Learning with Our Quick Skills Quiz:

How would you design a stack which has a function min that returns the minimum element in the stack, in addition to push and pop? All push, pop, min should have running time O(1).


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫