
In the world of machine learning and data analysis, data is like raw material, and its quality directly determines the performance of the final model and the reliability of the analysis conclusions. However, raw data in reality is often filled with various “impurities”—missing values, duplicate records, outliers, formatting errors, etc. These issues can severely disrupt the subsequent modeling process. Therefore, data cleaning and preprocessing are akin to screening and polishing raw materials, making them an indispensable key step in the entire data workflow.
The Core Significance of Data Cleaning
Data cleaning is essentially a process of “removing the false and preserving the true”. By systematically identifying and addressing errors, incomplete, duplicate, or inconsistent information in the data, raw data is transformed into a clean, standardized, and usable form. The value of this process is reflected in three aspects:
- Improving Data Quality: Eliminating “noise” in the data to ensure accuracy and consistency.
- Reducing Modeling Risks: Avoiding model bias or erroneous conclusions caused by poor-quality data.
- Enhancing Analysis Efficiency: Laying a solid foundation for subsequent exploratory analysis, feature engineering, and model training.
It can be said that without proper cleaning, even the most advanced algorithms cannot perform effectively. As a saying in the field of data science goes: “Garbage In, Garbage Out”.
The Complete Process of Data Cleaning and Preprocessing
1. Environment Setup and Tool Import
Before starting to process data, it is necessary to set up a suitable analysis environment and import the necessary tool libraries. In the Python ecosystem, the following libraries are core tools for data cleaning:
import pandas as pd # Core library for data processing and analysis
import numpy as np # Provides efficient numerical computation support
import matplotlib.pyplot as plt # Basic library for data visualization
import seaborn as sns # Advanced visualization tool, especially suitable for statistical charts
# Configure Chinese display to avoid garbled characters in charts
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
# Set pandas display parameters to ensure that columns are not truncated when viewing data
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)
These tool libraries provide complete functionality from data reading, processing to visualization, with pandas’ DataFrame data structure being the core carrier for data cleaning, capable of efficiently handling structured data.
2. Data Loading: Acquiring Raw Data
The first step in data cleaning is to load the raw data into the analysis environment. Depending on the data storage format, different loading methods need to be adopted:
# Load CSV file
df_csv = pd.read_csv('data.csv', sep=',', na_values=['NA', '未知'])
# Load Excel file (supports multiple sheets)
excel_handler = pd.ExcelFile('data.xlsx')
df_excel = excel_handler.parse('Sheet1') # Read specified sheet
# Check data scale, quickly understand dataset size
print(f"The dataset contains {df_csv.shape[0]} rows and {df_csv.shape[1]} columns")
When loading data, it is important to specify the correct delimiter, missing value indicators, and other parameters to ensure that the data can be correctly parsed. For large datasets, the usecols parameter can also be used to specify the columns to be loaded, improving loading efficiency.
3. Initial Data Exploration: Understanding Your Data
Before starting substantial cleaning, a comprehensive exploration of the data is needed to establish a basic understanding of the dataset. Common methods include:
# View basic information about the data: data types, number of non-null values, memory usage
print("Basic information about the data:")
df.info()
# Preview data content (default first 5 rows)
print("\nPreview of the first 5 rows:")
print(df.head())
# Analyze statistical characteristics of numerical columns
print("\nStatistical description of numerical columns:")
print(df.describe()) # Includes mean, standard deviation, min, quartiles, etc.
# Analyze the distribution of categorical columns
print("\nValue distribution of categorical columns:")
for col in df.select_dtypes(include=['object', 'category']).columns:
print(f"\nValue distribution of column {col}:")
print(df[col].value_counts())
Through these operations, potential issues in the data can be quickly identified: for example, certain columns may have many missing values, the distribution of numerical columns may be abnormal, or there may be inconsistencies in the spelling of categorical columns, guiding the subsequent cleaning work.
4. Handling Missing Values: Filling Data Gaps
Missing values are one of the most common issues in data, which may be caused by data collection errors, lost records, and other reasons. Handling missing values requires two steps:
Detecting Missing Values:
# Calculate the number and proportion of missing values for each column
missing_stats = pd.DataFrame({
'Number of Missing Values': df.isnull().sum(),
'Missing Proportion': df.isnull().sum() / len(df)
})
# Only display columns with missing values
print("Missing value statistics:")
print(missing_stats[missing_stats['Number of Missing Values'] > 0])
Handling Missing Values: Choose an appropriate handling strategy based on the missing proportion and data type:
-
①. Deletion Method: Suitable for cases with extremely low missing proportions.
# Delete records containing missing values by row df_clean = df.dropna(axis=0, how='any') -
②. Filling Method: Choose an appropriate fill value based on data type.
# Fill numerical columns with mean or median df['Age'] = df['Age'].fillna(df['Age'].median()) # Fill categorical columns with mode df['Occupation'] = df['Occupation'].fillna(df['Occupation'].mode()[0]) # Fill time series data with forward and backward values df['Temperature'] = df['Temperature'].fillna(method='ffill') # Forward fill
The filling method retains more data compared to the deletion method, but care must be taken to consider the impact of the filling method on data distribution to avoid introducing new biases.
5. Handling Duplicate Values: Removing Redundant Information
Duplicate values refer to records that are completely identical or have the same core fields, which may arise from data entry errors, system failures, etc. The steps to handle duplicate values are as follows:
# Detect duplicate rows
duplicate_mask = df.duplicated(subset=['Name', 'ID Number']) # Specify key columns to determine duplicates
print(f"Detected {duplicate_mask.sum()} duplicate records")
# View content of duplicate rows
if duplicate_mask.sum() > 0:
print("Details of duplicate records:")
print(df[duplicate_mask])
# Delete duplicate rows, keeping the first occurrence
df_clean = df.drop_duplicates(subset=['Name', 'ID Number'], keep='first')
print(f"Remaining {df_clean.shape[0]} records after removing duplicates")
When handling duplicate values, it is necessary to determine the key fields for identifying duplicates based on the business context, rather than simply judging whether all fields are identical.
6. Handling Outliers: Identifying and Correcting Extreme Data
Outliers are observations that differ significantly from other data points, which may be due to measurement errors or may represent true extreme cases. Identifying and handling outliers requires a combination of visualization and statistical methods:
Visual Identification:
# Draw boxplot to visually display outliers in numerical columns
plt.figure(figsize=(12, 6))
sns.boxplot(data=df.select_dtypes(include=np.number))
plt.title('Boxplot of Numerical Columns (Outlier Detection)')
plt.tight_layout()
plt.show()
Statistical Method Identification (IQR Method):
def find_outliers(df, column):
"""Detect outliers in the specified column using the IQR method"""
q1 = df[column].quantile(0.25) # Lower quartile
q3 = df[column].quantile(0.75) # Upper quartile
iqr = q3 - q1 # Interquartile range
lower_limit = q1 - 1.5 * iqr # Lower bound for outliers
upper_limit = q3 + 1.5 * iqr # Upper bound for outliers
return df[(df[column] < lower_limit) | (df[column] > upper_limit)], lower_limit, upper_limit
# Handle outliers for each numerical column
for col in df.select_dtypes(include=np.number).columns:
outliers, lower, upper = find_outliers(df, col)
if not outliers.empty:
print(f"{col} column detected {len(outliers)} outliers")
# Truncate outliers (replace with boundary values)
df.loc[df[col] < lower, col] = lower
df.loc[df[col] > upper, col] = upper
When handling outliers, caution is required to avoid blindly deleting extreme values that may contain important information. It is usually preferable to consider truncation, transformation, and other methods that retain data.
7. Data Type Conversion: Standardizing Data Formats
Data sets often have mismatched data types and actual meanings (e.g., dates stored as strings), requiring type conversion:
# View current data types
print("Data types before conversion:")
print(df.dtypes)
# Convert strings to numeric types
df['Income'] = pd.to_numeric(df['Income'], errors='coerce') # Values that cannot be converted become missing values
# Convert strings to date types
df['Birth Date'] = pd.to_datetime(df['Birth Date'], format='%Y年%m月%d日')
# Convert strings to categorical types (suitable for columns with limited values)
df['Education'] = df['Education'].astype('category')
print("\nData types after conversion:")
print(df.dtypes)
Correct data types not only reduce memory usage but also ensure that subsequent statistical analysis and modeling can proceed normally.
8. Data Standardization/Normalization: Eliminating Dimensional Influence
The numerical ranges of different features may vary greatly (e.g., age between 0-120, income possibly between 0-1 million), and this difference can affect the performance of many machine learning algorithms, necessitating standardization or normalization:
# Z-score standardization (mean of 0, standard deviation of 1)
from sklearn.preprocessing import StandardScaler
scaler_standard = StandardScaler()
numeric_cols = df.select_dtypes(include=np.number).columns
df[numeric_cols] = scaler_standard.fit_transform(df[numeric_cols])
# Or use Min-Max normalization (scale to [0,1] range)
from sklearn.preprocessing import MinMaxScaler
scaler_minmax = MinMaxScaler()
df[numeric_cols] = scaler_minmax.fit_transform(df[numeric_cols])
- Standardization is suitable for data that is approximately normally distributed and is less affected by extreme values.
- Normalization is suitable for scenarios where data needs to be restricted to a specific range, such as the input layer of neural networks.
Practical Case: Data Cleaning Process of the Iris Dataset
Taking the classic Iris dataset as an example, the complete data cleaning process is demonstrated:
# Import libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Load data
df = pd.read_excel('iris_dataset.xlsx', sheet_name='Sheet1')
# Initial data exploration
print("Original data information:")
df.info()
print(f"Original data scale: {df.shape[0]} rows, {df.shape[1]} columns")
print("First 5 rows of data:")
print(df.head())
# Handle missing values
missing = df.isnull().sum()
print("\nMissing value statistics:")
print(missing[missing > 0])
# Fill missing values
for col in df.columns:
if df[col].dtype == 'object':
df[col] = df[col].fillna(df[col].mode()[0]) # Categorical use mode
else:
df[col] = df[col].fillna(df[col].mean()) # Numerical use mean
# Handle duplicate values
print("\nNumber of duplicate values:", df.duplicated().sum())
df = df.drop_duplicates() # Delete duplicate rows
# Handle outliers
numeric_cols = df.select_dtypes(include=np.number).columns
for col in numeric_cols:
q1 = df[col].quantile(0.25)
q3 = df[col].quantile(0.75)
iqr = q3 - q1
lower = q1 - 1.5 * iqr
upper = q3 + 1.5 * iqr
df = df[(df[col] >= lower) & (df[col] <= upper)]
# Reset index
df = df.reset_index(drop=True)
# Save cleaned data
df.to_excel('iris_cleaned.xlsx', index=False)
print("\nCleaning completed, data has been saved. Cleaned scale:", df.shape)
Through the above steps, missing values, duplicate values, and outliers in the original data have been effectively handled, resulting in a clean and standardized dataset that can be directly used for subsequent data analysis and modeling work.
Conclusion
Data cleaning and preprocessing is one of the most time and effort-intensive steps in the machine learning process, but its value cannot be overlooked. A scientifically standardized cleaning process can:
- Significantly improve data quality, providing a reliable foundation for subsequent analysis.
- Reduce model bias and erroneous conclusions caused by data issues.
- Enhance the efficiency and effectiveness of feature engineering, indirectly improving model performance.
In practical work, data cleaning does not have a fixed pattern; it needs to flexibly adjust strategies based on specific business scenarios, data characteristics, and analysis objectives. However, mastering the basic processes and methods introduced in this article can help us establish systematic thinking, confidently address various data quality issues, and lay a solid foundation for the success of machine learning projects.