SPE Colombia Hackaton 2020

Análisis datos Agencia Nacional de Hidrocarburos - ANH

Archivo 1 : Lectura y procesamiento de los datos

Se describe el proceso para la lectura y procesamiento de los datos descargados de las pagina de la ANH. como anotacion se encuentra que los datos para los años 2013 y 2014 no cuentan con la columna de municipio y operadora, reemplazandose por empresa y cuenca. ademas de esto, el archivo de datos del 2014 solo tenia datos hasta el mes de octubre.
In [1]:
from pathlib import Path
  from datetime import date , datetime
  import pandas as pd
  import numpy as np
  import matplotlib.pyplot as plt
  import seaborn as sns
  import warnings
  from scipy.optimize import curve_fit
  warnings.filterwarnings("ignore")
  

Luego de procesar estos datos se creará un df que contenga el compilado de todos los datos oficiales y blind test en el númeral

  • Tabla de datos oficiales
  • Tabla de datos blind

El script de lectura para ambos archivos es el mismo

In [2]:
def lectyproc(ruta):
          #Se quiere que este código perdure en el tiempo, por tanto, se genera el código para que lea todos los excel  hasta el año actual
      today = date.today()
      #Los datos de producción se obtienen desde el año 2013
      primeraño=2013
      añoactual=today.year
      listado_años=[]
      #Un rango de fechas desde el 2013 hasta el año actual
      años = range(primeraño,añoactual+1,1)
      #Se crea una función para leer los nombres de los archivos que estan ubicados en el directorio
      def ls(ruta = Path.cwd()):
          return [arch.name for arch in Path(ruta).iterdir() if arch.is_file()]
      #Se establece la ruta dentro del directorio actual
      files=ls(ruta)
      for año in años:
          for file in files:
              añotemp = file[file.find('2'):file.find('2')+4]
              if int(año) == int(añotemp):
                  #Se leen los documentos de excel que están en el directorio especificado. Se limita las columnas de la A a la Q
                  globals()["año" + str(año)] = pd.read_excel(ruta+file,usecols='A:Q')
                  #Se eliminan las filas con valores nulos, para así quitar encabezados y totalizadores y la primera fila pasa a ser el encabezado del data frame
                  if globals()["año" + str(año)].isnull().sum().sum() != 0:
                      globals()["año" + str(año)]=globals()["año" + str(año)].dropna().reset_index(drop=True) 
                      globals()["año" + str(año)]=globals()["año" + str(año)].rename(columns= globals()["año" + str(año)].iloc[0]).drop(0)
                         
                  #Hago una lista con los nombres de las columnas del dataframe
                  globals()["año" + str(año)].columns = globals()["año" + str(año)].columns.str.upper()
                  globals()["año" + str(año)].columns = globals()["año" + str(año)].columns.str.strip()
                  globals()["column" + str(año)]=globals()["año" + str(año)].columns
                  #hallo la posición de la columna que contiene a Enero
                  for col in range(0,len( globals()["column" + str(año)])):
                      if  globals()["column" + str(año)][col].lower() == 'enero':
                          j=col
                  #Paso de formato wide a long sabiendo cual es la columna que contiene a enero, lugar desde el cual queremos hacer el pivote
                  globals()["table" + str(año)] = pd.melt(globals()["año" + str(año)], id_vars=globals()["column" + str(año)][0:j], var_name="MES", value_name="ACEITE")
                  for columna1 in globals()["column" + str(año)]:
                      if columna1 == 'EMPRESA':
                          globals()["table" + str(año)] = globals()["table" + str(año)].rename(columns={'EMPRESA': 'OPERADORA'})
                      if columna1 == 'CUENCA':
                          globals()["table" + str(año)] = globals()["table" + str(año)].rename(columns={'CUENCA': 'MUNICIPIO'})
                          globals()["table" + str(año)]['MUNICIPIO'] = 'No encontrado' 
                  #Ahora convertiré el mes a número para tener datos secuenciales MM-YYYY
                  def mesnum(mes):
                      if mes.lower() == 'enero':
                          mesn = 1 
                      if mes.lower() == 'febrero':
                          mesn = 2 
                      if mes.lower() == 'marzo':
                          mesn = 3
                      if mes.lower() == 'abril':
                          mesn = 4 
                      if mes.lower() == 'mayo':
                          mesn = 5 
                      if mes.lower() == 'junio':
                          mesn = 6
                      if mes.lower() == 'julio':
                          mesn = 7 
                      if mes.lower() == 'agosto':
                          mesn = 8 
                      if mes.lower() == 'septiembre':
                          mesn = 9
                      if mes.lower() == 'octubre':
                          mesn = 10 
                      if mes.lower() == 'noviembre':
                          mesn = 11
                      if mes.lower() == 'diciembre':
                          mesn = 12
                      return mesn
                  globals()["table" + str(año)]['MM'] = globals()["table" + str(año)]['MES'].apply(mesnum)
                  globals()["table" + str(año)]['YYYY'] = año
                  #Concateno el mes y el año
                  def concat(*args):
                      strs = [str(arg) for arg in args if not pd.isnull(arg)]
                      return '/'.join(strs) if strs else np.nan
                  np_concat = np.vectorize(concat)
                  globals()["table" + str(año)]['MM-YYYY'] = np_concat(globals()["table" + str(año)]['MM'], globals()["table" + str(año)]['YYYY'])
                  #Realizo formato de fecha
                  globals()["table" + str(año)]['FECHA'] = globals()["table" + str(año)]['MM-YYYY'].apply(lambda x: datetime.strptime(x, '%m/%Y'))
                  #Borraré columnas que creé para generar la fecha
                  globals()["table" + str(año)].drop(['MM','MM-YYYY'], axis = 'columns', inplace=True)
                  listado_años.append(globals()["table" + str(año)])
      table= pd.concat(listado_años, ignore_index=True)
      return table
  
