{"id":626,"date":"2016-06-28T07:35:41","date_gmt":"2016-06-28T06:35:41","guid":{"rendered":"http:\/\/blog.tiran.info\/?p=626"},"modified":"2017-12-22T14:44:22","modified_gmt":"2017-12-22T13:44:22","slug":"classification-bayesienne-naive-avec-oracle","status":"publish","type":"post","link":"https:\/\/blog.tiran.stream\/?p=626","title":{"rendered":"Classification Bay\u00e9sienne Na\u00efve avec Oracle"},"content":{"rendered":"<p style=\"text-align: justify;\">Les r\u00e9centes campagnes concernant le <a href=\"http:\/\/www.telegraph.co.uk\/news\/2016\/06\/15\/eu-referendum-remain-uses-project-fear-more-in-tweets-than-leave\/\" target=\"_blank\">maintien de la Grande Bretagne dans l&rsquo;UE<\/a> ou celle des <a href=\"http:\/\/www.techrepublic.com\/article\/election-tech-clinton-and-trump-prove-social-analytics-are-predictive-analytics\/\" target=\"_blank\">primaires aux Etats-Unis<\/a> ont mis sur le devant de la sc\u00e8ne de nouvelles m\u00e9thodes de d\u00e9termination des tendances de votes. Ces derni\u00e8res se basent en grand partie sur les <a href=\"http:\/\/archives.lesechos.fr\/archives\/cercle\/2013\/04\/05\/cercle_69745.htm\" target=\"_blank\">informations \u00e9chang\u00e9es via les r\u00e9seaux sociaux<\/a> &#8211; Twitter notamment &#8211; et sont connues sous le nom d&rsquo;<a href=\"https:\/\/fr.wikipedia.org\/wiki\/Opinion_mining\" target=\"_blank\">Analyse de Sentiment ou Opinion Mining<\/a>.<\/p>\n<p style=\"text-align: justify;\">Leur principe consiste \u00e0 exploiter une information non-structur\u00e9e &#8211; du texte g\u00e9n\u00e9ralement &#8211; pour d\u00e9terminer des nuances (pour\/contre, triste\/neutre\/joyeux etc&#8230;).<\/p>\n<p style=\"text-align: justify;\">On imagine ais\u00e9ment la complexit\u00e9 de ce type d&rsquo;analyse dans la mesure o\u00f9 il y a une infinit\u00e9 de mani\u00e8re d&rsquo;exprimer un avis dans un texte.<\/p>\n<p style=\"text-align: justify;\">Une des techniques employ\u00e9es pour r\u00e9aliser ce genre d&rsquo;analyse &#8211; <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Classification_na%C3%AFve_bay%C3%A9sienne\" target=\"_blank\">la Classification Na\u00efve Bay\u00e9sienne<\/a> &#8211; se base, comme son nom l&rsquo;indique, sur l&rsquo;<a href=\"https:\/\/fr.wikipedia.org\/wiki\/Inf%C3%A9rence_bay%C3%A9sienne\" target=\"_blank\">inf\u00e9rence Bay\u00e9sienne<\/a>. Cette technique est dite na\u00efve car elle repose sur une simplification majeure &#8211; \u00e0 savoir, l&rsquo;ind\u00e9pendance des mots au sein du texte. C&rsquo;est bien entendu faux mais en pratique, cela marche quand m\u00eame! On trouve sur internet de nombreuses discussions &amp; \u00e9tudes expliquant pourquoi ce n&rsquo;est pas vraiment probl\u00e9matique.<\/p>\n<p style=\"text-align: justify;\">Toujours est-t \u2018il que cette simplification autorise la repr\u00e9sentation du texte sous la forme d&rsquo;un <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Sac_de_mots\" target=\"_blank\">sac de mots<\/a>. Sous cette forme, seules les fr\u00e9quences relatives d&rsquo;apparition des termes sont importantes pour le classifieur. Il existe aussi des variantes bas\u00e9es sur des n-grams (groupes de n mots).<\/p>\n<p style=\"text-align: justify;\">A titre d&rsquo;exemple, dans ce billet, je me suis int\u00e9ress\u00e9 \u00e0 la d\u00e9termination du genre litt\u00e9raire d&rsquo;un livre \u00e0 partir du r\u00e9sum\u00e9 g\u00e9n\u00e9ralement pr\u00e9sent\u00e9 en quatri\u00e8me de couverture. Pour cela, j&rsquo;ai r\u00e9alis\u00e9 un peu de web-scrapping \u00e0 partir du site de l&rsquo;<a href=\"http:\/\/www.decitre.fr\/\" target=\"_blank\">excellent \u00e9diteur Decitre<\/a>.<\/p>\n<p style=\"text-align: justify;\">Cela m&rsquo;a permis de collecter environ 21000 r\u00e9sum\u00e9s de livres dans trois genre diff\u00e9rents: Litt\u00e9rature Sentimentale, Polar et Philosophie-Sociologie.<\/p>\n<p style=\"text-align: justify;\">On peut comprendre le fonctionnement du classifieur \u00e0 partir d&rsquo;un exemple simple de faible dimension. Imaginons par exemple que l&rsquo;on essaie de d\u00e9terminer le genre d\u2019un livre dont l&rsquo;extrait contient les 3 termes suivants: \u00ab\u00a0meurtre\u00a0\u00bb, \u00ab\u00a0romance\u00a0\u00bb, \u00ab\u00a0enqu\u00eate\u00a0\u00bb.<\/p>\n<p style=\"text-align: justify;\">La formule du <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Th%C3%A9or%C3%A8me_de_Bayes\" target=\"_blank\">th\u00e9or\u00e8me de Bayes<\/a> nous dit P(A|B)=P(B|A)P(A)\/P(B)<\/p>\n<p style=\"text-align: justify;\">On calcule d&rsquo;abord les probabilit\u00e9s \u00ab\u00a0\u00e0 priori\u00a0\u00bb de chaque classe P(A) dans notre jeu d&rsquo;apprentissage. Ici, consid\u00e9rons les valeurs suivantes:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(sentimental)=0.33<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(polar)=0.5<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(philo-socio)=0.17<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Puis on calcule, \u00e0 partir du jeu d&rsquo;apprentissage, la probabilit\u00e9 des mots (unigrammes) dans chaque classe:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meutre|sentimental)=0.1<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meutre|polar)=0.9<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meutre|philo-socio)=0.05<\/span><\/li>\n<\/ul>\n<ul>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(romance|sentimental)=0.8<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(romance|polar)=0.3<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(romance|philo-socio)=0.6<\/span><\/li>\n<\/ul>\n<ul>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(enqu\u00eate|sentimental)=0.05<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(enqu\u00eate|polar)=0.9<\/span><\/li>\n<li style=\"text-align: justify;\"><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(enqu\u00eate|philo-socio)=0.4<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Ce calcul est souvent accompagn\u00e9 d&rsquo;une <a href=\"https:\/\/en.wikipedia.org\/wiki\/Additive_smoothing\" target=\"_blank\">correction de Laplace<\/a> pour \u00e9viter l&rsquo;effet de l&rsquo;absence d&rsquo;un terme dans une cat\u00e9gorie.<\/p>\n<p style=\"text-align: justify;\">On peut ensuite\u00a0calculer la vraisemblance P(B|A) pour chaque classe. Celle-ci se simplifie en un produit des probabilit\u00e9s des unigrammes en raison de l&rsquo;hypoth\u00e8se d&rsquo;ind\u00e9pendance des termes (aspect \u00ab\u00a0Na\u00eff\u00a0\u00bb de la m\u00e9thode):<\/p>\n<ul>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meurtre, romance, enqu\u00eate|sentimental) = P(meutre|sentimental)*P(romance|sentimental)*P(enqu\u00eate|sentimental)=0.1*0.8*0.05=0.004<\/span><\/li>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meurtre, romance, enqu\u00eate|polar)=P(meutre|polar)*P(romance|polar)*P(enqu\u00eate|polar)=0.9*0.3*0.9=0.243<\/span><\/li>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(meurtre, romance, enqu\u00eate|philo-socio)=P(meutre|philo-socio)*P(romance|philo-socio)*P(enqu\u00eate|philo-socio)=0.05*0.6*0.4=0.012<\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\">On arrive enfin \u00e0 l&rsquo;application du th\u00e9or\u00e8me de Bayes pour le calcul des probabilit\u00e9s \u00e0 posteriori P(A|B):<\/p>\n<ul>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(sentimental|meurtre, romance, enqu\u00eate) = P(meurtre, romance, enqu\u00eate|sentimental)*P(sentimental)\/P(meurtre, romance, enqu\u00eate)=<strong>0.00132\/P(meurtre, romance, enqu\u00eate)<\/strong><\/span><\/li>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(polar|meurtre, romance, enqu\u00eate)=P(meurtre, romance, enqu\u00eate|polar)*P(polar)\/P(meurtre, romance, enqu\u00eate)=<strong>0.1215\/P(meurtre, romance, enqu\u00eate)<\/strong><\/span><\/li>\n<li><span style=\"font-family: 'courier new', courier, monospace; font-size: 10pt;\">P(philo-socio|meurtre, romance, enqu\u00eate)=P(meurtre, romance, enqu\u00eate|philo-socio)*P(philo-socio)\/P(meurtre, romance, enqu\u00eate)=<strong>0.00204\/P(meurtre, romance, enqu\u00eate)<\/strong><\/span><\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Le d\u00e9nominateur \u00e9tant le m\u00eame entre les 3 expressions, leur comparaison est possible sur la base du num\u00e9rateur. On voit ainsi clairement que la probabilit\u00e9 que l&rsquo;extrait provienne d&rsquo;un polar est la plus importante.<\/p>\n<p style=\"text-align: justify;\">C&rsquo;est sur ce\u00a0principe\u00a0que la classification est r\u00e9alis\u00e9e.<\/p>\n<p style=\"text-align: justify;\">A noter que lors d&rsquo;une impl\u00e9mentation informatique, on passera par une transformation logarithmique pour changer les multiplications en additions et ainsi \u00e9viter le <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Soupassement_arithm%C3%A9tique\" target=\"_blank\">probl\u00e8me d&rsquo;underflow<\/a> qui survient lors de la multiplication d&rsquo;un grand nombre de faibles probabilit\u00e9s.<\/p>\n<p style=\"text-align: justify;\">Voil\u00e0, pour le principe g\u00e9n\u00e9ral\u2026<\/p>\n<p style=\"text-align: justify;\">Passons maintenant \u00e0 la mise en pratique \u00e0 grande \u00e9chelle!<\/p>\n<h2 style=\"text-align: justify;\">Pr\u00e9paration des donn\u00e9es<\/h2>\n<p style=\"text-align: justify;\">Les donn\u00e9es sont accessibles ici au format Table Externe DataPump:\u00a0<a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2016\/06\/DECITRE_EXTTAB.zip\">DECITRE_EXTTAB<\/a><\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE OR REPLACE DIRECTORY D1 AS &#039;C:\\RTI\\Tmp&#039;;\n\nDirectory created.\n\nSQL&gt;\nSQL&gt; DROP TABLE decitre_exttab_dp;\n\nTable dropped.\n\nSQL&gt;\nSQL&gt; CREATE TABLE decitre_exttab_dp\n  2  (\n  3     categorie   VARCHAR2 (50),\n  4     extrait     VARCHAR2 (4000)\n  5  )\n  6  ORGANIZATION EXTERNAL\n  7     (TYPE oracle_datapump\n  8           DEFAULT DIRECTORY D1\n  9           LOCATION (&#039;decitre_exttab.dp&#039;));\n\nTable created.\n\nSQL&gt;\nSQL&gt;   SELECT categorie, COUNT (*)\n  2      FROM decitre_exttab_dp\n  3  GROUP BY categorie;\n\nCATEGORIE                                            COUNT(*)\n-------------------------------------------------- ----------\nlitterature-sentimentale                                 7251\npolar                                                    8140\nphilo-socio                                              6141\n\nSQL&gt;\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;ensemble est ensuite divis\u00e9 en un jeu d&rsquo;apprentissage (75%) et un jeu de test (25%). A noter l&#8217;emploi de la clause SAMPLE qui permet un \u00e9chantillonnage al\u00e9atoire des donn\u00e9es ainsi que l&rsquo;ajout d&rsquo;une colonne IDENTITY qui permet de valoriser simplement une cl\u00e9 primaire:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; DROP TABLE decitre_books;\n\nTable dropped.\n\nSQL&gt;\nSQL&gt; CREATE TABLE decitre_books\n  2  AS\n  3     SELECT * FROM decitre_exttab_dp;\n\nTable created.\n\nSQL&gt;\nSQL&gt; ALTER TABLE decitre_books\n  2     ADD book# NUMBER GENERATED AS IDENTITY;\n\nTable altered.\n\nSQL&gt;\nSQL&gt; ALTER TABLE decitre_books\n  2     ADD CONSTRAINT pk_decitre_books PRIMARY KEY (book#);\n\nTable altered.\n\nSQL&gt;\nSQL&gt; DROP TABLE train_set_book# PURGE;\n\nTable dropped.\n\nSQL&gt;\nSQL&gt; CREATE TABLE train_set_book#\n  2  AS\n  3     SELECT book#\n  4       FROM decitre_books SAMPLE (75);\n\nTable created.\n\nSQL&gt;\nSQL&gt;\nSQL&gt; CREATE OR REPLACE VIEW train_set_books\n  2  AS\n  3     SELECT categorie, extrait\n  4       FROM decitre_books NATURAL JOIN train_set_book#;\n\nView created.\n\nSQL&gt;\nSQL&gt; CREATE OR REPLACE VIEW test_set_books\n  2  AS\n  3     SELECT categorie, extrait\n  4       FROM decitre_books\n  5      WHERE book# NOT IN (SELECT book#\n  6                            FROM train_set_book#);\n\nView created.\n\nSQL&gt;\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Le classifieur Bay\u00e9sien requiert la connaissance de probabilit\u00e9s \u00ab\u00a0\u00e0 priori\u00a0\u00bb &#8211; c&rsquo;est \u00e0 dire, une id\u00e9e de la fr\u00e9quence des divers groupes dans la population g\u00e9n\u00e9rale.<\/p>\n<p style=\"text-align: justify;\">Ici, on estime ces probabilit\u00e9s en mesurant la fr\u00e9quence de chaque groupe au sein de notre \u00e9chantillon d&rsquo;apprentissage:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt;   SELECT categorie,\n  2           COUNT (*),\n  3           ratio_to_report (COUNT (*)) OVER (PARTITION BY NULL) pct\n  4      FROM train_set_books\n  5  GROUP BY categorie;\n\nCATEGORIE                                            COUNT(*)        PCT\n-------------------------------------------------- ---------- ----------\npolar                                                    6107 .379222553\nlitterature-sentimentale                                 5419 .336500248\nphilo-socio                                              4578 .284277198\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Ces r\u00e9sultats vont \u00eatre stock\u00e9s dans une table (au format impos\u00e9) qui sera utilis\u00e9e ult\u00e9rieurement par Oracle Data Miner:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE TABLE BOOKS_NB_PRIORS\n  2  (\n  3     target_value        VARCHAR2 (100),\n  4     prior_probability   NUMBER\n  5  );\n\nTable created.\n\nSQL&gt;\nSQL&gt; INSERT INTO BOOKS_NB_PRIORS (target_value, prior_probability)\n  2       SELECT categorie, ratio_to_report (COUNT (*)) OVER (PARTITION BY NULL) pct\n  3         FROM train_set_books\n  4     GROUP BY categorie;\n\n3 rows created.\n\nSQL&gt;\n<\/pre>\n<h2 style=\"text-align: justify;\">Analyse\u00a0lexicale<\/h2>\n<p style=\"text-align: justify;\">L&rsquo;\u00e9tape suivante consiste \u00e0 constituer le sac de mots \u00e0 partir des extraits d&rsquo;apprentissage. Oracle Data Miner s&rsquo;appuie pour cela sur l&rsquo;<a href=\"http:\/\/www.oracle.com\/technetwork\/testcontent\/index-098492.html\" target=\"_blank\">option Oracle Text<\/a> qui offre des possibilit\u00e9s de d\u00e9coupage (tokenization) et de racinisation (stemming) linguistique:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; column comp_name format a20\nSQL&gt; column status format a15\nSQL&gt; column version format a15\nSQL&gt; \nSQL&gt; SELECT comp_name, version, status\n  2    FROM dba_registry\n  3   WHERE comp_id = &#039;CONTEXT&#039;;\n\nCOMP_NAME            VERSION         STATUS\n-------------------- --------------- ---------------\nOracle Text          12.1.0.2.0      VALID\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On va donc d\u00e9finir &#8211; en cr\u00e9ant une <a href=\"https:\/\/docs.oracle.com\/database\/121\/DMPRG\/to_dmprg781_d201.htm#DMPRG781\" target=\"_blank\">POLICY<\/a> &#8211; les propri\u00e9t\u00e9s de l&rsquo;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Lexical_analysis\" target=\"_blank\">analyse lexicale<\/a> que l&rsquo;on souhaite appliquer aux donn\u00e9es:<\/p>\n<ul>\n<li style=\"text-align: justify;\">\n<h4>Suppression des mots vides<\/h4>\n<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Les \u00ab\u00a0<a href=\"https:\/\/fr.wikipedia.org\/wiki\/Mot_vide\" target=\"_blank\">mots vides<\/a>\u00a0\u00bb sont des mots tr\u00e8s commun (comme des articles par exemple) qu&rsquo;il convient de supprimer de l&rsquo;analyse. Oracle propose une liste pr\u00e9d\u00e9finie mais celle-ci a \u00e9t\u00e9 enrichie \u00e0 partir de sources trouv\u00e9es sur internet:\u00a0<a href=\"http:\/\/www.ranks.nl\/stopwords\/french\" target=\"_blank\">http:\/\/www.ranks.nl\/stopwords\/french<\/a><\/p>\n<p style=\"text-align: justify;\">Les donn\u00e9es sont accessibles ici (au format Table Externe DataPump):\u00a0<a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2016\/06\/MOTSVIDES_EXTTAB.zip\">MOTSVIDES_EXTTAB<\/a><\/p>\n<p style=\"text-align: justify;\">On peut alors cr\u00e9e une <a href=\"https:\/\/docs.oracle.com\/database\/121\/CCREF\/cdatadic.htm#CCREF0238\" target=\"_blank\">STOPLIST<\/a> \u00e0 partir de ces mots:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE TABLE motsvides_exttab_dp\n  2  (\n  3     mot   VARCHAR2 (30)\n  4  )\n  5  ORGANIZATION EXTERNAL\n  6     (TYPE oracle_datapump\n  7           DEFAULT DIRECTORY D1\n  8           LOCATION (&#039;motsvides_exttab.dp&#039;));\n\nTable created.\n\nSQL&gt;\nSQL&gt;   SELECT mot\n  2      FROM motsvides_exttab_dp \n  3  FETCH FIRST 10 ROWS ONLY;\n\nMOT\n------------------------------\nduquel\netc\npeu\ntienne\neu\navoir\nt\nest\nfaites\nsans\n\n10 rows selected.\n\nSQL&gt;\nSQL&gt; BEGIN\n  2     ctx_ddl.create_stoplist (stoplist_name   =&gt; &#039;BOOKS_STOPLIST&#039;,\n  3                              stoplist_type   =&gt; &#039;BASIC_STOPLIST&#039;);\n  4\n  5     FOR rec IN (SELECT mot\n  6                   FROM motsvides_exttab_dp)\n  7     LOOP\n  8        ctx_ddl.add_stopword (stoplist_name   =&gt; &#039;BOOKS_STOPLIST&#039;,\n  9                              stopword        =&gt; rec.mot);\n 10     END LOOP;\n 11  END;\n 12  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;\nSQL&gt; COMMIT;\n\nCommit complete.\n\nSQL&gt;\n<\/pre>\n<ul>\n<li>\n<h4>M\u00e9canique de tokenization<\/h4>\n<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">On va d\u00e9couper le texte en mot en se servant des espaces comme s\u00e9parateurs. C&rsquo;est la m\u00e9thode par d\u00e9faut qui est employ\u00e9 par le <a href=\"https:\/\/docs.oracle.com\/database\/121\/CCREF\/cdatadic.htm#CCREF0218\" target=\"_blank\">BASIC_LEXER<\/a>.<\/p>\n<ul>\n<li style=\"text-align: justify;\">\n<h4>Racinisation<\/h4>\n<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">On va proc\u00e9der \u00e0 une racinisation des mots de mani\u00e8re associer les diff\u00e9rentes d\u00e9rivations d&rsquo;un m\u00eame terme. Par exemple, les mots \u00ab\u00a0suis\u00a0\u00bb, \u00ab\u00a0\u00e9tais\u00a0\u00bb, \u00ab\u00a0seras\u00a0\u00bb seront associ\u00e9s au verbe \u00ab\u00a0\u00eatre\u00a0\u00bb.<\/p>\n<p style=\"text-align: justify;\">Cette racinisation sera bas\u00e9e sur la langue Fran\u00e7aise.<\/p>\n<p style=\"text-align: justify;\">Elle est contr\u00f4l\u00e9e par le <a href=\"https:\/\/docs.oracle.com\/database\/121\/CCREF\/cdatadic.htm#CCREF0225\" target=\"_blank\">param\u00e8tre STEMMER de l&rsquo;attribut WORDLIST<\/a>.<\/p>\n<p style=\"text-align: justify;\">Ces divers param\u00e9trages sont f\u00e9d\u00e9r\u00e9s au sein d&rsquo;une <a href=\"https:\/\/docs.oracle.com\/database\/121\/DMPRG\/to_dmprg781_d201.htm#DMPRG781\" target=\"_blank\">POLICY <\/a>cr\u00e9\u00e9e \u00e0 l&rsquo;aide de la proc\u00e9dure <a href=\"https:\/\/docs.oracle.com\/database\/121\/CCREF\/cddlpkg.htm#CCREF2105\" target=\"_blank\">ctx_ddl.create_policy<\/a>.<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; BEGIN\n  2     ctx_ddl.create_preference (&#039;BOOKS_NB_LEXER&#039;, &#039;BASIC_LEXER&#039;);\n  3     ctx_ddl.create_preference (&#039;BOOKS_NB_WORDLIST&#039;, &#039;BASIC_WORDLIST&#039;);\n  4     ctx_ddl.set_attribute (&#039;BOOKS_NB_WORDLIST&#039;, &#039;STEMMER&#039;, &#039;FRENCH&#039;);\n  5\n  6     ctx_ddl.create_policy (policy_name   =&gt; &#039;BOOKS_NB_POLICY&#039;,\n  7                            lexer         =&gt; &#039;BOOKS_NB_LEXER&#039;,\n  8                            stoplist      =&gt; &#039;BOOKS_STOPLIST&#039;,\n  9                            wordlist      =&gt; &#039;BOOKS_NB_WORDLIST&#039;);\n 10  END;\n 11  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;\n<\/pre>\n<h2 style=\"text-align: justify;\">Cr\u00e9ation du mod\u00e8le<\/h2>\n<p style=\"text-align: justify;\">On passe ensuite \u00e0 la cr\u00e9ation du mod\u00e8le. Pour cela, on cr\u00e9\u00e9e une table de param\u00e9trage qui contient les \u00e9l\u00e9ments de configuration:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; CREATE TABLE books_nb_settings\n  2  (\n  3     setting_name    VARCHAR2 (30),\n  4     setting_value   VARCHAR2 (4000)\n  5  );\n\nTable created.\n\nSQL&gt;\nSQL&gt; BEGIN\n  2     INSERT INTO books_nb_settings\n  3             VALUES (\n  4                       DBMS_DATA_MINING.algo_name,\n  5                       DBMS_DATA_MINING.algo_naive_bayes);\n  6\n  7     INSERT INTO books_nb_settings\n  8          VALUES (DBMS_DATA_MINING.prep_auto, DBMS_DATA_MINING.prep_auto_on);\n  9\n 10     INSERT INTO books_nb_settings\n 11          VALUES (DBMS_DATA_MINING.odms_text_policy_name, &#039;BOOKS_NB_POLICY&#039;);\n 12\n 13     INSERT INTO books_nb_settings\n 14          VALUES (DBMS_DATA_MINING.CLAS_PRIORS_TABLE_NAME, &#039;BOOKS_NB_PRIORS&#039;);\n 15\n 16     COMMIT;\n 17  END;\n 18  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt; COMMIT;\n\nCommit complete.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On y sp\u00e9cifie l&rsquo;algorithme utilis\u00e9 (Bayes Na\u00eff), la table des probabilit\u00e9s \u00e0 priori (BOOKS_NB_PRIORS), le nom de la policy Oracle Text (BOOK_NB_POLICY) et on active la pr\u00e9paration automatique des donn\u00e9es (point important pour l&rsquo;application de la POLICY).<\/p>\n<p style=\"text-align: justify;\">Le mod\u00e8le est ensuite g\u00e9n\u00e9r\u00e9 en pr\u00e9cisant le recours \u00e0 une transformation afin que le champ EXTRAIT subissent une <a href=\"https:\/\/docs.oracle.com\/database\/121\/DMPRG\/to_dmprg752_d157.htm#DMPRG752\" target=\"_blank\">transformation de type TEXTE<\/a>. Au sein de cette transformation, on indique le nombre de features \u00e0 utiliser dans le mod\u00e8le. On pourrait aussi y indiquer le type de tokenization et le nom de la policy si cela n&rsquo;avait pas \u00e9t\u00e9 fait en amont (&lsquo;TEXT(POLICY_NAME:BOOKS_NB_POLICY)(TOKEN_TYPE:NORMAL)(MAX_FEATURES:1000)&rsquo;):<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; DECLARE\n  2     xformlist   DBMS_DATA_MINING_TRANSFORM.transform_list;\n  3  BEGIN\n  4     DBMS_DATA_MINING_TRANSFORM.set_transform (\n  5        xform_list           =&gt; xformlist,\n  6        attribute_name       =&gt; &#039;EXTRAIT&#039;,\n  7        attribute_subname    =&gt; NULL,\n  8        expression           =&gt; &#039;EXTRAIT&#039;,\n  9        reverse_expression   =&gt; NULL,\n 10        attribute_spec       =&gt; &#039;TEXT(MAX_FEATURES:1000)&#039;);\n 11     DBMS_DATA_MINING.create_model (\n 12        model_name            =&gt; &#039;BOOKS_NB&#039;,\n 13        mining_function       =&gt; DBMS_DATA_MINING.classification,\n 14        data_table_name       =&gt; &#039;TRAIN_SET_BOOKS&#039;,\n 15        case_id_column_name   =&gt; NULL,\n 16        target_column_name    =&gt; &#039;CATEGORIE&#039;,\n 17        settings_table_name   =&gt; &#039;BOOKS_NB_SETTINGS&#039;,\n 18        xform_list            =&gt; xformlist);\n 19  END;\n 20  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;\nSQL&gt;\n<\/pre>\n<h2 style=\"text-align: justify;\">Scoring<\/h2>\n<p style=\"text-align: justify;\">On peut alors r\u00e9aliser le scoring du mod\u00e8le sur l&rsquo;\u00e9chantillon de test. Les r\u00e9sultats sont pr\u00e9sent\u00e9s dans la matrice de confusion ci-apr\u00e8s:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; column cat_reelle format a25\nSQL&gt;   SELECT *\n  2      FROM (SELECT categorie AS cat_reelle,\n  3                   PREDICTION (BOOKS_NB USING *) AS cat_predict\n  4              FROM test_set_books)\n  5           PIVOT\n  6              (COUNT (*)\n  7              FOR cat_predict\n  8              IN (&#039;litterature-sentimentale&#039; litterature_sentimentale,\n  9                 &#039;philo-socio&#039; philo_socio,\n 10                 &#039;polar&#039; polar))\n 11  ORDER BY 1;\n\nCAT_REELLE                LITTERATURE_SENTIMENTALE PHILO_SOCIO      POLAR\n------------------------- ------------------------ ----------- ----------\nlitterature-sentimentale                      1538           6        288\nphilo-socio                                      4        1504         55\npolar                                          155          25       1853\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Le taux de r\u00e9ussite de\u00a0pr\u00e9diction du mod\u00e8le est de 90% [(1538+1504+1853)\/5428] &#8211; ce qui est tr\u00e8s bon.<\/p>\n<p style=\"text-align: justify;\">On peut encore l&rsquo;am\u00e9liorer en augmentant le nombre de features. Ici on passe de 1000 \u00e0 3000 features:<\/p>\n<pre class=\"brush: sql; ruler: true;\">SQL&gt; BEGIN\n  2     DBMS_DATA_MINING.drop_model (&#039;BOOKS_NB&#039;);\n  3  END;\n  4  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;\nSQL&gt;\nSQL&gt; DECLARE\n  2     xformlist   DBMS_DATA_MINING_TRANSFORM.transform_list;\n  3  BEGIN\n  4     DBMS_DATA_MINING_TRANSFORM.set_transform (\n  5        xform_list           =&gt; xformlist,\n  6        attribute_name       =&gt; &#039;EXTRAIT&#039;,\n  7        attribute_subname    =&gt; NULL,\n  8        expression           =&gt; &#039;EXTRAIT&#039;,\n  9        reverse_expression   =&gt; NULL,\n 10        attribute_spec       =&gt; &#039;TEXT(MAX_FEATURES:3000)&#039;);\n 11     DBMS_DATA_MINING.create_model (\n 12        model_name            =&gt; &#039;BOOKS_NB&#039;,\n 13        mining_function       =&gt; DBMS_DATA_MINING.classification,\n 14        data_table_name       =&gt; &#039;TRAIN_SET_BOOKS&#039;,\n 15        case_id_column_name   =&gt; NULL,\n 16        target_column_name    =&gt; &#039;CATEGORIE&#039;,\n 17        settings_table_name   =&gt; &#039;BOOKS_NB_SETTINGS&#039;,\n 18        xform_list            =&gt; xformlist);\n 19  END;\n 20  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;   SELECT *\n  2      FROM (SELECT categorie AS cat_reelle,\n  3                   PREDICTION (BOOKS_NB USING *) AS cat_predict\n  4              FROM test_set_books)\n  5           PIVOT\n  6              (COUNT (*)\n  7              FOR cat_predict\n  8              IN (&#039;litterature-sentimentale&#039; litterature_sentimentale,\n  9                 &#039;philo-socio&#039; philo_socio,\n 10                 &#039;polar&#039; polar))\n 11  ORDER BY 1;\n\nCAT_REELLE                LITTERATURE_SENTIMENTALE PHILO_SOCIO      POLAR\n------------------------- ------------------------ ----------- ----------\nlitterature-sentimentale                      1609           2        221\nphilo-socio                                      3        1512         48\npolar                                          134          10       1889\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Le taux de r\u00e9ussite de\u00a0pr\u00e9diction du mod\u00e8le <strong>augmente \u00e0 92.3%<\/strong> [(1609+1512+1889)\/5428].<\/p>\n<p style=\"text-align: justify;\">L&rsquo;ensemble des param\u00e8tres utilis\u00e9s par le mod\u00e8les sont accessibles via les vues:<\/p>\n<ul>\n<li style=\"text-align: justify;\">dba_mining_models\/dba_mining_model_settings\/dba_mining_model_tables\/dba_mining_model_attributes pour la partie ODM<\/li>\n<li style=\"text-align: justify;\">ctx_user_indexes\/ctx_user_index_objects\/ctx_user_index_values\/ctx_user_preferences\/ctx_user_preference_values\/ctx_user_stoplists\/ctx_user_stopwords pour la partie\u00a0d&rsquo;analyse textuelle (vues Oracle Text)<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Les r\u00e9centes campagnes concernant le maintien de la Grande Bretagne dans l&rsquo;UE ou celle des primaires aux Etats-Unis ont mis<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[3,5,7,11,19],"tags":[],"class_list":["post-626","post","type-post","status-publish","format-standard","hentry","category-classification","category-odm","category-oracle-advanced-analytics","category-probabilites","category-donnees-non-structurees"],"_links":{"self":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/626","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=626"}],"version-history":[{"count":1,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/626\/revisions"}],"predecessor-version":[{"id":1218,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/626\/revisions\/1218"}],"wp:attachment":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=626"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=626"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=626"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}