Python 实战:Oracle 数据库数据分析与数据探查全流程(附精简代码)
摘要:本文详细介绍了如何使用Python连接Oracle数据库并进行多维度数据分析。通过cx_Oracle库实现数据库连接,结合pandas进行数据处理,利用matplotlib/seaborn实现可视化分析。内容涵盖环境配置、数据读取、缺失值和异常值检测、分类变量占比分析、数值变量分布及相关性分析等核心步骤,并提供完整代码示例。文章还针对常见错误提供解决方案,并给出进阶优化建议,如批量查询、Ex
在企业级数据分析场景中,Oracle 数据库作为常用的关系型数据库,存储着海量核心业务数据。本文将手把手教你用 Python 连接 Oracle 数据库,实现数据读取、多维度数据探查(缺失值、异常值、分布特征、相关性)与可视化分析,代码精简易上手,无需复杂配置,助力快速挖掘 Oracle 数据价值。
一、核心原理与环境准备
1. 核心逻辑
Python 操作 Oracle 数据库进行数据分析的核心流程:
关键工具说明:
- cx_Oracle:Python 连接 Oracle 数据库的核心库,支持 SQL 执行、数据读取;
- pandas:数据处理核心库,将查询结果转换为 DataFrame,便于探查与分析;
- matplotlib/seaborn:数据可视化库,直观呈现数据特征;
- 优势:无需导出 Oracle 数据为 CSV,直接联动分析,实时性强、效率高。
2. 环境准备
|
工具 / 依赖 |
版本要求 |
作用描述 |
|
Python |
3.7+ |
核心运行环境 |
|
cx_Oracle |
8.0+ |
Oracle 数据库连接核心库 |
|
pandas |
1.0+ |
数据处理与 DataFrame 转换 |
|
matplotlib/seaborn |
3.0+/0.10+ |
数据可视化 |
|
numpy |
1.18+ |
数值计算支持 |
|
Oracle Instant Client |
12c+/19c+ |
Oracle 客户端(需与数据库版本兼容) |
|
pip |
20.0+ |
Python 包管理工具 |
3. 依赖安装与环境配置
(1)安装 Python 依赖
打开终端执行以下命令,安装核心库:
pip install cx_Oracle pandas matplotlib seaborn numpy
(2)Oracle 客户端配置(关键步骤)
- 下载 Oracle Instant Client(轻量客户端):
官网地址:https://www.oracle.com/database/technologies/instant-client/downloads.html
选择与操作系统匹配的版本(如 Windows 64 位、Linux 64 位),无需安装,解压即可;
- 配置环境变量:
-
- Windows:将解压后的客户端路径(如D:\instantclient_19_19)添加到系统环境变量PATH;
-
- Linux/Mac:执行export LD_LIBRARY_PATH=~/instantclient_19_19:$LD_LIBRARY_PATH(临时生效),或写入~/.bashrc永久生效;
- 验证配置:终端执行sqlplus,若未报错则配置成功。
4. 数据集说明
以 Oracle 数据库中销售业务表(SALES_DATA) 为例,表结构如下(实际场景替换为目标表):
|
字段名 |
字段类型 |
说明 |
|
SALE_ID |
NUMBER(10) |
销售订单 ID(主键) |
|
SALE_DATE |
DATE |
销售日期 |
|
REGION |
VARCHAR2(50) |
销售地区 |
|
PRODUCT_TYPE |
VARCHAR2(50) |
产品类型 |
|
SALE_AMOUNT |
NUMBER(12,2) |
销售金额(元) |
|
QUANTITY |
NUMBER(8) |
销售数量(件) |
|
CUSTOMER_TYPE |
VARCHAR2(20) |
客户类型(个人 / 企业) |
二、核心代码实现:Python 连接 Oracle 数据库
1. 数据库连接与数据读取
import cx_Oracle
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from datetime import datetime
# 设置中文字体(避免中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # Mac系统
plt.rcParams['axes.unicode_minus'] = False
def oracle_connect(query_sql, db_config):
"""
连接Oracle数据库并执行SQL查询
:param query_sql: 待执行的SQL查询语句
:param db_config: 数据库配置字典(包含user/password/dsn)
:return: 查询结果(DataFrame)
"""
try:
# 1. 连接数据库
conn = cx_Oracle.connect(
user=db_config['user'],
password=db_config['password'],
dsn=db_config['dsn'] # DSN格式:主机名:端口号/服务名(如:127.0.0.1:1521/ORCL)
)
print("Oracle数据库连接成功!")
# 2. 执行SQL查询并转换为DataFrame
df = pd.read_sql(query_sql, conn)
# 3. 关闭连接
conn.close()
print(f"数据读取成功,共获取 {len(df)} 条记录,{len(df.columns)} 个字段")
return df
except cx_Oracle.Error as e:
print(f"Oracle数据库连接/查询失败:{e}")
return None
# -------------------------- 数据库配置(需手动修改)--------------------------
db_config = {
'user': '你的Oracle用户名', # 如:SCOTT
'password': '你的Oracle密码', # 如:TIGER
'dsn': '主机IP:端口号/服务名' # 如:192.168.1.100:1521/ORCL
}
# -------------------------- SQL查询语句(按需修改)--------------------------
# 读取销售表所有数据(可添加WHERE条件筛选目标数据)
query_sql = """
SELECT SALE_ID, SALE_DATE, REGION, PRODUCT_TYPE, SALE_AMOUNT, QUANTITY, CUSTOMER_TYPE
FROM SALES_DATA
-- WHERE SALE_DATE BETWEEN TO_DATE('2024-01-01', 'YYYY-MM-DD') AND TO_DATE('2024-12-31', 'YYYY-MM-DD')
"""
# 执行数据读取
df = oracle_connect(query_sql, db_config)
# 查看数据基本信息
if df is not None:
print("\n数据预览(前5行):")
print(df.head())
print("\n数据字段信息:")
print(df.info())
2. 代码解析(关键步骤)
(1)数据库配置
- user/password:Oracle 数据库的登录用户名和密码;
- dsn:数据库连接串,格式为主机IP:端口号/服务名(默认端口 1521,服务名通常为 ORCL 或 XE)。
(2)数据读取逻辑
- 用cx_Oracle.connect建立数据库连接,pd.read_sql直接执行 SQL 并转换为 DataFrame(无需手动处理结果集);
- 支持复杂 SQL 查询(如 WHERE 筛选、GROUP BY 聚合、JOIN 关联查询),灵活获取目标数据;
- 读取后立即关闭连接,避免资源占用。
(3)数据预处理(可选)
# 数据预处理:转换日期格式、处理缺失值
if df is not None:
# 转换日期字段(SALE_DATE)为datetime类型
df['SALE_DATE'] = pd.to_datetime(df['SALE_DATE'])
# 处理缺失值(示例:删除关键字段缺失的记录)
df = df.dropna(subset=['SALE_AMOUNT', 'QUANTITY', 'REGION'])
# 新增衍生字段(如:单价)
df['UNIT_PRICE'] = df['SALE_AMOUNT'] / df['QUANTITY'].round(2)
print("\n预处理后数据预览:")
print(df.head())
三、多维度数据探查(核心分析步骤)
数据探查是数据分析的基础,重点关注缺失值、异常值、分布特征、分类变量占比、数值变量相关性等维度:
1. 维度 1:缺失值探查
def missing_value_analysis(df):
"""缺失值探查与可视化"""
# 计算各字段缺失值占比
missing_info = df.isnull().sum() / len(df) * 100
missing_info = missing_info[missing_info > 0].sort_values(ascending=False)
if len(missing_info) > 0:
print("\n=== 缺失值探查结果 ===")
print(missing_info.round(2).map(lambda x: f"{x}%"))
# 可视化缺失值
plt.figure(figsize=(10, 6))
sns.barplot(x=missing_info.index, y=missing_info.values, color='#E74C3C', alpha=0.7)
plt.title('各字段缺失值占比', fontsize=14, fontweight='bold')
plt.xlabel('字段名', fontsize=12)
plt.ylabel('缺失值占比(%)', fontsize=12)
plt.xticks(rotation=45)
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('缺失值占比图.png', dpi=300)
plt.show()
else:
print("\n=== 缺失值探查结果 ===")
print("无缺失值!")
# 执行缺失值探查
if df is not None:
missing_value_analysis(df)
2. 维度 2:分类变量探查(占比分析)
针对地区、产品类型、客户类型等分类字段,分析分布占比:
def categorical_analysis(df, cat_cols):
"""分类变量占比探查与可视化"""
print("\n=== 分类变量占比分析 ===")
for col in cat_cols:
if col in df.columns:
# 计算占比
cat_count = df[col].value_counts()
cat_ratio = (cat_count / len(df) * 100).round(2)
print(f"\n{col} 占比:")
print(pd.DataFrame({
'数量': cat_count,
'占比(%)': cat_ratio
}))
# 可视化(饼图)
plt.figure(figsize=(8, 8))
plt.pie(cat_count, labels=cat_count.index, autopct='%1.1f%%',
startangle=90, colors=sns.color_palette('viridis'), explode=[0.05]*len(cat_count))
plt.title(f'{col} 分布占比', fontsize=14, fontweight='bold')
plt.axis('equal')
plt.tight_layout()
plt.savefig(f'{col}_占比图.png', dpi=300)
plt.show()
# 定义分类字段列表(按需修改)
categorical_cols = ['REGION', 'PRODUCT_TYPE', 'CUSTOMER_TYPE']
if df is not None:
categorical_analysis(df, categorical_cols)
3. 维度 3:数值变量探查(分布与异常值)
针对销售金额、销量、单价等数值字段,分析分布特征与异常值:
def numerical_analysis(df, num_cols):
"""数值变量分布与异常值探查"""
print("\n=== 数值变量统计特征 ===")
# 统计描述(均值、标准差、中位数、四分位数等)
numerical_desc = df[num_cols].describe().round(2)
print(numerical_desc)
# 可视化:直方图(分布)+ 箱线图(异常值)
fig, axes = plt.subplots(2, len(num_cols), figsize=(15, 10))
fig.suptitle('数值变量分布与异常值探查', fontsize=16, fontweight='bold')
for i, col in enumerate(num_cols):
# 直方图(分布)
sns.histplot(df[col], ax=axes[0, i], bins=20, color='#2E86AB', alpha=0.7, kde=True)
axes[0, i].set_title(f'{col} 分布', fontsize=12)
axes[0, i].set_xlabel('')
axes[0, i].grid(alpha=0.3)
# 箱线图(异常值)
sns.boxplot(y=df[col], ax=axes[1,i], color='#F39C12', alpha=0.7)
axes[1, i].set_title(f'{col} 异常值', fontsize=12)
axes[1, i].set_xlabel('')
axes[1, i].grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('数值变量探查图.png', dpi=300)
plt.show()
# 定义数值字段列表(按需修改)
numerical_cols = ['SALE_AMOUNT', 'QUANTITY', 'UNIT_PRICE']
if df is not None:
numerical_analysis(df, numerical_cols)

