Análisis exploratorio de datos de producción
1. Importar librerías
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
2. Importar datos de producción
# Importamos datos de producción
data = pd.read_excel(r'datos/data.xlsx')
3. Explorar datos
3.1 Información del conjunto de datos
# Obtenemos información de los datos
data.info()
3.2 Estadística básica de los datos
# Más información
data.describe()
3.3 Depuración de valores
# Reemplazamos los valores negativos de la variables BORE_WAT_VOL
data.loc[data['BORE_WAT_VOL'] < 0, 'BORE_WAT_VOL'] = 0
4. Renombrar variables
4.1 Eliminación de información duplicada
# Algunas columnas contienen información redundante por lo cual se descartan
data = data.drop(['WELL_BORE_CODE', 'NPD_WELL_BORE_CODE','NPD_FIELD_CODE', 'NPD_FACILITY_CODE'], axis=1)
4.2 Asignación de nuevos nombres
# Renombramos las columnas para una manipulación más fácil
nombres = ['date', 'well_name', 'field_name', 'facility_name', 'stream_hours', 'downhole_press', 'downhole_temp', 'dp_tubing',
'annulus_press', 'choke_size', 'choke_uom', 'whp_p', 'wht_p', 'dp_choke_size', 'oil_volume', 'gas_volume','water_volume',
'injection_volume','flow_kind', 'flow_type']
# Reasignamos los nombres de las columnas
data.columns = nombres
5. Cálculo de variables
5.1 Cálculo de GOR y corte de agua
# Antes de realizar el eda, calculamos algunas variables
data['water_cut'] = data['water_volume'] / (data['oil_volume'] + data['water_volume'])
data['gor'] = data['gas_volume'] / data['oil_volume']
5.2 Verificar valores calculados
data.describe()
5.3 Depurar valores
# Reemplazamos valores infinitos derivados del cálculo del GOR
data.loc[data['gor'] == np.inf, 'gor'] = 0
6. Cifras del campo
6.1 Producción e inyección acumulada
# Determinamos la producción acumulada del campo
prod_acum = data.groupby('date').sum()
prod_acum = prod_acum.cumsum()
prod_acum.reset_index(inplace=True)
# Configuramos el estilo y la fuente de las gráficas
sns.set_style('darkgrid',{'axes.grid' : False})
sns.set(font_scale=1.5)
# Corroboramos estas cifras con los valores estimados en nuestro dataframe prod_acum
prod_acum.tail()
# Gráficas de las cifras globales de producción de agua y gas
plt.subplots(figsize=(12,6))
ax = sns.lineplot(prod_acum.date, prod_acum.oil_volume, color='green')
ax = sns.lineplot(prod_acum.date, prod_acum.water_volume, color='blue')
ax.fill_between(prod_acum.date.values, prod_acum.oil_volume.values, alpha=0.3, color='green')
ax.fill_between(prod_acum.date, prod_acum.oil_volume, prod_acum.water_volume, alpha=0.1, color='blue')
ax.set_xlabel('Año')
ax.set_ylabel('Producción acumulada petróleo y agua (Sm3)')
ax.set_ylim(0,17000000)
ax.set_title('Producción total - Volve')
ax.legend(labels=['Petróleo', 'Agua'])
plt.show()
# Gráficas de las cifras globales de producción de gas
plt.subplots(figsize=(12,6))
ax = sns.lineplot(prod_acum.date, prod_acum.gas_volume, color='red')
ax.set_xlabel('Año')
ax.set_ylabel('Producción acumulada de gas (Sm3)')
ax.set_title('Producción total de gas - Volve')
ax.fill_between(prod_acum.date, prod_acum.gas_volume, alpha=0.1, color='red')
plt.show()
# Gráfica de las cifras globales de inyección
plt.subplots(figsize=(12,6))
ax = sns.lineplot(prod_acum.date, prod_acum.injection_volume, color='cyan')
ax.set_xlabel('Año')
ax.set_ylabel('Volumen de inyección acumulado (Sm3)')
ax.fill_between(prod_acum.date.values, prod_acum.injection_volume.values, alpha=0.1, color='cyan')
ax.set_title('Inyección total Volve')
plt.show()
6.2 Producción e inyección promedio diaria
# Determinamos producción promedio día
prod_campo = data[['date', 'oil_volume','gas_volume','water_volume','injection_volume',
'water_cut', 'gor', 'downhole_press']]
prod_campo = prod_campo.groupby('date').sum()
prod_campo.reset_index(inplace=True)
# Remuestramos el conjunto de datos a una frecuencia semanal
prod_campo = prod_campo.resample('2W', on='date').mean()
prod_campo.reset_index(inplace=True)
# Cifras del campo
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date',y='oil_volume', data=prod_campo, color='green',alpha=0.6)
ax.fill_between(prod_campo.date.values, prod_campo.oil_volume.values, alpha=0.3, color='green')
ax.set_xlabel('Año')
ax.set_ylabel('Producción diaria promedio (sm3/día)')
ax.set_title('Producción de petróleo - Volve')
plt.show()
# Cifras del campo
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date',y='gas_volume', data=prod_campo, color='red',alpha=0.6)
ax.fill_between(prod_campo.date.values, prod_campo.gas_volume.values, alpha=0.3, color='red')
ax.set_xlabel('Año')
ax.set_ylabel('Producción diaria promedio (sm3/día)')
ax.set_title('Producción de gas - Volve')
plt.show()
# Cifras del campo
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date',y='water_volume', data=prod_campo, color='blue',alpha=0.6)
ax = sns.lineplot(x='date',y='injection_volume', data=prod_campo, color='cyan',alpha=0.6)
ax.fill_between(prod_campo.date.values, prod_campo.water_volume.values, alpha=0.2, color='blue')
ax.fill_between(prod_campo.date.values, prod_campo.injection_volume.values, alpha=0.2, color='cyan')
ax.set_xlabel('Año')
ax.set_ylabel('Tasa diaria promedio (sm3/día)')
ax.set_title('Producción e Inyección de agua - Volve')
ax.legend(labels=['Producción', 'Inyección'])
plt.show()
6.3 Corte de agua y GOR promedio diario
rel_campo = data[['date', 'water_cut', 'gor']]
rel_campo = rel_campo.resample('2W', on='date').mean()
rel_campo.reset_index(inplace=True)
# Un vistazo al gor y water cut del campo
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date',y='water_cut', data=rel_campo, color='blue',alpha=0.6, label='Corte de agua')
ax2 = plt.twinx()
ax2.grid(b=False)
ax2 = sns.lineplot(x='date',y='gor', data=rel_campo, color='red', ax=ax2, alpha=0.6, label='GOR')
ax.set_xlabel('Año')
ax.set_ylabel('Corte de agua')
ax2.set_ylabel('GOR (m3/m3)')
ax2.set_ylim(0,220)
h1, l1 = ax.get_legend_handles_labels()
h2, l2 = ax2.get_legend_handles_labels()
ax.legend(h1+h2, l1+l2, loc=0)
plt.title('Corte de agua y GOR promedio diario')
plt.show()
7. Cifras pozo a pozo
7.1 Contribución de producción de cada pozo
# Reformateamos la frecuencia de los datos
data_anual = data.groupby(['well_name']).resample('Y', on='date').mean()
data_anual.reset_index(inplace=True)
# Comparación de producción de petróleo anual pozo a pozo
plt.figure(figsize=(12,6))
ax = sns.histplot(data_anual, x='date', weights='oil_volume', hue='well_name', multiple='stack', palette='cubehelix',
shrink=0.8)
ax.set_xlabel('Año')
ax.set_title('Producción de petróleo anual por pozo')
plt.show()
# Determinamos la producción total de cada pozo
prod_pozos = data[['date','well_name','oil_volume', 'gas_volume','water_volume','injection_volume']]
prod_pozos = prod_pozos.groupby(['well_name']).sum()
pozos = prod_pozos.index
# Creamos un diagrama de pastel para representar la producción de petróleo de los pozos
fig, ax = plt.subplots(figsize=(7,4))
colors = sns.color_palette('cubehelix')[0:5]
ax.pie(prod_pozos['oil_volume'], colors = colors, radius=2, autopct='%1.1f%%')
ax.legend(labels=pozos, loc="center left", bbox_to_anchor=(1.3, 0, 0.5, 1))
ax.set_title('Distribución de producción de petróleo por pozo', pad=75)
plt.show()
# Creamos un diagrama de pastel para representar la producción de gas de los pozos
fig, ax = plt.subplots(figsize=(7,4))
colors = sns.color_palette('cubehelix')[0:5]
ax.pie(prod_pozos['gas_volume'], colors = colors, radius=2, autopct='%1.1f%%')
ax.legend(labels=pozos, loc="center left", bbox_to_anchor=(1.3, 0, 0.5, 1))
ax.set_title('Distribución de producción de gas por pozo', pad=75)
plt.show()
7.2 Tipo de pozos
# Creamos una paleta de colores para el diagrama de barras
palette = ['tab:blue', 'tab:green']
palette = {'injection': 'tab:blue','production': 'tab:green'}
# Exploramos el tipo de pozos
plt.figure(figsize=(12,6))
ax = sns.countplot(x = 'well_name', data=data, hue='flow_kind', palette=palette)
ax.set_xlabel('Año')
ax.set_ylabel('Observaciones')
ax.set_title('Pozos del campo Volve')
ax.legend(labels=['Producción', 'Inyección'])
plt.show()
7.3 Distribución y tendecia de valores de producción
# Diagrama de caja de la variable producción de petróleo
plt.figure(figsize=(12,6))
ax = sns.boxplot(x='well_name', y='oil_volume', data=data, palette='cubehelix')
ax.set_xlabel('Pozo')
ax.set_ylabel('Producción de petróleo (sm3/d)')
ax.set_title('Diagrama de caja')
plt.show()
# Verificamos la producción de gas de cada pozo
plt.figure(figsize=(12,6))
ax = sns.boxplot(x='well_name', y='gas_volume', data=data, palette='cubehelix')
ax.set_xlabel('Pozo')
ax.set_ylabel('Producción de gas (sm3/d)')
ax.set_title('Diagrama de caja')
plt.show()
# Verificamos la producción de agua de cada pozo
plt.figure(figsize=(12,6))
ax = sns.boxplot(x='well_name', y='water_volume', data=data, palette='cubehelix')
ax.set_xlabel('Pozo')
ax.set_ylabel('Producción de agua (sm3/d)')
ax.set_title('Diagrama de caja')
plt.show()
7.4 Distribución y tendencia de valores de inyección
# Verificamos la inyección de agua de cada pozo
plt.figure(figsize=(12,6))
ax = sns.boxplot(x='well_name', y='injection_volume', data=data, palette='cubehelix')
ax.set_xlabel('Pozo')
ax.set_ylabel('Inyección de agua (sm3/d)')
ax.set_title('Diagrama de caja')
plt.show()
7.5 Producción diaria
# Realizamos un resampling a los datos de producción
prod_mensual = data.groupby(['well_name']).resample('2W', on='date').mean()
prod_mensual.reset_index(inplace=True)
# Graficamos producción histórica de petróleo de los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='oil_volume', data=prod_mensual, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('Producción diaria promedio (sm3/d)')
ax.set_title('Producción de petróleo por pozo')
plt.show()
# Graficamos producción histórica de gas de los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='gas_volume', data=prod_mensual, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('Producción diaria promedio (sm3/d)')
ax.set_title('Producción de gas por pozo')
plt.show()
# Graficamos producción histórica de agua de los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='water_volume', data=prod_mensual, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('Producción diaria promedio (sm3/d)')
ax.set_title('Producción de agua por pozo')
plt.show()
7.6 Corte de agua y GOR diario
# Graficamos gor histórico los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='gor', data=prod_mensual, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('GOR diario promedio (m3/m3)')
ax.set_title('GOR por pozo')
plt.show()
# Graficamos producción histórica de agua de los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='water_cut', data=prod_mensual, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('Corte de agua diario promedio')
ax.set_title('Corte de agua por pozo')
plt.show()
7.7 Inyección diaria
# Filtramos la información correspondiente a los pozos inyectores
inyectores = prod_mensual[(prod_mensual['well_name'] == '15/9-F-5') | (prod_mensual['well_name'] == '15/9-F-4')]
# Graficamos inyección histórica de los pozos
plt.figure(figsize=(12,6))
ax = sns.lineplot(x='date', y='injection_volume', data=inyectores, hue='well_name', palette="husl")
ax.set_xlabel('Año')
ax.set_ylabel('Inyección diaria promedio (sm3/día)')
ax.set_title('Inyección de agua por pozo')
ax.legend(labels=['15/9-F-5', '15/9-F-4' ])
plt.show()
prod_pozos.reset_index(inplace=True)
iny_pozos = prod_pozos[(prod_pozos['well_name'] == '15/9-F-5') | (prod_pozos['well_name'] == '15/9-F-4')]
inyector = iny_pozos['well_name']
#define Seaborn color palette to us
fig, ax = plt.subplots(figsize=(7,4))
colors = sns.color_palette('husl')
#create pie chart
ax.pie(iny_pozos['injection_volume'], colors = colors, radius=2, autopct='%1.1f%%')
ax.legend(labels=inyector, loc="center left", bbox_to_anchor=(1.3, 0, 0.5, 1))
ax.set_title('Distribución de inyección por pozo', pad=75)
plt.show()
7.8 Presión de fondo fluyente
plt.figure(figsize=(12,6))
ax=sns.lineplot(prod_mensual.date, prod_mensual.downhole_press, hue=prod_mensual.well_name)
ax.set_xlabel('Año')
ax.set_ylabel('Presión de fondo fluyente (bar)')
ax.set_title('Presión de fondo fluyente por pozo')
ax.set_ylim(0,350)
plt.show()