对于许多数据科学初学者来说,Python 是大家学习和探索的第一门语言。它是一门功能强大的通用语言,能够高效地进行数据处理,因此深受数据从业者的喜爱。
然而,随着实际项目的推进,基础的入门知识已经远远不够。现实问题更加复杂,简单的代码可能无法解决实际需求,代码甚至会变得低效且难以维护和沟通。
如果你希望从初级迈向中级,这一点尤为明显。仅仅学习新的库或复杂的算法是不够的,你还必须通过引入编程模式来优化你的 Python 代码结构和工作流程。
如前所述,从初级到中级数据科学家的转变,并不只是写基础代码。你需要更聪明、更有结构地编写代码。中级阶段的目标是让你的代码更加模块化、可扩展,同时提高代码的可读性和可维护性,能够应对更复杂的工作流。
通过运用各种 Python 编程模式,我们可以极大地提升代码质量和工作流程,远超基础水平。下面,我们将从数据处理流水线模式开始,逐步探讨这些模式。
在本文中,我们将讨论多种 Python 编程模式,助你提升代码水平,迈入中级数据科学家行列。让我们正式开始吧!
数据流水线模式(Data Pipeline Pattern)
在数据处理过程中,我们会遇到诸多任务,如数据清洗、预处理和特征工程。初学者常常在笔记本或脚本中零散处理这些任务,甚至多次重复同样的操作。
如果你持续采用这种方式,调试会变得异常繁琐和困难,同时也会带来巨大的技术债务,影响团队协作。因此,我们需要流水线模式来优化工作流程。
流水线是一种将数据处理步骤按顺序组织起来的过程。我们定义好各个阶段,每个阶段专注于一个特定操作,如数据加载、清洗、缩放、模型训练等。这是一种系统化、逐步推进的过程。
让我们以 Pandas DataFrame 为例,模拟一个销售数据的数据框:
import pandas as pd
import numpy as np
data = {
'sales': [1000, 1500, np.nan, 2000, 2500],
'quantity': [50, 60, 70, np.nan, 90],
'product': ['A', 'B', 'C', 'D', 'E']
}
example_df = pd.DataFrame(data)
作为数据科学家,你可能经常需要执行以下常见的数据处理步骤:数据加载、清洗和特征工程。
# 第一步:加载数据
def load_data(df: pd.DataFrame) -> pd.DataFrame:
return df
# 第二步:数据清洗
def clean_data(df: pd.DataFrame) -> pd.DataFrame:
missing_before = df.isnull().sum().sum()
df_cleaned = df.dropna().reset_index(drop=True)
missing_after = df_cleaned.isnull().sum().sum()
return df_cleaned
# 第三步:特征工程
def engineer_features(df: pd.DataFrame) -> pd.DataFrame:
if 'sales' in df.columns and 'quantity' in df.columns:
df['avg_price'] = df['sales'] / df['quantity']
return df
通过将每个数据处理环节封装成可复用的函数,你可以多次执行,而无需每次都手动编写。
不过,为了让结构更加清晰,应该将其做成流水线。下面我们为这些函数创建一个流水线执行函数:
def execute_pipeline(df: pd.DataFrame, steps: list) -> pd.DataFrame:
for step in steps:
df = step(df)
return df
pipeline_steps = [
load_data,
clean_data,
engineer_features
]
final_df = execute_pipeline(example_df, pipeline_steps)
就是这样!通过简单的流水线函数,你就拥有了可复用且易读的代码。
你还可以用 Scikit-Learn 创建数据处理和建模的流水线。以下是相关的概念代码:
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
pipeline = Pipeline([
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler()),
('classifier', RandomForestClassifier(n_estimators=100, random_state=42))
])
pipeline.fit(X, y)
请善用流水线模式,它对你未来的数据科学任务大有裨益。
工厂模式(Factory Pattern)
区分初级与中级编程能力的关键在于:能否实现代码复用,并尽量少写重复代码。对于数据科学来说,由于流程更复杂、实验更频繁,这一点尤为重要。
在进行数据和模型实验时,我们常常需要频繁切换不同模型和数据集,手动编写代码既繁琐又容易混乱。
此时,工厂模式就非常有用。本质上,工厂模式是将对象的创建(如机器学习模型)集中管理,通过调整参数即可生成不同对象,而无需为每种情况单独写代码。
借助工厂模式,我们可以集中管理对象的创建,轻松进行实验,使代码更加模块化。
来看一个创建机器学习模型的工厂模式例子:
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
def model_factory(model_type: str, **kwargs):
models = {
'logistic_regression': LogisticRegression,
'decision_tree': DecisionTreeClassifier,
'random_forest': RandomForestClassifier,
'gradient_boosting': GradientBoostingClassifier
}
if model_type not in models:
raise ValueError(f"Unsupported model type '{model_type}'. Supported types: {list(models.keys())}")
return models[model_type](**kwargs)
我们只需定义一个函数,通过更改参数即可创建不同的机器学习模型。
然后便可轻松调用函数生成所需模型:
logreg_model = model_factory(
model_type='logistic_regression',
solver='liblinear',
random_state=42)
对于容易混乱的实验环节,建议采用工厂模式进行管理。
装饰器模式(Decorator Pattern)
随着数据工作流的扩展,你可能希望增加如日志记录等额外功能。许多人会在脚本里手动插入日志代码,但这样容易造成冗余,降低代码可读性。
这时可以使用装饰器模式。装饰器是一种特殊函数,用于包装其他函数,在不改变核心逻辑的前提下,给函数添加额外功能。
利用装饰器,可以在多个函数中统一处理附加功能,同时保持代码整洁。如无需求,移除装饰器也非常方便。
例如,以下是一个用于记录函数执行耗时的装饰器:
import functools
import time
def log_and_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
func_name = func.__name__
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
print(f"'{func_name}' completed in {duration:.4f} seconds.\n")
return result
return wrapper
假设我们要定义一个生成模拟数据的函数,可以用上面的装饰器:
@log_and_time
def load_simulated_data(n_rows=10000):
np.random.seed(42)
df = pd.DataFrame({
'age': np.random.randint(18, 70, size=n_rows),
'income': np.random.normal(50000, 15000, size=n_rows),
'credit_score': np.random.randint(300, 850, size=n_rows),
'loan_amount': np.random.normal(20000, 5000, size=n_rows),
'defaulted': np.random.binomial(1, 0.2, size=n_rows)
})
for col in ['income', 'credit_score']:
df.loc[df.sample(frac=0.05).index, col] = np.nan
return df
执行该函数:
df_loaded = load_simulated_data()
你会看到类似如下的输出结果:
'load_simulated_data' completed in 0.0707 seconds.
装饰器能够正确获取函数名称,并精确给出执行时间。
对于需要封装或统计信息的任务,建议采用装饰器模式。
总结
从初级到中级数据科学家,意味着你要将 Python 编程能力提升到更高层次,不再局限于入门级别。你需要用更有条理和更高效的方式管理数据工作流。在本文中,我们介绍了几种能够助你进阶的 Python 编程模式,包括数据流水线模式、工厂模式和装饰器模式。
希望本文能对你有所帮助!