<jupyter_start><jupyter_text><jupyter_code>import gspread

import pandas as pd
import re

gc = gspread.service_account()
worksheet = gc.open('Total partidas').sheet1

rows = worksheet.get_all_values()

data = pd.DataFrame.from_records(rows)
data.columns = data.iloc[0]
data.drop(0, inplace=True)
display(data.info())
display(data.describe())
respaldo = data.copy(deep=True)
data = respaldo[['Id_Partida', 'Convocante', 'Descripción', 'Descripción de la Clave', 'Grupo de productos', 'Cuadro Básico', 'Nos interesa', 'Grupo Productos']]
data.columns = ['id', 'convocante', 'descripcion', 'clave', 'grupo_1', 'cuadro_basico', 'interes', 'grupo_2']
data['cuadro_2'] = data['descripcion'].str.extract(r'(\d{3}[\.\s-]\d{3}[\.\s-]\d{4})').replace(r'[\s-]', '.')
CATEGORIAS = ['grupo_1', 'clave', 'interes', 'grupo_2']
data['grupo_2'] = data['grupo_2'].str.lower()
data['descripcion'] = data['descripcion'].str.lower()
data['grupo_2'][data['grupo_2'] == 'película y químicos dental'] = 'pelicula y quimicos dental'
data['grupo_2'][data['grupo_2'] == 'retos ind. quimicos'] = 'indicadores quimicos'
data['grupo_2'][data['grupo_2'] == 'reveladoras y casetas análogas'] = 'filme plano'
data['grupo_2'][data['grupo_2'] == 'mastografía'] = 'mastografias'
data['grupo_2'][data['grupo_2'] == 'rayos x digital'] = 'dr'
data['grupo_2'][data['grupo_2'] == 'mesa de rayos x'] = 'dr'
data['grupo_2'][data['grupo_2'] == 'dental digital'] = 'dr'
data['grupo_2'][data['grupo_2'] == 'película dry'] = 'pelicula dry'
data['grupo_2'][data['grupo_2'] == 'automaticas'] = 'servicios profesionales'
data['grupo_2'][data['grupo_2'] == 'impresoras'] = 'pelicula dry'
data['grupo_2'][data['grupo_2'] == 'pacs/ris'] = 'dr'
data[CATEGORIAS] = data[CATEGORIAS].apply(lambda x: x.astype('category'), axis=0)
categorias_dumies = pd.get_dummies(data[CATEGORIAS])
grupo_tech = pd.get_dummies(data['grupo_1'])
data['grupo_2'].value_counts()<jupyter_output>/home/mauricio/.local/lib/python3.9/site-packages/pandas/core/frame.py:3599: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self._set_item_frame_value(key, value)
/home/mauricio/.local/lib/python3.9/site-packages/pandas/core/frame.py:3607: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self._set_item(key, value)
/home/mauricio/.local/lib/python3.9/site-packages/pandas/core/generic.py:8861: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the docume[...]<jupyter_text>Modelo de clasificación con todos los datosPara generar un modelo de clasificación de los datos de las partidas a partir de regresión logística.<jupyter_code>y = data['grupo_2']
X = data.drop('grupo_2', axis=1)
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split.split(X, y):
  X_train = X.iloc[train_index]
  X_test = X.iloc[test_index]
  y_train = y.iloc[train_index]
  y_test = y.iloc[test_index]

from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.multiclass import OneVsRestClassifier

tokens = '[A-Za-z0-9]+(?=\\s+)'

X_train['descripcion'].fillna('', inplace=True)

vectorizer = CountVectorizer(token_pattern= tokens)
vectorizer.fit_transform(X_train['descripcion'])

pl = Pipeline([
    ('vec', CountVectorizer(token_pattern = tokens)),
    ('clf', OneVsRestClassifier(LogisticRegression(max_iter=200)))
])

pl.fit(X_train['descripcion'], y_train)
import numpy as np

data2 = data.sort_values('grupo_2')
no_producto = data2.iloc[0:116984]
productos = data2.iloc[116985:]
drops = np.random.choice(no_producto.index, 100000, replace=False)
no_producto.drop(drops, inplace=True)
data2 = pd.concat([no_producto, productos])
X2 = data2.drop('grupo_2', axis=1)
y2 = data2['grupo_2']
X2['descripcion'].fillna('', inplace=True)
vec = CountVectorizer(token_pattern=tokens)
vec.fit_transform(X_train['descripcion'])
pl.fit(X2['descripcion'], y2)