In [3]:
table_comp=lectyproc("Datos/Datos oficiales/")
  
In [4]:
table_comp.to_csv('Tabla general datos oficiales.csv',index=False)
  table_comp.to_excel('Tabla general datos oficiales.xlsx',index=False)
  
In [5]:
table_comp
  
Out[5]:
CAMPO CONTRATO MUNICIPIO OPERADORA DEPARTAMENTO MES ACEITE YYYY FECHA
0 Abanico Abanico No encontrado PACIFIC STRATUS ENERGY Tolima ENERO 1220.71 2013 2013-01-01
1 Abarco Nare No encontrado MANSAROVAR ENERGY COLOMBIA LTD. Boyacá ENERO 5027.19 2013 2013-01-01
2 Abedus Cravoviejo No encontrado C&C ENERGÍA Casanare ENERO 0 2013 2013-01-01
3 Abejas Estero No encontrado PERENCO COLOMBIA LIMITED Casanare ENERO 233.806 2013 2013-01-01
4 Acacia Este Las Quinchas No encontrado PACIFIC STRATUS ENERGY Santander ENERO 0 2013 2013-01-01
... ... ... ... ... ... ... ... ... ...
41395 RÍO SALDAÑA TOLIMA CHAPARRAL HOCOL S.A. TOLIMA AGOSTO 1133.84 2020 2020-08-01
41396 TOLDADO TOLDADO ORTEGA HOCOL S.A. TOLIMA AGOSTO 364.62 2020 2020-08-01
41397 TOQUI TOQUI PULI PIEDRAS HOCOL S.A. TOLIMA AGOSTO 362.87 2020 2020-08-01
41398 TOTARE ARMERO ALVARADO HOCOL S.A. TOLIMA AGOSTO 0 2020 2020-08-01
41399 TOY TOY ORTEGA HOCOL S.A. TOLIMA AGOSTO 0 2020 2020-08-01

41400 rows × 9 columns

In [6]:
table_comp[table_comp['YYYY']==2019]['ACEITE'].sum()
  
Out[6]:
10630608.662526865
In [7]:
blind_table_comp=lectyproc("Datos/Blind data/")
  
In [8]:
blind_table_comp
  
Out[8]:
DEPARTAMENTO MUNICIPIO OPERADORA CONTRATO CAMPO MES ACEITE YYYY FECHA
0 cf33cb8a cf33cb8a d5580f74 76a16657 1f d2689f ENERO 12371.083713 2017 2017-01-01
1 cf33cb8a cf33cb8a d5580f74 76a16657 9ac1420f ENERO 5.367156 2017 2017-01-01
2 cf33cb8a cf33cb8a d5580f74 76a16657 9b395bc9 ENERO 120.462831 2017 2017-01-01
3 cf33cb8a cf33cb8a d5580f74 29ded6f4 2f614c0b ENERO 23208.879752 2017 2017-01-01
4 cf33cb8a cf33cb8a d5580f74 29ded6f4 043b305e ENERO 4386.088856 2017 2017-01-01
... ... ... ... ... ... ... ... ... ...
1459 0fa93c9b 756c486f 2fe52430 4b05ae15 373ebdec DICIEMBRE 1084.287554 2019 2019-12-01
1460 0fa93c9b 756c486f 2fe52430 4b05ae15 e32e23a1 DICIEMBRE 414.497377 2019 2019-12-01
1461 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 0.000000 2019 2019-12-01
1462 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 408.016097 2019 2019-12-01
1463 657b6154 28b6a6a0 ffd6d24d 8568d01e 8568d01e DICIEMBRE 166.892938 2019 2019-12-01

