Actian Vector a été rebaptisé Actian Analytics Engine en 2026.

Dans la première partie de cet article en deux parties, nous avons créé le modèle. Dans cette partie, nous allons créer les UDF dans la base de données.

Nous pouvons convertir le modèle en Python, et j'ai utilisé m2cgen pour transposer le modèle sklearn en modèle Python .

Je vais fabriquer 3 types d'UDF,

  1. Fonction définie par l'utilisateur (Python .
  2. Fonction définie par l'utilisateur (UDF) JavaScript.
  3. Enregistrement des données au format JSON, puis classification à partir de ces données JSON.

Fonction définie par l'utilisateur (Python

La ligne de code suivante nous permettra d'obtenir un modèle en Python.

import m2cgen as m2c\
code = m2c.export_to_python(clf)\
Le résultat obtenu est le suivant :\
def score(input):\
return [0.2834483510261381 + input[0] * 0.4156346233598447
+ input[1] * 1.6410466066307934 + input[2]
* -2.4486206310542746 + input[3] * -1.0775840518519904,
1,271492823301712 + input[0] * 0,7334652955571552
+ input[1] * -2,0527321763924102 + input[2]
* 0,4049181379167901 + input[3] * -1,4276343377888174,
-1,403879236024429 + input[0] * -1,8886197150361799
+ input[1] * -1,701005052157171 + input[2]
* 2.803528886728411 + input[3] * 2.6749639949986195]
Comme m2cgen a besoin d'un tableau en entrée, nous fournissons input sous forme de chaîne de caractères et la divisons en valeurs flottantes.
input = [float(i) for i in lst.split(",")]

Mathématiques : régression linéaire et régression logistique

La formule de régression linéaire est la suivante ;

Y=Wo+ X1W1+ X2W2+ X3W3+ ......

La régression linéaire est davantage conçue pour prédire des valeurs numériques que pour résoudre un problème de classification.

Cependant, pour la régression logistique, nous aimerions obtenir un résultat entre 0 et 1. Pour cela, nous devons utiliser une fonction non linéaire appelée sigmoïde ;

H(X) =1/(1 + e^ (-y))

Les résultats sont interprétés en termes de probabilités.

Nous avons 4 valeurs d'entrée et m2cgen nous donne facilement une équation linéaire avec nos entrées, le coefficient et les intercepts calculés par le modèle. Nous appliquons la fonction sigmoïde à l'équation ci-dessus et nous obtenons une classification un contre un.

for i in range(0, len(var0)):
    arr1.append(1 / (1 + math.exp(-var0[i])))
    print(arr1)

Après avoir appliqué sigmod, nous obtenons un tableau. Comme notre fonction définie par l'utilisateur (UDF) est scalaire, nous devons modifier le code pour qu'il renvoie l'index de l'élément du tableau présentant la probabilité maximale. Il suffit d'ajouter du code pour renvoyer l'index de la valeur maximale ;

max_val = arr1[0]
for i in range(0, len(arr1)):
    if arr1[i] > max_val:
        index = i
        max_val = arr1[i]
        return index + 1
En regroupant tout cela, notre fonction se présente comme suit :
import math
def score (lst):
input = [float(i) for i in lst.split(",")]
var0 = [((((0.24739569243110213) + ((input[0]) * (0.3677840447489154))) + ((input[1]) * (1.4151458935607388))) + ((input[2]) * (-2.124321635674482))) + ((input[3]) * (-0.9309638143559119)), ((((0.7060488675827682) + ((entrée[0]) * (0,6404296785789872))) + ((entrée[1]) * (-1,7889249557223028))) + ((entrée[2]) * (0,4056580513021318))) + ((entrée[3]) * (-1,106884750746711)), ((((-0,9529159159570318) + ((entrée[0]) * (-1,5615947756178696))) + ((input[1]) * (-1,1894433955845047))) + ((input[2]) * (2,1944766675309997))) + ((input[3]) * (2,0100453163309537))]
print(var0)
index=0
arr1=[]
for i in range(0,len(var0)):
    arr1.append( 1 / (1 + math.exp(-var0[i])))
    print(arr1)