4. 维度 4:变量相关性探查(数值字段)
分析数值变量间的线性相关性,识别关键关联特征:
def correlation_analysis(df, num_cols):
"""数值变量相关性探查"""
# 计算相关系数(Pearson相关系数)
corr_matrix = df[num_cols].corr().round(3)
print("\n=== 数值变量相关性矩阵 ===")
print(corr_matrix)
# 可视化(热力图)
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='RdYlBu_r', vmin=-1, vmax=1,
square=True, linewidths=0.5, cbar_kws={'shrink': 0.8})
plt.title('数值变量相关性热力图', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('相关性热力图.png', dpi=300)
plt.show()
if df is not None:
correlation_analysis(df, numerical_cols)
5. 维度 5:时间趋势探查(针对日期字段)
分析销售数据随时间的变化趋势:
def time_trend_analysis(df, date_col, value_col):
"""时间趋势探查(按日/月聚合)"""
if date_col not in df.columns or value_col not in df.columns:
print("\n时间趋势分析:缺少日期字段或数值字段,跳过!")
return
# 按月份聚合(统计每月销售金额)
df['YEAR_MONTH'] = df[date_col].dt.to_period('M') # 新增年月字段
time_trend = df.groupby('YEAR_MONTH')[value_col].sum().reset_index()
time_trend['YEAR_MONTH'] = time_trend['YEAR_MONTH'].astype(str) # 转换为字符串便于显示
print("\n=== 时间趋势分析(按月聚合) ===")
print(time_trend)
# 可视化(折线图)
plt.figure(figsize=(14, 6))
sns.lineplot(x='YEAR_MONTH', y=value_col, data=time_trend, marker='o',
linewidth=2, markersize=6, color='#8E44AD')
plt.title(f'每月{value_col}趋势', fontsize=14, fontweight='bold')
plt.xlabel('年月', fontsize=12)
plt.ylabel(value_col, fontsize=12)
plt.xticks(rotation=45)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('时间趋势图.png', dpi=300)
plt.show()
if df is not None:
time_trend_analysis(df, date_col='SALE_DATE', value_col='SALE_AMOUNT')
四、运行与测试步骤(手把手操作)
1. 前置准备
- 安装 Python 依赖与 Oracle Instant Client,配置环境变量;
- 确认 Oracle 数据库服务正常运行,获取登录用户名、密码、主机 IP、端口号、服务名;
- 替换代码中的db_config(数据库配置)和query_sql(SQL 查询语句),确保目标表存在。
2. 运行代码
- 按顺序执行代码(分单元格执行,如 Jupyter Notebook,便于调试);
- 观察控制台输出:
-
- 数据库连接状态(成功 / 失败);
-
- 数据读取结果(记录数、字段数);
-
- 各维度探查结果(缺失值、分类占比、统计特征、相关性等);
- 查看项目目录:生成缺失值占比图、分类变量饼图、数值变量探查图、相关性热力图、时间趋势图等可视化文件。
3. 结果解读示例
- 缺失值:若 “PRODUCT_TYPE” 字段缺失率 10%,需评估是否影响分析(可删除或填充);
- 分类占比:华东地区销售占比 40%,为主要市场;电子产品占比 60%,是核心产品;
- 数值分布:销售金额集中在 1000-5000 元,无明显异常值;
- 相关性:销量与销售金额相关系数 0.95,呈强正相关(符合业务逻辑);
- 时间趋势:6-8 月销售金额峰值,可能为旺季。
五、避坑指南(新手必看)
1. Oracle 数据库连接失败
- 错误现象:cx_Oracle.Error: ORA-12170: TNS:连接超时或ORA-12514: TNS:监听程序当前无法识别连接描述符中请求的服务;
- 解决方法:
-
- 检查主机 IP、端口号、服务名是否正确(可通过tnsping 服务名测试网络连通性);
-
- 确认 Oracle 数据库服务已启动(Windows:服务中启动 OracleServiceORCL;Linux:systemctl start oracle);
-
- 关闭防火墙(或开放 1521 端口),避免端口被拦截;
-
- 客户端版本与数据库版本兼容(如 Oracle 19c 数据库搭配 19c 客户端)。
2. 中文乱码问题
- 错误现象:查询结果中中文字段显示为问号(?);
- 解决方法:
-
- 连接数据库时指定编码:conn = cx_Oracle.connect(user, password, dsn, encoding='utf8', nencoding='utf8');
-
- 确保 Oracle 数据库字符集为 UTF-8(可执行select userenv('language') from dual;查询,需包含UTF8)。
3. 数据量过大导致内存溢出
- 错误现象:读取大量数据(百万级)时,Python 报错 “MemoryError”;
- 解决方法:
-
- 用 SQLWHERE条件筛选目标数据(如按日期范围),减少读取量;
-
- 分块读取数据:pd.read_sql(query_sql, conn, chunksize=10000),逐块处理;
-
- 聚合查询:用GROUP BY在 Oracle 端完成聚合,减少返回数据量。
4. 日期字段处理错误
- 错误现象:日期字段读取后为字符串,无法进行时间趋势分析;
- 解决方法:用pd.to_datetime(df['SALE_DATE'])转换为 datetime 类型,或在 SQL 中指定日期格式:TO_CHAR(SALE_DATE, 'YYYY-MM-DD') AS SALE_DATE。
六、进阶扩展(按需优化)
1. 批量执行多 SQL 查询
def batch_query(db_config, sql_list):
"""批量执行多个SQL查询,返回结果字典"""
results = {}
conn = cx_Oracle.connect(**db_config)
for sql_name, sql in sql_list.items():
try:
df = pd.read_sql(sql, conn)
results[sql_name] = df
print(f"{sql_name}:读取 {len(df)} 条记录")
except Exception as e:
print(f"{sql_name} 执行失败:{e}")
results[sql_name] = None
conn.close()
return results
# 定义多SQL查询
sql_dict = {
'销售明细': "SELECT * FROM SALES_DATA WHERE SALE_DATE >= TO_DATE('2024-01-01', 'YYYY-MM-DD')",
'地区销售汇总': "SELECT REGION, SUM(SALE_AMOUNT) AS TOTAL_AMOUNT FROM SALES_DATA GROUP BY REGION"
}
# 批量执行
# batch_results = batch_query(db_config, sql_dict)
2. 分析结果导出为 Excel 报告
def export_to_excel(results, output_path):
"""将多维度探查结果导出为Excel(多sheet)"""
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# 原始数据
df.to_excel(writer, sheet_name='原始数据', index=False)
# 分类变量占比
for col in categorical_cols:
if col in df.columns:
cat_ratio = (df[col].value_counts() / len(df) * 100).round(2)
pd.DataFrame({
'类别': cat_ratio.index,
'占比(%)': cat_ratio.values
}).to_excel(writer, sheet_name=f'{col}占比', index=False)
# 数值变量统计
df[numerical_cols].describe().round(2).to_excel(writer, sheet_name='数值统计')
# 相关性矩阵
df[numerical_cols].corr().round(3).to_excel(writer, sheet_name='相关性矩阵')
print(f"分析结果已导出至:{output_path}")
# 导出Excel(替换为实际路径)
# if df is not None:
# export_to_excel(df, 'Oracle数据分析报告.xlsx')
3. 结合 SQL 聚合与 Python 分析
# 示例:用SQL完成复杂聚合,Python仅负责可视化
sql_agg = """
SELECT
REGION,
PRODUCT_TYPE,
TO_CHAR(SALE_DATE, 'YYYY-MM') AS YEAR_MONTH,
SUM(SALE_AMOUNT) AS TOTAL_AMOUNT,
AVG(QUANTITY) AS AVG_QUANTITY
FROM SALES_DATA
GROUP BY REGION, PRODUCT_TYPE, TO_CHAR(SALE_DATE, 'YYYY-MM')
ORDER BY YEAR_MONTH, REGION
"""
df_agg = oracle_connect(sql_agg, db_config)
if df_agg is not None:
# 可视化:各地区各产品类型月度销售金额
plt.figure(figsize=(14, 8))
sns.barplot(x='YEAR_MONTH', y='TOTAL_AMOUNT', hue='REGION', data=df_agg, palette='Set2')
plt.title('各地区各产品类型月度销售金额', fontsize=14, fontweight='bold')
plt.xlabel('年月', fontsize=12)
plt.ylabel('销售金额(元)', fontsize=12)
plt.xticks(rotation=45)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('地区产品月度销售图.png', dpi=300)
plt.show()
总结
本文通过 “数据库连接 - 数据读取 - 多维度探查 - 可视化分析” 的完整流程,手把手教你用 Python 实现 Oracle 数据库数据分析,核心亮点如下:
- 连接简单:仅需配置数据库信息,10 行代码即可读取 Oracle 数据,无需导出中间文件;
- 探查全面:覆盖缺失值、分类变量、数值变量、相关性、时间趋势 5 大核心维度;
- 代码精简:核心分析逻辑仅 300 余行,支持灵活修改(如替换表名、字段、SQL 查询);
- 可视化直观:生成多类图表,快速呈现数据特征,助力业务决策;
- 实战性强:提供避坑指南与进阶扩展(批量查询、Excel 导出、SQL 聚合联动),直接复用。
该方案适用于企业级数据分析、业务报表生成、数据质量监控等场景,无论你是数据分析新手还是有经验的开发者,都能通过本文快速掌握 Python 操作 Oracle 数据库的核心技巧,高效挖掘数据价值。来源地址:||@FiRe.BaNjInJgPt.cOm@||@FiRe.JuJiAJiU.cOm@|
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)