1464 rows × 9 columns

In [9]:
blind_table_comp[blind_table_comp['YYYY']==2019]['ACEITE'].sum()
  
Out[9]:
946021.7258925696
In [10]:
blind_table_comp.to_csv('Tabla general datos ciegos.csv',index=False)
  blind_table_comp.to_excel('Tabla general datos ciegos.xlsx',index=False)
  

Archivo 2 : Respuestas datos oficiales

Se describe el procedimiento para las respuestas a las preguntas del reto. ademas de esto, se pasa el Data Frame a una base de datos usando Postgresql
In [1]:
from pathlib import Path
from datetime import date , datetime
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from scipy.optimize import curve_fit
from sqlalchemy import create_engine, text
warnings.filterwarnings("ignore")
In [2]:
#Creando la conexión con las bases de datos postgres local Nota: postgres deja en minuscula los encabezados, por eso toca pasarlos a mayuscula de nuevo aunque esto ya se hiciera en el archivo de lectura
#engine=create_engine(f'postgresql://postgres:postgres@localhost:5432/HACKATON', max_overflow=20)
#table_comp = pd.read_sql_table('datosoficiales',engine)
#table_comp.columns = table_comp.columns.str.upper()
#Si quiere probar los resultados con postgres, descomente las tres lineas anteriores y deje como comentario la siguiente
table_comp = pd.read_csv('Datos/Tablas resumen/Tabla general datos oficiales.csv')
In [3]:
table_comp
Out[3]:
CAMPO CONTRATO MUNICIPIO OPERADORA DEPARTAMENTO MES ACEITE YYYY FECHA
0 Abanico Abanico No encontrado PACIFIC STRATUS ENERGY Tolima ENERO 1220.709677 2013 2013-01-01
1 Abarco Nare No encontrado MANSAROVAR ENERGY COLOMBIA LTD. Boyacá ENERO 5027.193548 2013 2013-01-01
2 Abedus Cravoviejo No encontrado C&C ENERGÍA Casanare ENERO 0.000000 2013 2013-01-01
3 Abejas Estero No encontrado PERENCO COLOMBIA LIMITED Casanare ENERO 233.806452 2013 2013-01-01
4 Acacia Este Las Quinchas No encontrado PACIFIC STRATUS ENERGY Santander ENERO 0.000000 2013 2013-01-01
... ... ... ... ... ... ... ... ... ...
41395 RÍO SALDAÑA TOLIMA CHAPARRAL HOCOL S.A. TOLIMA AGOSTO 1133.840000 2020 2020-08-01
41396 TOLDADO TOLDADO ORTEGA HOCOL S.A. TOLIMA AGOSTO 364.620000 2020 2020-08-01
41397 TOQUI TOQUI PULI PIEDRAS HOCOL S.A. TOLIMA AGOSTO 362.870000 2020 2020-08-01
41398 TOTARE ARMERO ALVARADO HOCOL S.A. TOLIMA AGOSTO 0.000000 2020 2020-08-01
41399 TOY TOY ORTEGA HOCOL S.A. TOLIMA AGOSTO 0.000000 2020 2020-08-01

41400 rows × 9 columns

1

In [4]:
table2020=table_comp[table_comp['YYYY']==2020].reset_index(drop=True)
#Agrupo por campo
campo2020 = pd.pivot_table(table2020, values='ACEITE', index=['CAMPO'], aggfunc=np.sum).sort_values(by='ACEITE', ascending=False, na_position='first')
#Al agrupar también ordené de mayor a menor, por tanto el top 5 es igual a las primeras 5 filas
top2020campos=campo2020[0:5]
In [5]:
campo2020
Out[5]:
ACEITE
CAMPO
RUBIALES 857001.07
CASTILLA 537068.14
CHICHIMENE 388023.81
CASTILLA NORTE 380005.77
QUIFA 304783.67
... ...
CERRO GORDO 0.48
MARSUPIAL 0.32
MERECUMBE 0.26
LILIA 0.24
LISA 0.03

385 rows × 1 columns

In [6]:
top2020campos
Out[6]:
ACEITE
CAMPO
RUBIALES 857001.07
CASTILLA 537068.14
CHICHIMENE 388023.81
CASTILLA NORTE 380005.77
QUIFA 304783.67
In [7]:
plot = top2020campos.plot(kind='bar', title='Top 5 de campos de mayor producción de petróleo en 2020')

2