max_val=arr1[0]
for i in range(0,len(arr1)):
if arr1[i] > max_val:
index=i
max_val=arr1[i]
return index+1
La structure de notre fonction définie par l'utilisateur (UDF) est prête ; il suffit d'ajouter CREATE OR REPLACE FUNCTION pour que la syntaxe soit correcte et puisse être ajoutée à la base de données.
udf='''CREATE OR REPLACE FUNCTION Iris_classifier(lst VARCHAR(100) not null)
return (int not null)
AS LANGUAGE PYTHON
SOURCE='
def score (lst):
input = [float(i) for i in lst.split(",")]
var0= [((((0.24739569243110213) + ((input[0]) * (0.3677840447489154))) + ((input[1]) * (1.4151458935607388))) + ((input[2]) * (-2.124321635674482))) + ((input[3]) * (-0.9309638143559119)), ((((0.7060488675827682) + ((entrée[0]) * (0,6404296785789872))) + ((entrée[1]) * (-1,7889249557223028))) + ((entrée[2]) * (0,4056580513021318))) + ((entrée[3]) * (-1,106884750746711)), ((((-0,9529159159570318) + ((entrée[0]) * (-1,5615947756178696))) + ((input[1]) * (-1,1894433955845047))) + ((input[2]) * (2,1944766675309997))) + ((input[3]) * (2,0100453163309537))]
print(var0)
index=0
max_val=var0[0]
for i in range(0,len(var0)):
if var0[i] > max_val:
index=i
max_val=var0[i]
return index+1
return score (lst)'
'''

Notre fonction UDF est prête, il ne nous reste plus qu'à l'ajouter à la base de données.

cursor.execute(udf)
conn.commit()

L'UDF est ajoutée à la base de données et peut être utilisée pour la classification des données. Notez que l'entrée est ajoutée sous forme de chaîne de caractères, car m2cgen attend une chaîne de caractères en entrée pour le modèle.

predict='''select CASE
WHEN species='Iris-setosa' THEN '1'
WHEN species='Iris-versicolor' THEN '2'
ELSE '3'
END as species, Iris_classifier (sepallengthcm  || ',' || sepalwidthcm  || ',' || petallengthcm  || ',' || petalwidthcm ) as classify  from iris'''
predict1=pd.read_sql(predict, conn)
predict1.head()

Fonction définie par l'utilisateur (UDF) JavaScript

Pour transcompiler la fonction UDF JavaScript, il suffit de fournir les éléments suivants :

code = m2c.export_to_javascript(clf)
output generated is
function score(input) {
return [((((0.2901789521827987) + ((input[0]) * (0.4467535618836661))) + ((input[1]) * (1.5843519667681565))) + ((input[2]) * (-2.409947591791464))) + ((input[3]) * (-1.0736156286007468)), ((((0.8330817501826279) + ((input[0]) * (1.0259003852575856))) + ((input[1]) * (-2.4327046722797347))) + ((input[2]) * (0.48745117088772905))) + ((input[3]) * (-1.8329094419137872)), ((((-1.141764377255606) + ((input[0]) * (-2.35933886039274))) + ((input[1]) * (-1.2090666108474617))) + ((input[2]) * (2.981435002839768))) + ((input[3]) * (2.99871035615134))];
}

Ici, je renvoie l'indice de la valeur maximale et je n'utilise pas la fonction sigmoïde, car si je n'utilise pas la fonction sigmoïde, elle fonctionne sur les estimations du maximum de vraisemblance.

Il suffit de le modifier en fonction de la qualification UDF pour Javascript.

udf_JS ='''create function  iris_lr_javascript1(lst VARCHAR(100) not
null) return (int not null) AS LANGUAGE JAVASCRIPT SOURCE='
function score(lst) {
var input = lst.split(",").map(function(item) {  return
parseFloat(item); });
nums=[((((0.2901789521827987) + ((input[0]) * (0.4467535618836661))) + ((input[1]) * (1.5843519667681565))) + ((input[2]) * (-2.409947591791464))) + ((input[3]) * (-1.0736156286007468)), ((((0.8330817501826279) + ((input[0]) * (1.0259003852575856))) + ((input[1]) * (-2.4327046722797347))) + ((input[2]) * (0.48745117088772905))) + ((input[3]) * (-1.8329094419137872)), ((((-1.141764377255606) + ((input[0]) * (-2.35933886039274))) + ((input[1]) * (-1.2090666108474617))) + ((input[2]) * (2.981435002839768))) + ((input[3]) * (2.99871035615134))];
var index = 0;
for (var i = 0; i < nums.length; i++) {
index = nums[i] > nums[index] ? i : index;
}
return index+1;
}
return score(lst)'
'''
cursor.execute(udf_JS)
conn.commit()

