3. ESG数据清洗与预处理:缺失值处理、异常值检测、数据标准化与归一化、文本数据清洗(NLP基础)
各位同学,欢迎来到第三章。说实话,ESG分析里最磨人的不是建模,而是数据清洗。我见过太多人,模型跑得飞起,结果因为数据没洗干净,最后结论全是错的。这一章,咱们就把这些脏活累活讲透。
核心观点:ESG数据质量直接决定模型上限。再牛的算法,也救不了垃圾数据。
3.1 缺失值处理——别让空值毁了你的模型
ESG数据里,缺失值简直家常便饭。我做过一个项目,某公司碳排放数据缺了40%,你说这怎么整?
我个人习惯,先分三类情况处理:
- 随机缺失:比如某年忘了填报告,这种可以用均值或中位数填充
- 系统缺失:比如小公司根本不披露某些指标,这种得用模型预测
- 完全缺失:整个行业都不披露,嗯,直接删掉这列吧
我的经验:千万别一上来就删数据。我曾经删掉一批缺失行,结果发现那些全是高污染企业,模型直接偏了。先分析缺失模式,再动手。
# 缺失值处理示例
import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer
# 加载ESG数据
df = pd.read_csv('esg_data.csv')
# 查看缺失情况
print(df.isnull().sum())
# 数值型:用中位数填充(抗异常值)
df['carbon_emission'] = df['carbon_emission'].fillna(df['carbon_emission'].median())
# 分类型:用众数填充
df['disclosure_level'] = df['disclosure_level'].fillna(df['disclosure_level'].mode()[0])
# 高级玩法:KNN填充(适合有规律缺失)
imputer = KNNImputer(n_neighbors=5)
df_imputed = pd.DataFrame(imputer.fit_transform(df.select_dtypes(include=[np.number])))
3.2 异常值检测——揪出那些离谱的数据
ESG数据里异常值特别多。你想想看,一家制造业公司,碳排放突然比去年高了100倍,这合理吗?
我常用的方法就三个:
| 方法 | 适用场景 | 我的评价 |
|---|---|---|
| IQR(四分位距) | 数据分布偏态明显 | 简单粗暴,够用 |
| Z-Score | 数据近似正态分布 | 标准化后好比较 |
| 业务规则 | 有行业标准 | 最靠谱,但费功夫 |
避坑指南:我曾经用Z-Score一刀切,结果把某家新能源公司的高增长数据当异常删了。后来发现人家确实在扩产。记住:异常≠错误,可能是业务真相。
# 异常值检测实战
from scipy import stats
# IQR方法
Q1 = df['water_usage'].quantile(0.25)
Q3 = df['water_usage'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['water_usage'] < lower_bound) | (df['water_usage'] > upper_bound)]
# Z-Score方法
z_scores = np.abs(stats.zscore(df['employee_turnover']))
df_clean = df[(z_scores < 3)] # 保留3个标准差内的数据
3.3 数据标准化与归一化——让不同量纲的数据能打架
ESG指标五花八门,碳排放是吨,员工流失率是百分比,董事会独立性是人数。你直接放一起算,那不是扯淡吗?
标准化和归一化,说白了就是让这些数据站在同一起跑线上。
- Z-score标准化:适合数据有异常值的情况,把数据变成均值为0、标准差为1
- Min-Max归一化:把数据压缩到[0,1]区间,适合神经网络
我的建议:做ESG评级模型,优先用Z-score。为什么?因为Min-Max对异常值太敏感,一个极端值就能把其他数据压成一条线。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-score标准化(推荐)
scaler = StandardScaler()
df_scaled = pd.DataFrame(
scaler.fit_transform(df[['carbon_emission', 'water_usage', 'waste_recycling']]),
columns=['carbon_emission', 'water_usage', 'waste_recycling']
)
# Min-Max归一化
minmax_scaler = MinMaxScaler()
df_normalized = pd.DataFrame(
minmax_scaler.fit_transform(df[['board_independence', 'employee_satisfaction']]),
columns=['board_independence', 'employee_satisfaction']
)
3.4 文本数据清洗——从ESG报告里挖出金子
ESG数据不全是数字。那些几百页的可持续发展报告,里面藏着大量信息。我做过一个项目,光年报就爬了2000份,全是PDF。
文本清洗的流程,我总结为四步:
- 去噪:去掉HTML标签、特殊符号、多余空格
- 分词:中文用jieba,英文用NLTK
- 去停用词:去掉"的"、"了"、"是"这类没意义的词
- 词向量化:把文字变成数字,比如TF-IDF或Word2Vec
避坑指南:我曾经直接拿原始文本跑模型,结果"环境"和"环保"被当成两个词。后来加了同义词替换,效果好了不少。ESG领域,术语统一特别重要。
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
# 中文分词示例
text = "公司致力于减少碳排放,提升环境绩效"
words = jieba.lcut(text)
print(words) # ['公司', '致力于', '减少', '碳排放', '提升', '环境', '绩效']
# TF-IDF向量化
corpus = [
"公司减少碳排放",
"提升员工福利",
"加强董事会监督"
]
vectorizer = TfidfVectorizer(tokenizer=jieba.lcut)
X = vectorizer.fit_transform(corpus)
print(vectorizer.get_feature_names_out())
3.5 数据清洗流水线——把一切串起来
实际项目中,你不会一步步手动操作。我习惯用Pipeline把整个流程串起来,这样可复现、可部署。
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
# 定义不同列的处理方式
numeric_features = ['carbon_emission', 'water_usage']
categorical_features = ['industry', 'region']
preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numeric_features),
('cat', 'passthrough', categorical_features) # 分类列先不动
])
# 构建完整流水线
pipeline = Pipeline([
('preprocessor', preprocessor),
# 后面再接模型...
])
# 一键清洗
df_clean = pipeline.fit_transform(df)
核心要点:数据清洗不是一次性工作。每次拿到新数据,都要重新审视清洗策略。我见过太多人,写了个清洗脚本就再也不管了,结果数据源一变,模型全崩。
好了,这一章的内容就到这。数据清洗确实枯燥,但它是整个ESG评级模型的基石。你想想看,如果数据都是脏的,后面的模型再花哨又有什么用?