In [8]:
table2018=table_comp[table_comp['YYYY']==2018].reset_index(drop=True)
campo2018cas= table2018[table2018['DEPARTAMENTO']=='CASANARE'].drop('DEPARTAMENTO',axis=1).reset_index()
In [9]:
#Se divide en 12 porque en formato largo aparecera 12 veces cada conteo, uno por cada mes
campo2018cascount=(campo2018cas.groupby('OPERADORA')['CAMPO'].count()/12).to_frame()
campo2018cascount=campo2018cascount[campo2018cascount['CAMPO']>=5].sort_values(['CAMPO'],ascending=False)
campo2018cascount
Out[9]:
CAMPO
OPERADORA
Frontera Energy Colombia Corp Sucursal Colombia 37.0
PERENCO COLOMBIA LIMITED 36.0
GEOPARK COLOMBIA S.A.S. 22.0
ECOPETROL S.A. 10.0
PAREX RESOURCES COLOMBIA LTD. SUCURSAL 7.0
CEPSA COLOMBIA S.A. 6.0
COLOMBIA ENERGY DEVELOPMENT CO 6.0
NEW GRANADA ENERGY CORPORATION SUCURSAL COLOMBIA 6.0
CARRAO ENERGY S.A. SUCURSAL COLOMIBA 5.0
LEWIS ENERGY COLOMBIA INC 5.0
In [10]:
plot = campo2018cascount.plot(kind='bar', title='Operadoras que resportaron producción en más de 5 campos de Casanare en 2018')

3

In [11]:
contrato2018 = pd.pivot_table(table2018, values='ACEITE', index=['CONTRATO'], aggfunc=np.sum).sort_values(by='ACEITE', ascending=False, na_position='first')
#Divide en 1millon para dejar las unidades en MMstb
top2018contratos=contrato2018[0:5]/1000000
In [12]:
top2018contratos
Out[12]:
ACEITE
CONTRATO
CUBARRAL 2.177189
RUBIALES 1.433612
LLA 34 0.725580
QUIFA 0.554438
LA CIRA INFANTAS 0.542415
In [13]:
plot = top2018contratos.plot(kind='bar', title='Top 5 de contratos de mayor producción de petróleo en 2018')

4

In [14]:
table2019=table_comp[table_comp['YYYY']==2019].reset_index(drop=True)
operadora2019 = pd.pivot_table(table2019, values='ACEITE', index=['OPERADORA','MES'], aggfunc=np.sum).sort_values(by='ACEITE', ascending=False, na_position='first').reset_index(level='MES')
operadora2019ago=operadora2019[operadora2019['MES']=='AGOSTO'].sort_values(by='ACEITE', ascending=False, na_position='first').drop('MES',axis=1)
topoperadora2019ago=operadora2019ago[0:10]
In [15]:
operadora2019
Out[15]:
MES ACEITE
OPERADORA
ECOPETROL S.A. DICIEMBRE 484942.87
ECOPETROL S.A. ENERO 481671.46
ECOPETROL S.A. JUNIO 481050.47
ECOPETROL S.A. FEBRERO 480734.78
ECOPETROL S.A. MAYO 478635.43
... ... ...
INVEPETROL LIMITED COLOMBIA ABRIL 0.00
TPL COLOMBIA LTD - SUCURSAL COLOMBIA ANTES PANATLANTIC COLOMBIA LTD SUCURSAL EN COLOMBIA FEBRERO 0.00
PETROLEOS COLOMBIANOS SA MARZO 0.00
PETROLEOS COLOMBIANOS SA FEBRERO 0.00
TPL COLOMBIA LTD - SUCURSAL COLOMBIA ANTES PANATLANTIC COLOMBIA LTD SUCURSAL EN COLOMBIA ENERO 0.00

504 rows × 2 columns

In [16]:
topoperadora2019ago
Out[16]:
ACEITE
OPERADORA
ECOPETROL S.A. 473986.41
Frontera Energy Colombia Corp Sucursal Colombia 81441.68
GEOPARK COLOMBIA S.A.S. 69154.42
OCCIDENTAL DE COLOMBIA LLC 53299.12
EQUION ENERGÍA LIMITED 34950.01
GRAN TIERRA ENERGY COLOMBIA LTD 29555.20
MANSAROVAR ENERGY COLOMBIA LTD 25256.75
HOCOL S.A. 19614.02
PAREX RESOURCES COLOMBIA LTD. SUCURSAL 15727.97
CEPSA COLOMBIA S.A. 12702.09
In [17]:
plot = topoperadora2019ago.plot(kind='bar', title='Top 10 de operadoras con mayor producción de petróleo en agosto de 2019')

5