Notre fonction UDF est désormais enregistrée dans la base de données ; de la même manière, nous pouvons l'utiliser pour la classification, comme nous l'avons fait avec la fonction Python .

Fonction UDF avec des données JSON

VectorH 6.0 et Vector 6.0 support également support type de données JSON. Nous pouvons donc convertir le modèle en données JSON, qui seront ensuite utilisées avec notre modèle.

import json
model_param = {}
model_param['coef'] = clf.coef_.tolist()
model_param['intercept'] =clf.intercept_.tolist()
b = json.dumps(model_param)
print(b)
{"coef": [[0.4467535618836661, 1.5843519667681565, -2.409947591791464, -1.0736156286007468], [1.0259003852575856, -2.4327046722797347, 0.48745117088772905, -1.8329094419137872], [-2.35933886039274, -1.2090666108474617, 2.981435002839768, 2.99871035615134]], "intercept": [0.2901789521827987, 0.8330817501826279, -1.141764377255606]}
jsonstr='''create function  iris_lr_json(lst VARCHAR(100) not null)
return (int not null) AS LANGUAGE python SOURCE='
import json
def score1 (lst):
input = [float(i) for i in lst.split(",")]
json_data = "{"coef": [[0.4156346233598447, 1.6410466066307934, 
-2.4486206310542746, -1.0775840518519904], [0.7334652955571552, 
-2.0527321763924102, 0.4049181379167901, -1.4276343377888174], 
[-1.8886197150361799, -1.701005052157171, 2.803528886728411, 
2.6749639949986195]], "intercept": [0.2834483510261381, 
1.271492823301712, -1.403879236024429]}"
dictjson = json.loads(json_data)
# raise Exception("it is %s" % str(dictjson))
var0=[dictjson["intercept"][0]+ input[0]*dictjson["coef"][0][0] +
input[1]*dictjson["coef"][0][1]+input[2]*dictjson["coef"][0][2] +
input[3]*dictjson["coef"][0][3], dictjson["intercept"][1]+
input[0]*dictjson["coef"][1][0] +input[1]*dictjson["coef"][1][1]+
input[2]*dictjson["coef"][1][2] + input[3]*dictjson["coef"][1][3],
dictjson["intercept"][2]+ input[0]*dictjson["coef"][2][0] +
input[1]*dictjson["coef"][2][1]+input[2]*dictjson["coef"][2][2] +
input[3]*dictjson["coef"][2][3]]
#print(var0)
index=0
max_val=var0[0]
for i in range(0,len(var0)):
if var0[i] > max_val:
index=i
max_val=var0[i]
return index+1
return score (lst)'
'''
cursor.execute(jsonstr)
conn.commit()

L'UDF peut être appelé simplement par la requête, comme indiqué dans Python UDF.

Le code détaillé est disponible à l'adresse suivante : https://github.com/ActianCorp/MachineLearningUDFs/blob/master/Vector-UDF.ipynb

Si vous avez des questions, n'hésitez pas à me contacter à l'adresse suivante : [email protected]

Conclusion

L'intérêt des UDF sur base de données pour l'évaluation ML réside dans la possibilité d'évaluer les données sur base de données à une vitesse fulgurante. Le modèle et les données se trouvent au même endroit, ce qui réduit les déplacements de données. Toutes les opérations étant exécutées sur la base de données, vos modèles d'apprentissage automatique fonctionneront extrêmement rapidement grâce au moteur Vector X100. Python est l'un des langages les plus utilisés pour le développement de l'apprentissage automatique, il sera donc très facile de transférer et de gérer les modèles Python et JavaScript sur la base de données Scalar FDU pour le scoring par lots et les cas d'utilisation de scoring en temps quasi-réel.

Pour en savoir plus sur les Fonctionnalités tous les produits Actian, visitez notre site web.