data2[['descripcion', 'cuadro_2', 'grupo_2']].to_csv('datos_entrenamiento.csv', index=False)<jupyter_output><empty_output><jupyter_text>Clasificación con SpacyUna prueba para mejorar el modelo usando los modelos preentrenados de spacy<jupyter_code># Ejemplo usando Spacy para la clasificaión de las partidas
!pip install --upgrade spacy
import spacy
nlp = spacy.blank('es')
textcat = nlp.add_pipe('textcat')
labels = data['grupo_2'].unique()
for label in labels:
  textcat.add_label(label)

train_text = data['descripcion'].values
train_labels = [{'cats': {label: case == label for label in labels}} for case in data['grupo_2']]
train_data = list(zip(train_text, train_labels))
train_data[:3]
from spacy.util import minibatch
from spacy.training.example import Example 

spacy.util.fix_random_seed(1)
optimizer = nlp.begin_training()

batches = minibatch(train_data, size=10)
for batch in batches:
  for text, labels in batch:
    doc = nlp.make_doc(text)
    example = Example.from_dict(doc, labels)
    nlp.update([example], sgd=optimizer)<jupyter_output><empty_output><jupyter_text>Ejemplo de aplicación del modeladoEste es un ejemplo del uso del algoritmo en un archivo anterior de partidas.<jupyter_code>ejemplo = gc.open_by_key('<KEY>')
ejemplo = ejemplo.get_worksheet(1)
rows = ejemplo.get_all_values()
ejemplo = pd.DataFrame.from_records(rows)
ejemplo.columns = ejemplo.iloc[0]
ejemplo.drop(0, inplace=True)
ejemplo['Descripción'] = ejemplo['Descripción'].str.lower()
display(ejemplo.describe())
textos = ejemplo['Descripción']
docs = [nlp.tokenizer(texto) for texto in textos]
textcat = nlp.get_pipe('textcat')
scores = textcat.predict(docs)
predicted_labels = scores.argmax(axis=1)
predicted_labels = [textcat.labels[label] for label in predicted_labels]
ejemplo['prediccion'] = predicted_labels

# Los resultados de las predicciones fueron peores que con regresión lógistica de sklearn con un tiempo de entrenamiento de 75 min.
ejemplo['prediccion'] = pl.predict(ejemplo['Descripción'])
ejemplo
todas = pd.read_csv('partidas_solicitante2.csv')
todas['categoria'] = pl.predict(todas['descripcion'])
todas.to_csv('partidas_etiquetadas.csv', index=False)<jupyter_output><empty_output><jupyter_text>Procesado de los datos de Cantidades<jupyter_code>textos = [text for text in data['Cantidad Máxima'] if len(text) > 5]

rango_maxmin = r'(\d+) a (\d+)'
cantidad_unidad = r'(\d+) (\w+)'
minmax = r'min+max'
dos_palabras = r'([A-Z]+) +([A-Z]+)'
miles = r'(\d{1,3}),(\d{3})'

display(textos)
display([re.match(cantidad_unidad, texto).group(2) for texto in textos if re.match(cantidad_unidad, texto)])
# Funciones utilitarias

def num_text_to_int(text):
  nums = ['cero', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve', 'diez']
data['Cantidad Máxima'] = (data['Cantidad Máxima'].str.replace('\D', ''))
data['Cantidad Mínima'] = (data['Cantidad Mínima'].str.replace('\D', ''))
data['Cantidad Máxima'] = data['Cantidad Máxima'].astype(int)
data['Cantidad Mínima'] = data['Cantidad Mínima'].astype(int)
for index, num in enumerate(data['Cantidad Máxima']):
  print('{} {}'.format(index, int(num)))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15931628392484343, 'fraction_numerical': 0.016179540709812108, 'mean_word_length': 6.94300518134715, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '515656', 'license': 'MIT', 'n_tokens_mistral': 3017, 'n_tokens_neox': 2963, 'n_words': 581, 'path': 'clasificacion.ipynb', 'repo_name': 'bjimenezTechnodomus/licitaciones', 'size': '7703'}