In [18]:
#Lista para realizar el filtro
T1=['enero','febrero','marzo']
T2=['abril','mayo','junio']
In [19]:
#Agrupo por mes
meses2019 = pd.pivot_table(table2019, values='ACEITE', index=['MES'], aggfunc=np.sum).sort_values(by='ACEITE', ascending=False, na_position='first').reset_index(level='MES')
#Aplico formato al texto para realizar el filtro correctamente 
meses2019['MES']=meses2019['MES'].apply(lambda x: x.lower())
#Aplico los filtros de los trimestres y guardo los resultados
T12019=meses2019[meses2019['MES'].isin(T1)].reset_index(drop=True)
T22019=meses2019[meses2019['MES'].isin(T2)].reset_index(drop=True)
#Agrupo por mes
meses2020 = pd.pivot_table(table2020, values='ACEITE', index=['MES'], aggfunc=np.sum).sort_values(by='ACEITE', ascending=False, na_position='first').reset_index(level='MES')
#Aplico formato al texto para realizar el filtro correctamente 
meses2020['MES']=meses2020['MES'].apply(lambda x: x.lower())
#Aplico los filtros de los trimestres y guardo los resultados
T12020=meses2020[meses2020['MES'].isin(T1)].reset_index(drop=True)
T22020=meses2020[meses2020['MES'].isin(T2)].reset_index(drop=True)
In [20]:
#Genero un data frame para guardas los resultados de los filtros y agrupaciones
trim1920 = pd.DataFrame({"Año": [2019,2020], "Trimestre 1": [T12019['ACEITE'].sum(),T12020['ACEITE'].sum()], "Trimestre 2": [T22019['ACEITE'].sum(),T22020['ACEITE'].sum()]})
#Subo a indice la columna año
trim1920.set_index("Año")
Out[20]:
Trimestre 1 Trimestre 2
Año
2019 2676538.43 2.677717e+06
2020 2619416.71 2.258345e+06
In [21]:
coloresMedallas = ['#FFD700','#C0C0C0']

trim1920.plot(kind = 'bar',
             width=0.8,
             figsize=(10,4),
             color = coloresMedallas);

Archivo 3 : Respuestas datos Blind Test

Se describe el procedimiento para las repuestas del reto en lo concerniente al Blind Test. se ajusta la columna con la fecha dado que al trabajarla se tiene como formato 'string' y no como un objecto fecha en python
In [1]:
from pathlib import Path
from datetime import date , datetime
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from scipy.optimize import curve_fit
from sqlalchemy import create_engine, text
warnings.filterwarnings("ignore")
In [2]:
#Creando la conexión con las bases de datos postgres local Nota: postgres deja en minuscula los encabezados, por eso toca pasarlos a mayuscula de nuevo aunque esto ya se hiciera en el archivo de lectura
#engine=create_engine(f'postgresql://postgres:postgres@localhost:5432/HACKATON', max_overflow=20)
#blind_table_comp = pd.read_sql_table('datosciegos',engine)
#blind_table_comp.columns = blind_table_comp.columns.str.upper()
#Si quiere probar los resultados con postgres, descomente las dos lineas anteriores y deje como comentario la siguiente
blind_table_comp = pd.read_csv('Datos/Tablas resumen/Tabla general datos ciegos.csv')
#Aunque en el documento de lectura se asignó a esta columna un tipo de dato datetime, al descargarlo a csv y leer el csv, esto no se conservó y toca cambiar el formato de string a date time
blind_table_comp['FECHA'] = pd.to_datetime(blind_table_comp['FECHA'])
In [3]:
blind_table_comp
Out[3]:
DEPARTAMENTO MUNICIPIO OPERADORA CONTRATO CAMPO MES ACEITE YYYY FECHA
0 cf33cb8a cf33cb8a d5580f74 76a16657 1f d2689f ENERO 12371.083713 2017 2017-01-01
1 cf33cb8a cf33cb8a d5580f74 76a16657 9ac1420f ENERO 5.367156 2017 2017-01-01
2 cf33cb8a cf33cb8a d5580f74 76a16657 9b395bc9 ENERO 120.462831 2017 2017-01-01
3 cf33cb8a cf33cb8a d5580f74 29ded6f4 2f614c0b ENERO 23208.879752 2017 2017-01-01
4 cf33cb8a cf33cb8a d5580f74 29ded6f4 043b305e ENERO 4386.088856 2017 2017-01-01
... ... ... ... ... ... ... ... ... ...
1459 0fa93c9b 756c486f 2fe52430 4b05ae15 373ebdec DICIEMBRE 1084.287554 2019 2019-12-01
1460 0fa93c9b 756c486f 2fe52430 4b05ae15 e32e23a1 DICIEMBRE 414.497377 2019 2019-12-01
1461 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 0.000000 2019 2019-12-01
1462 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 408.016097 2019 2019-12-01
1463 657b6154 28b6a6a0 ffd6d24d 8568d01e 8568d01e DICIEMBRE 166.892938 2019 2019-12-01

