4、数据采集与清洗:数据源识别、数据提取技巧、数据清洗规则
好,咱们进入第四讲。数据采集与清洗,说白了就是「找数据」和「洗数据」。我见过太多审计同行,花80%的时间在整理数据,真正分析的时间反而没多少。这其实是个大坑。我个人习惯是,把数据采集和清洗流程化、工具化,效率能翻好几倍。
4.1 数据源识别:你得知道去哪儿找
数据源识别,听起来高大上,其实就是搞清楚「数据在哪儿」。我刚开始做审计时,经常被财务部的人带着跑,他们给什么我就用什么。后来发现,很多关键数据其实藏在别的地方。
常见的审计数据源,我大致分了这么几类:
| 数据源类型 | 典型来源 | 我踩过的坑 |
|---|---|---|
| 财务系统 | 金蝶、用友、SAP | 导出的Excel经常有合并单元格,一处理就乱 |
| 业务系统 | ERP、CRM、OA | 业务数据跟财务数据对不上,口径不一致 |
| 外部数据 | 工商、税务、银行流水 | 格式五花八门,PDF、图片都有 |
| 非结构化数据 | 合同扫描件、邮件、聊天记录 | OCR识别率低,得人工复核 |
4.2 数据提取技巧:怎么把数据「拿」出来
数据源找到了,接下来就是提取。这里我分几种常见场景来讲。
4.2.1 从数据库直接提取
如果你能直接连数据库,那是最理想的。我个人习惯用SQL,简单高效。举个例子,从SAP HANA里提取某个月的销售数据:
-- 提取2024年1月销售数据
SELECT
VBELN AS 销售订单号,
POSNR AS 行项目,
MATNR AS 物料编码,
KWMENG AS 数量,
NETWR AS 净额
FROM VBAK
JOIN VBAP ON VBAK.VBELN = VBAP.VBELN
WHERE ERDAT BETWEEN '20240101' AND '20240131'
AND VKORG = '1000'; -- 销售组织
嗯,这里要注意:数据库权限问题。我曾经遇到过,IT部门给了只读权限,但表名是加密的,根本看不懂。后来我学乖了,先要一份数据字典,或者让DBA帮忙写个视图。
4.2.2 从Excel/CSV提取
大部分审计数据还是以Excel形式存在。我建议用Python的pandas库来处理,比手动操作快得多。
import pandas as pd
# 读取Excel文件
df = pd.read_excel('财务数据.xlsx', sheet_name='总账', header=0)
# 查看前5行,确认数据格式
print(df.head())
# 如果有多层表头,需要指定header参数
df = pd.read_excel('财务数据.xlsx', sheet_name='总账', header=[0, 1])
4.2.3 从PDF/图片提取
这个场景比较头疼。银行回单、合同扫描件,很多都是PDF或图片。我一般用OCR技术,但准确率不是100%。
import pytesseract
from PIL import Image
# 读取图片
img = Image.open('银行回单.jpg')
# OCR识别
text = pytesseract.image_to_string(img, lang='chi_sim')
# 提取关键信息(比如金额、日期)
import re
amount = re.findall(r'\d+\.\d{2}', text)
print(amount)
说实话,OCR识别出来的数据,我建议一定要人工复核一遍。特别是金额、日期这些关键字段,错一个数字,整个审计结论可能就偏了。
4.3 数据清洗规则:把脏数据「洗」干净
数据提取出来,你会发现各种问题:空值、重复、格式不统一、异常值……不洗一下,根本没法用。我总结了一套清洗规则,按优先级排序。
4.3.1 处理缺失值
缺失值是最常见的问题。我的处理原则是:
- 关键字段缺失: 比如金额、日期,必须补全。可以找原始凭证,或者跟业务部门确认。
- 非关键字段缺失: 比如备注、摘要,可以填充为「未知」或直接删除。
- 整行缺失: 如果一行数据大部分字段都为空,直接删除。
# 用pandas处理缺失值
df = df.dropna(subset=['金额', '日期']) # 删除关键字段缺失的行
df['备注'] = df['备注'].fillna('未知') # 非关键字段填充
4.3.2 去除重复数据
重复数据会导致统计结果失真。我一般先按关键字段去重,比如订单号、凭证号。
# 按订单号去重,保留第一条
df = df.drop_duplicates(subset=['订单号'], keep='first')
4.3.3 统一数据格式
同一个字段,不同来源的格式可能不一样。比如日期,有的用「2024-01-01」,有的用「2024/01/01」,还有的用「2024年1月1日」。我习惯统一成标准格式。
# 统一日期格式
df['日期'] = pd.to_datetime(df['日期'], format='mixed')
# 统一金额格式(去掉千分位分隔符)
df['金额'] = df['金额'].str.replace(',', '').astype(float)
4.3.4 处理异常值
异常值往往意味着风险点。我一般用箱线图或标准差法来识别。
# 用标准差法识别异常值
mean = df['金额'].mean()
std = df['金额'].std()
df = df[(df['金额'] > mean - 3*std) & (df['金额'] < mean + 3*std)]
不过,异常值不一定是错误。比如一笔大额采购,金额远超正常范围,这恰恰可能是审计重点。所以,识别出异常值后,不要直接删除,先标记出来,后续重点核查。
4.3.5 数据一致性校验
最后一步,是校验数据的一致性。比如,总账的借方发生额应该等于贷方发生额,销售订单的金额应该等于发票金额。如果不一致,说明数据有问题,需要回溯。
# 校验借贷平衡
debit_sum = df[df['借贷方向'] == '借']['金额'].sum()
credit_sum = df[df['借贷方向'] == '贷']['金额'].sum()
if abs(debit_sum - credit_sum) > 0.01:
print('借贷不平衡,差异金额:', debit_sum - credit_sum)
好了,数据采集与清洗这部分就讲到这里。说白了,就是「找数据」要准,「拿数据」要快,「洗数据」要狠。下一章,咱们聊聊数据分析的具体方法。