1464 rows × 9 columns

6

In [4]:
blind_table2019=blind_table_comp[blind_table_comp['YYYY']==2019].reset_index(drop=True)
#Si se desea inspeccionar otro campo y otro mes, solo debe cambiar estas variables
campo='1f d2689f'
mes='JULIO'
campo2019_7 = blind_table2019[blind_table2019['CAMPO']==campo.lower()][blind_table2019['MES']==mes.upper()].reset_index(drop=True)
print('Caudal de producción del campo', campo.upper(), 'en Julio de 2019:',campo2019_7['ACEITE'][0])
Caudal de producción del campo 1F D2689F en Julio de 2019: 4766.241346484784
In [5]:
blind_table2019
Out[5]:
DEPARTAMENTO MUNICIPIO OPERADORA CONTRATO CAMPO MES ACEITE YYYY FECHA
0 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f ENERO 7897.993261 2019 2019-01-01
1 cf33cb8a cf33cb8a d5580f74 1f d2689f 9ac1420f ENERO 134.214677 2019 2019-01-01
2 cf33cb8a cf33cb8a d5580f74 1f d2689f 9b395bc9 ENERO 322.628507 2019 2019-01-01
3 cf33cb8a cf33cb8a d5580f74 1f d2689f 254d7db5 ENERO 40.170881 2019 2019-01-01
4 cf33cb8a cf33cb8a d5580f74 29ded6f4 2f614c0b ENERO 22890.888398 2019 2019-01-01
... ... ... ... ... ... ... ... ... ...
547 0fa93c9b 756c486f 2fe52430 4b05ae15 373ebdec DICIEMBRE 1084.287554 2019 2019-12-01
548 0fa93c9b 756c486f 2fe52430 4b05ae15 e32e23a1 DICIEMBRE 414.497377 2019 2019-12-01
549 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 0.000000 2019 2019-12-01
550 657b6154 a6b36c07 ffd6d24d 38c31ea1 11e586b4 DICIEMBRE 408.016097 2019 2019-12-01
551 657b6154 28b6a6a0 ffd6d24d 8568d01e 8568d01e DICIEMBRE 166.892938 2019 2019-12-01

552 rows × 9 columns

In [6]:
blind_table2019[blind_table2019['CAMPO']==campo.lower()]
Out[6]:
DEPARTAMENTO MUNICIPIO OPERADORA CONTRATO CAMPO MES ACEITE YYYY FECHA
0 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f ENERO 7897.993261 2019 2019-01-01
46 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f FEBRERO 6687.201142 2019 2019-02-01
92 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f MARZO 6176.648164 2019 2019-03-01
138 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f ABRIL 5998.336864 2019 2019-04-01
184 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f MAYO 5838.969170 2019 2019-05-01
230 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f JUNIO 6390.660871 2019 2019-06-01
276 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f JULIO 4766.241346 2019 2019-07-01
322 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f AGOSTO 5871.527810 2019 2019-08-01
368 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f SEPTIEMBRE 5179.292397 2019 2019-09-01
414 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f OCTUBRE 5928.184630 2019 2019-10-01
460 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f NOVIEMBRE 6237.904951 2019 2019-11-01
506 cf33cb8a cf33cb8a d5580f74 1f d2689f 1f d2689f DICIEMBRE 6226.606211 2019 2019-12-01
In [7]:
by_field=sns.barplot(x='MES', y='ACEITE', hue='CAMPO', data=blind_table2019[blind_table2019['CAMPO']==campo.lower()], palette=sns.color_palette("RdBu", n_colors=7))
for item in by_field.get_xticklabels():
    item.set_rotation(45)

7

In [8]:
#Si se desea inspeccionar otro campo y otro mes, solo debe cambiar estas variables
operadora = '2fe52430'
mes = 'FEBRERO'
operadora2019_2 = blind_table2019[blind_table2019['OPERADORA']==operadora.lower()][blind_table2019['MES']==mes.upper()].reset_index(drop=True)
print('Caudal de producción de la operadora', operadora.upper(), 'en Febrero de 2019:',operadora2019_2['ACEITE'].sum())
Caudal de producción de la operadora 2FE52430 en Febrero de 2019: 7452.2204502174945
In [9]:
blind_table2019[blind_table2019['OPERADORA']==operadora.lower()][blind_table2019['MES']==mes.upper()]
Out[9]:
DEPARTAMENTO MUNICIPIO OPERADORA CONTRATO CAMPO MES ACEITE YYYY FECHA
74 f7fd2c4f 16b873c5 2fe52430 23980b82 7eb34927 FEBRERO 88.628230 2019 2019-02-01
75 f7fd2c4f 16b873c5 2fe52430 23980b82 4f4a249f FEBRERO 141.326684 2019 2019-02-01
76 f7fd2c4f 16b873c5 2fe52430 23980b82 8ba362f3 FEBRERO 477.124368 2019 2019-02-01
86 0fa93c9b 756c486f 2fe52430 4b05ae15 48670499 FEBRERO 5605.229884 2019 2019-02-01
87 0fa93c9b 756c486f 2fe52430 4b05ae15 373ebdec FEBRERO 572.625364 2019 2019-02-01
88 0fa93c9b 756c486f 2fe52430 4b05ae15 e32e23a1 FEBRERO 567.285920 2019 2019-02-01
In [10]:
by_field=sns.barplot(x='CAMPO', y='ACEITE', hue='MES', data=blind_table2019[blind_table2019['OPERADORA']==operadora.lower()][blind_table2019['MES']==mes.upper()], palette=sns.color_palette("RdBu", n_colors=7))
for item in by_field.get_xticklabels():
    item.set_rotation(45)

8

In [11]:
blind_table2018=blind_table_comp[blind_table_comp['YYYY']==2018].reset_index(drop=True)
#Agrupo por departamento
departamento2018 = pd.pivot_table(blind_table2018, values='ACEITE', index=['DEPARTAMENTO'], aggfunc=np.sum).sort_values(by='ACEITE', na_position='first').reset_index()
In [12]:
departamento2018
Out[12]:
DEPARTAMENTO ACEITE
0 0fa93c9b 98767.669386
1 f7fd2c4f 126069.165338
2 cf33cb8a 623608.432526
In [13]:
by_field=sns.barplot(x='DEPARTAMENTO', y='ACEITE', data=departamento2018, palette=sns.color_palette("RdBu", n_colors=7))
for item in by_field.get_xticklabels():
    item.set_rotation(45)

9

In [14]:
depcampo = pd.pivot_table(blind_table_comp, values='ACEITE', index=['DEPARTAMENTO','CAMPO','YYYY'], aggfunc=np.mean).sort_values(by='ACEITE', ascending=False, na_position='first').reset_index()
depcampo.drop(columns=['CAMPO','YYYY'],inplace=True)
In [15]:
summary_blind_table=depcampo.groupby('DEPARTAMENTO').describe().unstack(1)
print(summary_blind_table)
               DEPARTAMENTO
ACEITE  count  0fa93c9b            9.000000
               5f559ecb            1.000000
               657b6154            2.000000
               cf33cb8a           70.000000
               ec12ad00            3.000000
               eccb9ef1            1.000000
               f7fd2c4f           31.000000
        mean   0fa93c9b         2460.323964
               5f559ecb           14.576681
               657b6154          147.434035
               cf33cb8a         1819.576036
               ec12ad00            5.415088
               eccb9ef1           29.290088
               f7fd2c4f         1056.621413
        std    0fa93c9b         2537.313576
               5f559ecb                 NaN
               657b6154           74.044511
               cf33cb8a         2928.122479
               ec12ad00            8.328458
               eccb9ef1                 NaN
               f7fd2c4f         1219.352958
        min    0fa93c9b          479.041021
               5f559ecb           14.576681
               657b6154           95.076659
               cf33cb8a            0.374268
               ec12ad00            0.122720
               eccb9ef1           29.290088
               f7fd2c4f           32.483481
        25%    0fa93c9b          874.141684
               5f559ecb           14.576681
               657b6154          121.255347
               cf33cb8a          132.634932
               ec12ad00            0.615060
               eccb9ef1           29.290088
               f7fd2c4f          317.016578
        50%    0fa93c9b          927.678493
               5f559ecb           14.576681
               657b6154          147.434035
               cf33cb8a          404.799042
               ec12ad00            1.107400
               eccb9ef1           29.290088
               f7fd2c4f          564.751948
        75%    0fa93c9b         5131.886897
               5f559ecb           14.576681
               657b6154          173.612723
               cf33cb8a         2849.668766
               ec12ad00            8.061272
               eccb9ef1           29.290088
               f7fd2c4f         1690.345421
        max    0fa93c9b         6650.664063
               5f559ecb           14.576681
               657b6154          199.791411
               cf33cb8a        12458.858168
               ec12ad00           15.015145
               eccb9ef1           29.290088
               f7fd2c4f         4714.695603
dtype: float64
In [16]:
sns.set_theme(style="whitegrid")
ax = sns.violinplot(x="DEPARTAMENTO", y="ACEITE", 
                    data=depcampo, palette="muted")

Según los valores de desviación estandar, y el "violin plot" se observa claramente que el departamento cf33cb8a es el que tiene mayor variación en la producción promedio anual.

10

In [17]:
#Grafica de los datos de producción en el tiempo Nota: Se realiza para que pueda ser graficado distintos campos al tiempo
def RegularPlot(df, wells, units):
    fig, ax = plt.subplots(figsize=(15,8))
    plt.xlabel('Fecha')
    plt.ylabel('ACEITE '+ units)
    for well in wells:
        df_filtered = df[df['CAMPO']==well]
        rate = df_filtered['ACEITE']
        date = df_filtered['FECHA']
        ax.plot(date, rate, 'o', label=well)
    ax.legend(shadow=True, fancybox=True)
    return plt
#Se normaliza la grafica anterior con pasos mensuales

def NormalisedData(df, wells):
    norm_data = {}
    for well in wells:
        df_filtered = df[df['CAMPO']==well]
        start_date = min(df_filtered['FECHA'])
        rate = df_filtered['ACEITE']
        time = df_filtered['FECHA'] - start_date
        time = time.dt.days
        norm_data[well] = {
            'rate': rate,
            'time': time
        }
    return norm_data

def NormalisedPlot(df, wells):
    fig, ax = plt.subplots(figsize=(15, 8))
    plt.xlabel('DIAS')
    plt.ylabel('ACEITE')
    for well in wells:
        df_filtered = df[df['CAMPO']==well]
        start_date = min(df_filtered['FECHA'])
        rate = df_filtered['ACEITE']
        time = df_filtered['FECHA'] - start_date
        time = time.dt.days
        ax.plot(time, rate, 'o', label=well)
    ax.legend(shadow=True, fancybox=True)
    return plt
In [18]:
campo = ['51cbb05d']
dfcampo = blind_table_comp.drop(columns=['DEPARTAMENTO','MUNICIPIO','OPERADORA','CONTRATO','YYYY','MES']).reset_index(drop=True)
In [19]:
plot_data = RegularPlot (dfcampo, campo, 'BOPM')
In [20]:
normalised_data = NormalisedData(dfcampo, campo)
normalised_plot = NormalisedPlot(dfcampo, campo)
In [21]:
#Se dejará todo expresado de tal manera que si quiere realizar un tiempo de prueba y otro tiempo de testeo de la ecuación, solo deba cambiar "datat" y quitar el númeral de las dos lineas de código comentada
#Esto se hace ya que es algo común en métodos de machine learning
def arps(t, decline):   #Definimos la función de ARPS
        #Declinación hiperbolica
    #Se dejó el b factor como 0.5 según las indicaciones    
    values = initialrate / ((1 + 0.5 * decline * t) ** (1 / 0.5))      
    return values

fitdict2={}
for well in campo:
    X_p = normalised_data[well]['time']        
    Y_p = normalised_data[well]['rate']
    X_arps=X_p[:int(len(X_p))]           
    Y_arps=Y_p[:int(len(Y_p))]
    #Como tasa inicial se lee la primera tasa de producción, la cual debido al formato, corresponde al dia 30
    initialrate =  Y_arps[30]    
    #Se ajusta la nuve de puntos a la función de la ecuación de Arps
    popt, pcov = curve_fit(arps, X_arps, Y_arps, bounds=([0],[0.1]))    
    #Diccionario que guarda las variables que mejor se ajustan a la ecuación de Arps 
    fitdict2[well]={
      
      'decline rate': popt[0] 
    }
#Porcentaje de los datos que hubieran sido tomados como entrenamiento
datat=0
time_predict=[]
rate_predict=[]
arps_predict={}
for well in campo:
    X_p = normalised_data[well]['time']
    time_train=X_p[:int(len(X_p)*datat)]   
    time_predict=X_p[int(len(X_p)*datat):]    #20% de los datos como prueba
    Y_p = normalised_data[well]['rate']
    rate_test=Y_p[int(len(Y_p)*datat):]
    for time in time_predict:
        rate_predict=arps(time_predict, fitdict2[well]['decline rate'])
        #Descomentar la linea de abajo si quiere realizar split test
        #rate_train=arps(time_train, fitdict[well]['beta'], fitdict[well]['initial rate'], fitdict[well]['decline rate'])
    arps_predict[well]={
        'time':time_predict,
        'rate':rate_predict
    }
    plt.scatter(X_p, Y_p)
    plt.plot(time_predict, rate_predict, color='green', linewidth=3)
    #Descomentar la linea de abajo si quiere realizar split test
    #plt.plot(time_train, rate_train, color='red', linewidth=3)
    plt.xlabel('Days')
    plt.ylabel('Rate')
    plt.title('Arps equation')
    plt.show()
In [22]:
print('Se tiene una tasa de declinación de',fitdict2['51cbb05d']['decline rate'])
Se tiene una tasa de declinación de 0.0034727883551543617