Auto-update: 2025-10-23 15:04:00

This commit is contained in:
divingeek 2025-10-23 15:04:00 +02:00
parent 7698240a79
commit 6170c48371
28 changed files with 19938 additions and 0 deletions

9
activite1/activite1.aux Normal file
View file

@ -0,0 +1,9 @@
\relax
\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo }
\@nameuse{bbl@beforestart}
\catcode `:\active
\catcode `;\active
\catcode `!\active
\catcode `?\active
\babel@aux{french}{}
\gdef \@abspage@last{4}

750
activite1/activite1.log Normal file
View file

@ -0,0 +1,750 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux) (preloaded format=pdflatex 2025.8.2) 23 OCT 2025 12:21
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**activite1.tex
(./activite1.tex
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
(/usr/share/texmf-dist/tex/latex/base/article.cls
Document Class: article 2024/06/29 v1.4n Standard LaTeX document class
(/usr/share/texmf-dist/tex/latex/base/size11.clo
File: size11.clo 2024/06/29 v1.4n Standard LaTeX file (size option)
)
\c@part=\count196
\c@section=\count197
\c@subsection=\count198
\c@subsubsection=\count199
\c@paragraph=\count266
\c@subparagraph=\count267
\c@figure=\count268
\c@table=\count269
\abovecaptionskip=\skip49
\belowcaptionskip=\skip50
\bibindent=\dimen141
)
(/usr/share/texmf-dist/tex/latex/base/inputenc.sty
Package: inputenc 2024/02/08 v1.3d Input encoding file
\inpenc@prehook=\toks17
\inpenc@posthook=\toks18
)
(/usr/share/texmf-dist/tex/latex/base/fontenc.sty
Package: fontenc 2021/04/29 v2.0v Standard LaTeX package
)
(/usr/share/texmf-dist/tex/generic/babel/babel.sty
Package: babel 2025/02/14 v25.4 The multilingual framework for pdfLaTeX, LuaLaT
eX and XeLaTeX
\babel@savecnt=\count270
\U@D=\dimen142
\l@unhyphenated=\language5
(/usr/share/texmf-dist/tex/generic/babel/txtbabel.def)
\bbl@readstream=\read2
\bbl@dirlevel=\count271
(/usr/share/texmf-dist/tex/generic/babel-french/francais.ldf
Language: francais 2024-07-25 v3.6c French support from the babel system
Package francais.ldf Warning: Option `francais' for Babel is *deprecated*,
(francais.ldf) it might be removed sooner or later. Please
(francais.ldf) use `french' instead; reported on input line 31.
(/usr/share/texmf-dist/tex/generic/babel-french/french.ldf
Language: french 2024-07-25 v3.6c French support from the babel system
Package babel Info: Hyphen rules for 'acadian' set to \l@french
(babel) (\language4). Reported on input line 91.
Package babel Info: Hyphen rules for 'canadien' set to \l@french
(babel) (\language4). Reported on input line 92.
\FB@stdchar=\count272
Package babel Info: Making : an active character on input line 421.
Package babel Info: Making ; an active character on input line 422.
Package babel Info: Making ! an active character on input line 423.
Package babel Info: Making ? an active character on input line 424.
\FBguill@level=\count273
\FBold@everypar=\toks19
\FB@Mht=\dimen143
\mc@charclass=\count274
\mc@charfam=\count275
\mc@charslot=\count276
\std@mcc=\count277
\dec@mcc=\count278
\FB@parskip=\dimen144
\listindentFB=\dimen145
\descindentFB=\dimen146
\labelindentFB=\dimen147
\labelwidthFB=\dimen148
\leftmarginFB=\dimen149
\parindentFFN=\dimen150
\FBfnindent=\dimen151
)))
(/usr/share/texmf-dist/tex/latex/carlisle/scalefnt.sty)
(/usr/share/texmf-dist/tex/latex/geometry/geometry.sty
Package: geometry 2020/01/02 v5.9 Page Geometry
(/usr/share/texmf-dist/tex/latex/graphics/keyval.sty
Package: keyval 2022/05/29 v1.15 key=value parser (DPC)
\KV@toks@=\toks20
)
(/usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead.
(/usr/share/texmf-dist/tex/generic/iftex/iftex.sty
Package: iftex 2024/12/12 v1.0g TeX engine tests
))
\Gm@cnth=\count279
\Gm@cntv=\count280
\c@Gm@tempcnt=\count281
\Gm@bindingoffset=\dimen152
\Gm@wd@mp=\dimen153
\Gm@odd@mp=\dimen154
\Gm@even@mp=\dimen155
\Gm@layoutwidth=\dimen156
\Gm@layoutheight=\dimen157
\Gm@layouthoffset=\dimen158
\Gm@layoutvoffset=\dimen159
\Gm@dimlist=\toks21
)
(/usr/share/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty
(/usr/share/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex
\pgfutil@everybye=\toks22
\pgfutil@tempdima=\dimen160
\pgfutil@tempdimb=\dimen161
)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def
\pgfutil@abb=\box52
)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex
(/usr/share/texmf-dist/tex/generic/pgf/pgf.revision.tex)
Package: pgfrcs 2023-01-15 v3.1.10 (3.1.10)
))
Package: pgf 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty
(/usr/share/texmf-dist/tex/latex/graphics/graphicx.sty
Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR)
(/usr/share/texmf-dist/tex/latex/graphics/graphics.sty
Package: graphics 2024/08/06 v1.4g Standard LaTeX Graphics (DPC,SPQR)
(/usr/share/texmf-dist/tex/latex/graphics/trig.sty
Package: trig 2023/12/02 v1.11 sin cos tan (DPC)
)
(/usr/share/texmf-dist/tex/latex/graphics-cfg/graphics.cfg
File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration
)
Package graphics Info: Driver file: pdftex.def on input line 106.
(/usr/share/texmf-dist/tex/latex/graphics-def/pdftex.def
File: pdftex.def 2024/04/13 v1.2c Graphics/color driver for pdftex
))
\Gin@req@height=\dimen162
\Gin@req@width=\dimen163
)
(/usr/share/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex
Package: pgfsys 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex
\pgfkeys@pathtoks=\toks23
\pgfkeys@temptoks=\toks24
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeyslibraryfiltered.code.te
x
\pgfkeys@tmptoks=\toks25
))
\pgf@x=\dimen164
\pgf@y=\dimen165
\pgf@xa=\dimen166
\pgf@ya=\dimen167
\pgf@xb=\dimen168
\pgf@yb=\dimen169
\pgf@xc=\dimen170
\pgf@yc=\dimen171
\pgf@xd=\dimen172
\pgf@yd=\dimen173
\w@pgf@writea=\write3
\r@pgf@reada=\read3
\c@pgf@counta=\count282
\c@pgf@countb=\count283
\c@pgf@countc=\count284
\c@pgf@countd=\count285
\t@pgf@toka=\toks26
\t@pgf@tokb=\toks27
\t@pgf@tokc=\toks28
\pgf@sys@id@count=\count286
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg
File: pgf.cfg 2023-01-15 v3.1.10 (3.1.10)
)
Driver file for pgf: pgfsys-pdftex.def
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def
File: pgfsys-pdftex.def 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def
File: pgfsys-common-pdf.def 2023-01-15 v3.1.10 (3.1.10)
)))
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex
File: pgfsyssoftpath.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfsyssoftpath@smallbuffer@items=\count287
\pgfsyssoftpath@bigbuffer@items=\count288
)
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex
File: pgfsysprotocol.code.tex 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/latex/xcolor/xcolor.sty
Package: xcolor 2024/09/29 v3.02 LaTeX color extensions (UK)
(/usr/share/texmf-dist/tex/latex/graphics-cfg/color.cfg
File: color.cfg 2016/01/02 v1.6 sample color configuration
)
Package xcolor Info: Driver file: pdftex.def on input line 274.
(/usr/share/texmf-dist/tex/latex/graphics/mathcolor.ltx)
Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1349.
Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1353.
Package xcolor Info: Model `RGB' extended on input line 1365.
Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1367.
Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1368.
Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1369.
Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1370.
Package xcolor Info: Model `Gray' substituted by `gray' on input line 1371.
Package xcolor Info: Model `wave' substituted by `hsb' on input line 1372.
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex
Package: pgfcore 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex
\pgfmath@dimen=\dimen174
\pgfmath@count=\count289
\pgfmath@box=\box53
\pgfmath@toks=\toks29
\pgfmath@stack@operand=\toks30
\pgfmath@stack@operation=\toks31
)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonometric.code
.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison.code.te
x) (/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerarithmetics
.code.tex) (/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex
\c@pgfmathroundto@lastzeros=\count290
))
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfint.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex
File: pgfcorepoints.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@picminx=\dimen175
\pgf@picmaxx=\dimen176
\pgf@picminy=\dimen177
\pgf@picmaxy=\dimen178
\pgf@pathminx=\dimen179
\pgf@pathmaxx=\dimen180
\pgf@pathminy=\dimen181
\pgf@pathmaxy=\dimen182
\pgf@xx=\dimen183
\pgf@xy=\dimen184
\pgf@yx=\dimen185
\pgf@yy=\dimen186
\pgf@zx=\dimen187
\pgf@zy=\dimen188
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.code.tex
File: pgfcorepathconstruct.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@path@lastx=\dimen189
\pgf@path@lasty=\dimen190
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
File: pgfcorepathusage.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@shorten@end@additional=\dimen191
\pgf@shorten@start@additional=\dimen192
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex
File: pgfcorescopes.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfpic=\box54
\pgf@hbox=\box55
\pgf@layerbox@main=\box56
\pgf@picture@serial@count=\count291
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex
File: pgfcoregraphicstate.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgflinewidth=\dimen193
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformations.code.t
ex
File: pgfcoretransformations.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@pt@x=\dimen194
\pgf@pt@y=\dimen195
\pgf@pt@temp=\dimen196
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex
File: pgfcorequick.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex
File: pgfcoreobjects.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.te
x
File: pgfcorepathprocessing.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex
File: pgfcorearrows.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfarrowsep=\dimen197
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex
File: pgfcoreshade.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@max=\dimen198
\pgf@sys@shading@range@num=\count292
\pgf@shadingcount=\count293
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex
File: pgfcoreimage.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex
File: pgfcoreexternal.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfexternal@startupbox=\box57
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex
File: pgfcorelayers.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.code.tex
File: pgfcoretransparency.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.tex
File: pgfcorepatterns.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.tex
File: pgfcorerdf.code.tex 2023-01-15 v3.1.10 (3.1.10)
)))
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex
File: pgfmoduleshapes.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfnodeparttextbox=\box58
)
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex
File: pgfmoduleplot.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty
Package: pgfcomp-version-0-65 2023-01-15 v3.1.10 (3.1.10)
\pgf@nodesepstart=\dimen199
\pgf@nodesepend=\dimen256
)
(/usr/share/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty
Package: pgfcomp-version-1-18 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgffor.sty
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex))
(/usr/share/texmf-dist/tex/latex/pgf/math/pgfmath.sty
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex))
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex
Package: pgffor 2023-01-15 v3.1.10 (3.1.10)
\pgffor@iter=\dimen257
\pgffor@skip=\dimen258
\pgffor@stack=\toks32
\pgffor@toks=\toks33
))
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex
Package: tikz 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.te
x
File: pgflibraryplothandlers.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@plot@mark@count=\count294
\pgfplotmarksize=\dimen259
)
\tikz@lastx=\dimen260
\tikz@lasty=\dimen261
\tikz@lastxsaved=\dimen262
\tikz@lastysaved=\dimen263
\tikz@lastmovetox=\dimen264
\tikz@lastmovetoy=\dimen265
\tikzleveldistance=\dimen266
\tikzsiblingdistance=\dimen267
\tikz@figbox=\box59
\tikz@figbox@bg=\box60
\tikz@tempbox=\box61
\tikz@tempbox@bg=\box62
\tikztreelevel=\count295
\tikznumberofchildren=\count296
\tikznumberofcurrentchild=\count297
\tikz@fig@count=\count298
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex
File: pgfmodulematrix.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfmatrixcurrentrow=\count299
\pgfmatrixcurrentcolumn=\count300
\pgf@matrix@numberofcolumns=\count301
)
\tikz@expandcount=\count302
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
topaths.code.tex
File: tikzlibrarytopaths.code.tex 2023-01-15 v3.1.10 (3.1.10)
))) (/usr/share/texmf-dist/tex/latex/amsmath/amsmath.sty
Package: amsmath 2024/11/05 v2.17t AMS math features
\@mathmargin=\skip51
For additional information on amsmath, use the `?' option.
(/usr/share/texmf-dist/tex/latex/amsmath/amstext.sty
Package: amstext 2021/08/26 v2.01 AMS text
(/usr/share/texmf-dist/tex/latex/amsmath/amsgen.sty
File: amsgen.sty 1999/11/30 v2.0 generic functions
\@emptytoks=\toks34
\ex@=\dimen268
))
(/usr/share/texmf-dist/tex/latex/amsmath/amsbsy.sty
Package: amsbsy 1999/11/29 v1.2d Bold Symbols
\pmbraise@=\dimen269
)
(/usr/share/texmf-dist/tex/latex/amsmath/amsopn.sty
Package: amsopn 2022/04/08 v2.04 operator names
)
\inf@bad=\count303
LaTeX Info: Redefining \frac on input line 233.
\uproot@=\count304
\leftroot@=\count305
LaTeX Info: Redefining \overline on input line 398.
LaTeX Info: Redefining \colon on input line 409.
\classnum@=\count306
\DOTSCASE@=\count307
LaTeX Info: Redefining \ldots on input line 495.
LaTeX Info: Redefining \dots on input line 498.
LaTeX Info: Redefining \cdots on input line 619.
\Mathstrutbox@=\box63
\strutbox@=\box64
LaTeX Info: Redefining \big on input line 721.
LaTeX Info: Redefining \Big on input line 722.
LaTeX Info: Redefining \bigg on input line 723.
LaTeX Info: Redefining \Bigg on input line 724.
\big@size=\dimen270
LaTeX Font Info: Redeclaring font encoding OML on input line 742.
LaTeX Font Info: Redeclaring font encoding OMS on input line 743.
\macc@depth=\count308
LaTeX Info: Redefining \bmod on input line 904.
LaTeX Info: Redefining \pmod on input line 909.
LaTeX Info: Redefining \smash on input line 939.
LaTeX Info: Redefining \relbar on input line 969.
LaTeX Info: Redefining \Relbar on input line 970.
\c@MaxMatrixCols=\count309
\dotsspace@=\muskip17
\c@parentequation=\count310
\dspbrk@lvl=\count311
\tag@help=\toks35
\row@=\count312
\column@=\count313
\maxfields@=\count314
\andhelp@=\toks36
\eqnshift@=\dimen271
\alignsep@=\dimen272
\tagshift@=\dimen273
\tagwidth@=\dimen274
\totwidth@=\dimen275
\lineht@=\dimen276
\@envbody=\toks37
\multlinegap=\skip52
\multlinetaggap=\skip53
\mathdisplay@stack=\toks38
LaTeX Info: Redefining \[ on input line 2953.
LaTeX Info: Redefining \] on input line 2954.
)
(/usr/share/texmf-dist/tex/latex/amsfonts/amssymb.sty
Package: amssymb 2013/01/14 v3.01 AMS font symbols
(/usr/share/texmf-dist/tex/latex/amsfonts/amsfonts.sty
Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support
\symAMSa=\mathgroup4
\symAMSb=\mathgroup5
LaTeX Font Info: Redeclaring math symbol \hbar on input line 98.
LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold'
(Font) U/euf/m/n --> U/euf/b/n on input line 106.
))
(/usr/share/texmf-dist/tex/latex/enumitem/enumitem.sty
Package: enumitem 2025/02/06 v3.11 Customized lists
\labelindent=\skip54
\enit@outerparindent=\dimen277
\enit@toks=\toks39
\enit@inbox=\box65
\enit@count@id=\count315
\enitdp@description=\count316
)
(/usr/share/texmf-dist/tex/latex/tcolorbox/tcolorbox.sty
Package: tcolorbox 2024/10/22 version 6.4.1 text color boxes
(/usr/share/texmf-dist/tex/latex/tools/verbatim.sty
Package: verbatim 2024-01-22 v1.5x LaTeX2e package for verbatim enhancements
\every@verbatim=\toks40
\verbatim@line=\toks41
\verbatim@in@stream=\read4
)
(/usr/share/texmf-dist/tex/latex/environ/environ.sty
Package: environ 2014/05/04 v0.3 A new way to define environments
(/usr/share/texmf-dist/tex/latex/trimspaces/trimspaces.sty
Package: trimspaces 2009/09/17 v1.1 Trim spaces around a token list
))
(/usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
Package: etoolbox 2025/02/11 v2.5l e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count317
)
\tcb@titlebox=\box66
\tcb@upperbox=\box67
\tcb@lowerbox=\box68
\tcb@phantombox=\box69
\c@tcbbreakpart=\count318
\c@tcblayer=\count319
\c@tcolorbox@number=\count320
\l__tcobox_tmpa_box=\box70
\l__tcobox_tmpa_dim=\dimen278
\tcb@temp=\box71
\tcb@temp=\box72
\tcb@temp=\box73
\tcb@temp=\box74
)
(/usr/share/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty
Package: fancyhdr 2025/02/07 v5.2 Extensive control of page headers and footers
\f@nch@headwidth=\skip55
\f@nch@offset@elh=\skip56
\f@nch@offset@erh=\skip57
\f@nch@offset@olh=\skip58
\f@nch@offset@orh=\skip59
\f@nch@offset@elf=\skip60
\f@nch@offset@erf=\skip61
\f@nch@offset@olf=\skip62
\f@nch@offset@orf=\skip63
\f@nch@height=\skip64
\f@nch@footalignment=\skip65
\f@nch@widthL=\skip66
\f@nch@widthC=\skip67
\f@nch@widthR=\skip68
\@temptokenb=\toks42
)
(/usr/share/texmf-dist/tex/latex/tools/multicol.sty
Package: multicol 2024/09/14 v1.9i multicolumn formatting (FMi)
\c@tracingmulticols=\count321
\mult@box=\box75
\multicol@leftmargin=\dimen279
\c@unbalance=\count322
\c@collectmore=\count323
\doublecol@number=\count324
\multicoltolerance=\count325
\multicolpretolerance=\count326
\full@width=\dimen280
\page@free=\dimen281
\premulticols=\dimen282
\postmulticols=\dimen283
\multicolsep=\skip69
\multicolbaselineskip=\skip70
\partial@page=\box76
\last@line=\box77
\mc@boxedresult=\box78
\maxbalancingoverflow=\dimen284
\mult@rightbox=\box79
\mult@grightbox=\box80
\mult@firstbox=\box81
\mult@gfirstbox=\box82
\@tempa=\box83
\@tempa=\box84
\@tempa=\box85
\@tempa=\box86
\@tempa=\box87
\@tempa=\box88
\@tempa=\box89
\@tempa=\box90
\@tempa=\box91
\@tempa=\box92
\@tempa=\box93
\@tempa=\box94
\@tempa=\box95
\@tempa=\box96
\@tempa=\box97
\@tempa=\box98
\@tempa=\box99
\@tempa=\box100
\@tempa=\box101
\@tempa=\box102
\@tempa=\box103
\@tempa=\box104
\@tempa=\box105
\@tempa=\box106
\@tempa=\box107
\@tempa=\box108
\@tempa=\box109
\@tempa=\box110
\@tempa=\box111
\@tempa=\box112
\@tempa=\box113
\@tempa=\box114
\@tempa=\box115
\@tempa=\box116
\@tempa=\box117
\@tempa=\box118
\c@minrows=\count327
\c@columnbadness=\count328
\c@finalcolumnbadness=\count329
\last@try=\dimen285
\multicolovershoot=\dimen286
\multicolundershoot=\dimen287
\mult@nat@firstbox=\box119
\colbreak@box=\box120
\mc@col@check@num=\count330
)
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
shapes.geometric.code.tex
File: tikzlibraryshapes.geometric.code.tex 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/libraries/shapes/pgflibraryshapes.geomet
ric.code.tex
File: pgflibraryshapes.geometric.code.tex 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
calc.code.tex
File: tikzlibrarycalc.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
File: l3backend-pdftex.def 2024-05-08 L3 backend support: PDF output (pdfTeX)
\l__color_backend_stack_int=\count331
\l__pdf_internal_box=\box121
) (./activite1.aux
(/usr/share/texmf-dist/tex/generic/babel/locale/fr/babel-french.tex
Package babel Info: Importing font and identification data for french
(babel) from babel-fr.ini. Reported on input line 11.
))
\openout1 = `activite1.aux'.
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 33.
LaTeX Font Info: ... okay on input line 33.
LaTeX Info: Redefining \degres on input line 33.
Package french.ldf Info: Setting StandardItemizeEnv=true for
(french.ldf) compatibility with enumitem package,
(french.ldf) reported on input line 33.
Package french.ldf Info: Setting StandardEnumerateEnv=true for
(french.ldf) compatibility with enumitem package,
(french.ldf) reported on input line 33.
LaTeX Info: Redefining \up on input line 33.
*geometry* driver: auto-detecting
*geometry* detected driver: pdftex
*geometry* verbose mode - [ preamble ] result:
* driver: pdftex
* paper: a4paper
* layout: <same size as paper>
* layoutoffset:(h,v)=(0.0pt,0.0pt)
* modes:
* h-part:(L,W,R)=(56.9055pt, 483.69687pt, 56.9055pt)
* v-part:(T,H,B)=(56.9055pt, 731.23584pt, 56.9055pt)
* \paperwidth=597.50787pt
* \paperheight=845.04684pt
* \textwidth=483.69687pt
* \textheight=731.23584pt
* \oddsidemargin=-15.36449pt
* \evensidemargin=-15.36449pt
* \topmargin=-52.36449pt
* \headheight=12.0pt
* \headsep=25.0pt
* \topskip=11.0pt
* \footskip=30.0pt
* \marginparwidth=50.0pt
* \marginparsep=10.0pt
* \columnsep=10.0pt
* \skip\footins=10.0pt plus 4.0pt minus 2.0pt
* \hoffset=0.0pt
* \voffset=0.0pt
* \mag=1000
* \@twocolumnfalse
* \@twosidefalse
* \@mparswitchfalse
* \@reversemarginfalse
* (1in=72.27pt=25.4mm, 1cm=28.453pt)
(/usr/share/texmf-dist/tex/context/base/mkii/supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
\scratchcounter=\count332
\scratchdimen=\dimen288
\scratchbox=\box122
\nofMPsegments=\count333
\nofMParguments=\count334
\everyMPshowfont=\toks43
\MPscratchCnt=\count335
\MPscratchDim=\dimen289
\MPnumerator=\count336
\makeMPintoPDFobject=\count337
\everyMPtoPDFconversion=\toks44
) (/usr/share/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty
Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf
Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4
85.
(/usr/share/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
e
))
LaTeX Font Info: Trying to load font information for U+msa on input line 59.
(/usr/share/texmf-dist/tex/latex/amsfonts/umsa.fd
File: umsa.fd 2013/01/14 v3.01 AMS symbols A
)
LaTeX Font Info: Trying to load font information for U+msb on input line 59.
(/usr/share/texmf-dist/tex/latex/amsfonts/umsb.fd
File: umsb.fd 2013/01/14 v3.01 AMS symbols B
)
[1
{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}{/usr/share/texmf-dist/fonts
/enc/dvips/cm-super/cm-super-t1.enc}]
[2]
[3]
[4] (./activite1.aux)
***********
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
***********
)
Here is how much of TeX's memory you used:
19631 strings out of 475142
396084 string characters out of 5765947
784639 words of memory out of 5000000
42341 multiletter control sequences out of 15000+600000
571118 words of font info for 64 fonts, out of 8000000 for 9000
14 hyphenation exceptions out of 8191
102i,11n,107p,410b,737s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/
texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texmf-dist/font
s/type1/public/amsfonts/cm/cmsy10.pfb></usr/share/texmf-dist/fonts/type1/public
/amsfonts/symbols/msam10.pfb></usr/share/texmf-dist/fonts/type1/public/cm-super
/sfbx1095.pfb></usr/share/texmf-dist/fonts/type1/public/cm-super/sfbx1200.pfb><
/usr/share/texmf-dist/fonts/type1/public/cm-super/sfbx1440.pfb></usr/share/texm
f-dist/fonts/type1/public/cm-super/sfbx2488.pfb></usr/share/texmf-dist/fonts/ty
pe1/public/cm-super/sfrm1000.pfb></usr/share/texmf-dist/fonts/type1/public/cm-s
uper/sfrm1095.pfb></usr/share/texmf-dist/fonts/type1/public/cm-super/sfti1095.p
fb>
Output written on activite1.pdf (4 pages, 182024 bytes).
PDF statistics:
76 PDF objects out of 1000 (max. 8388607)
47 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
13 words of extra memory for PDF output out of 10000 (max. 10000000)

BIN
activite1/activite1.pdf Normal file

Binary file not shown.

Binary file not shown.

301
activite1/activite1.tex Normal file
View file

@ -0,0 +1,301 @@
\documentclass[a4paper,11pt]{article}
% Packages
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[francais]{babel}
\usepackage{geometry}
\usepackage{tikz}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{enumitem}
\usepackage{xcolor}
\usepackage{tcolorbox}
\usepackage{fancyhdr}
\usepackage{multicol}
% Configuration de la page
\geometry{margin=2cm}
\pagestyle{fancy}
\fancyhf{}
\fancyfoot[C]{Page \thepage/4 -- Activité k-NN}
\renewcommand{\headrulewidth}{0pt}
% Couleurs personnalisées
\definecolor{classA}{RGB}{231,76,60}
\definecolor{classB}{RGB}{52,152,219}
\definecolor{lightblue}{RGB}{227,242,253}
\definecolor{lightyellow}{RGB}{255,243,205}
% Configuration TikZ
\usetikzlibrary{shapes.geometric,calc}
\begin{document}
% ============= PAGE 1 =============
\begin{center}
{\Huge \textbf{Activité débranchée : k-NN}}\\[0.3cm]
{\Large \textbf{Les k Plus Proches Voisins}}
\end{center}
\vspace{0.5cm}
\textbf{Objectif :} Comprendre comment l'algorithme k-NN classifie un nouveau point en utilisant la proximité avec les points d'apprentissage.
\vspace{0.3cm}
\begin{tcolorbox}[colback=lightblue,colframe=blue!75!black,title=\textbf{Principe}]
\begin{itemize}[leftmargin=*]
\item On dispose d'un ensemble de points déjà classifiés (points d'apprentissage)
\item Pour classifier un nouveau point, on cherche ses \textit{k} plus proches voisins
\item La classe majoritaire parmi ces \textit{k} voisins devient la classe du nouveau point
\end{itemize}
\end{tcolorbox}
\vspace{0.5cm}
\section*{Exercice 1 : Classification avec k = 3}
Voici un ensemble de points sur un plan. Les cercles rouges (\textcolor{classA}{$\bullet$}) sont de classe A, les carrés bleus (\textcolor{classB}{$\blacksquare$}) sont de classe B. Le point noir ($\star$) est à classifier.
\vspace{0.3cm}
\begin{center}
\begin{tikzpicture}[scale=1.2]
% Grille
\draw[gray!30, step=1] (0,0) grid (8,8);
% Axes et cadre
\draw[thick] (0,0) rectangle (8,8);
% Points de classe A (cercles rouges)
\foreach \point in {(1,7), (1.5,6), (2,7.5), (2.5,6.5), (1.5,5), (2.5,5.5), (3,7)} {
\fill[classA] \point circle (0.15);
}
% Points de classe B (carrés bleus)
\fill[classB] (5,2) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]5,2) rectangle ++(0.24,0.24);
\fill[classB] (5.5,3) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]5.5,3) rectangle ++(0.24,0.24);
\fill[classB] (6,1.5) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]6,1.5) rectangle ++(0.24,0.24);
\fill[classB] (6.5,2.5) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]6.5,2.5) rectangle ++(0.24,0.24);
\fill[classB] (5.5,1) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]5.5,1) rectangle ++(0.24,0.24);
\fill[classB] (7,2) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]7,2) rectangle ++(0.24,0.24);
\fill[classB] (6.5,3.5) circle (0.15);
\fill[classB] ([shift={(-0.12,-0.12)}]6.5,3.5) rectangle ++(0.24,0.24);
% Point à classifier (étoile noire)
\node[star,star points=5,star point ratio=2.5,fill=black,draw=black,thick,minimum size=0.6cm] at (4,4.5) {};
\end{tikzpicture}
\vspace{0.3cm}
% Légende
\begin{tabular}{ccccc}
\textcolor{classA}{$\bullet$} Classe A & \quad &
\textcolor{classB}{$\blacksquare$} Classe B & \quad &
$\star$ À classifier
\end{tabular}
\end{center}
\vspace{0.5cm}
\subsection*{Questions :}
\begin{enumerate}
\item Identifiez les 3 points les plus proches du point noir $\star$. Tracez les distances sur le graphique ci-dessus.
\vspace{0.3cm}
Distances : \underline{\hspace{3cm}} \underline{\hspace{3cm}} \underline{\hspace{3cm}}
\vspace{0.3cm}
\item Parmi ces 3 points, combien sont de classe A ? \underline{\hspace{1.5cm}} De classe B ? \underline{\hspace{1.5cm}}
\vspace{0.3cm}
\item À quelle classe appartient donc le point noir avec $k = 3$ ? \underline{\hspace{3cm}}
\end{enumerate}
% ============= PAGE 2 =============
%\newpage
\section*{Exercice 2 : Influence du paramètre k}
Reprenez le même graphique que l'exercice 1.
\vspace{0.5cm}
\subsection*{a) Avec k = 1 (1 seul voisin)}
\begin{itemize}
\item Quel est le point le plus proche ? \underline{\hspace{5cm}}
\item Classification du point noir : \underline{\hspace{5cm}}
\end{itemize}
\vspace{0.5cm}
\subsection*{b) Avec k = 5 (5 voisins)}
\begin{itemize}
\item Listez les 5 points les plus proches : \underline{\hspace{7cm}}
\vspace{0.2cm}
\underline{\hspace{10cm}}
\item Nombre de classe A : \underline{\hspace{2cm}} \quad Nombre de classe B : \underline{\hspace{2cm}}
\item Classification du point noir : \underline{\hspace{5cm}}
\end{itemize}
\vspace{0.5cm}
\subsection*{c) Avec k = 7 (tous les voisins de chaque classe)}
\begin{itemize}
\item Nombre de classe A : \underline{\hspace{2cm}} \quad Nombre de classe B : \underline{\hspace{2cm}}
\item Classification du point noir : \underline{\hspace{5cm}}
\end{itemize}
\vspace{0.8cm}
\begin{tcolorbox}[colback=lightyellow,colframe=orange!75!black,title=\textbf{Réflexion}]
\textbf{1. La classification change-t-elle selon la valeur de k ? Pourquoi ?}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\vspace{0.5cm}
\textbf{2. Que se passe-t-il si k est trop petit (k = 1) ?}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\vspace{0.5cm}
\textbf{3. Que se passe-t-il si k est trop grand (k = nombre total de points) ?}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\end{tcolorbox}
% ============= PAGE 3 =============
\newpage
\section*{Exercice 3 : À vous de jouer !}
Créez votre propre situation de classification avec $k = 3$.
\vspace{0.5cm}
\begin{center}
\begin{tikzpicture}[scale=1.3]
% Grille fine
\draw[gray!20, step=1] (0,0) grid (12,12);
% Axes et cadre
\draw[very thick] (0,0) rectangle (12,12);
% Graduations
\foreach \x in {0,2,4,6,8,10,12} {
\node[below] at (\x,-0.2) {\small \x};
}
\foreach \y in {0,2,4,6,8,10,12} {
\node[left] at (-0.2,\y) {\small \y};
}
\end{tikzpicture}
\end{center}
\vspace{0.5cm}
\begin{tcolorbox}[colback=lightblue,colframe=blue!75!black,title=\textbf{Instructions}]
\begin{itemize}
\item Placez au moins 10 points : 5 cercles rouges (classe A) et 5 carrés bleus (classe B)
\item Placez une étoile noire (point à classifier)
\item Tracez les 3 distances les plus courtes
\item Déterminez la classe du point noir
\end{itemize}
\end{tcolorbox}
\vspace{0.5cm}
\textbf{Classification finale :} \underline{\hspace{5cm}}
% ============= PAGE 4 =============
\newpage
\section*{Pour aller plus loin}
\subsection*{Applications réelles de k-NN}
\begin{itemize}
\item Reconnaissance d'écriture manuscrite
\item Systèmes de recommandation (films, musique, produits)
\item Diagnostic médical (classification de maladies)
\item Détection de spam dans les emails
\item Reconnaissance faciale
\item Prévision météorologique
\end{itemize}
\vspace{0.5cm}
\subsection*{Questions de réflexion}
\textbf{1. Avantages de k-NN :}
\begin{itemize}
\item Simple à comprendre et à implémenter
\item Pas besoin d'entraînement complexe
\item Fonctionne bien pour des frontières non linéaires
\end{itemize}
\vspace{0.3cm}
\textbf{2. Limitations de k-NN :}
\begin{itemize}
\item Lent avec beaucoup de données (doit calculer toutes les distances)
\item Sensible aux données aberrantes
\item Nécessite de choisir la bonne valeur de $k$
\item Ne fonctionne pas bien si les classes sont déséquilibrées
\end{itemize}
\vspace{0.3cm}
\textbf{3. Comment choisir k ?}
\begin{itemize}
\item $k$ trop petit ($k=1$) : sensible au bruit, risque de sur-apprentissage
\item $k$ trop grand : perd les détails, risque de sous-apprentissage
\item Conseil : tester plusieurs valeurs et choisir celle qui donne les meilleurs résultats
\item Souvent, $k$ impair pour éviter les égalités ($k = 3, 5, 7...$)
\end{itemize}
\vspace{0.5cm}
\begin{tcolorbox}[colback=lightyellow,colframe=orange!75!black,title=\textbf{Défi bonus}]
Imaginez une situation où k-NN pourrait donner un mauvais résultat. Dessinez cette situation sur une feuille séparée et expliquez pourquoi.
\vspace{0.5cm}
\textit{Indices : Pensez aux données bruitées, aux classes déséquilibrées, ou aux points isolés...}
\end{tcolorbox}
\end{document}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,693 @@
"""
Script pour générer une page HTML interactive avec les données des villages corses embarquées.
Usage: python generate_interactive_map.py villages_corse.csv
"""
import csv
import json
import sys
def parse_coordinates(point_geo_str):
"""Parse la colonne Point_Geo"""
try:
parts = point_geo_str.split(',')
lat = float(parts[0].strip())
lon = float(parts[1].strip())
return lat, lon
except:
return None, None
def load_villages_from_csv(csv_file):
"""Charge les villages depuis le CSV"""
villages = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.reader(f, delimiter=';')
next(reader) # Skip header
for row in reader:
if len(row) >= 18:
lat, lon = parse_coordinates(row[17])
if lat and lon:
villages.append({
'name': row[0],
'nameCorse': row[1],
'lat': lat,
'lon': lon,
'dept': row[9],
'altitude': float(row[15]) if row[15] else 0
})
return villages
def generate_html(villages, output_file='knn_interactive_full.html'):
"""Génère le fichier HTML avec les données embarquées"""
villages_json = json.dumps(villages, ensure_ascii=False)
html_content = f'''<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Classification k-NN Interactive - Corse</title>
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
* {{
margin: 0;
padding: 0;
box-sizing: border-box;
}}
body {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}}
.container {{
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}}
.header {{
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}}
.header h1 {{
font-size: 2.5em;
margin-bottom: 10px;
}}
.header p {{
font-size: 1.2em;
opacity: 0.9;
}}
.main-content {{
display: grid;
grid-template-columns: 350px 1fr;
gap: 0;
}}
.sidebar {{
background: #f5f5f5;
padding: 30px;
border-right: 2px solid #ddd;
max-height: 900px;
overflow-y: auto;
}}
.controls {{
background: white;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}}
.controls h3 {{
margin-bottom: 15px;
color: #333;
font-size: 1.2em;
}}
.control-group {{
margin-bottom: 20px;
}}
.control-group label {{
display: block;
font-weight: bold;
color: #555;
margin-bottom: 8px;
}}
.slider-container {{
display: flex;
align-items: center;
gap: 10px;
}}
input[type="range"] {{
flex: 1;
height: 8px;
border-radius: 5px;
background: #ddd;
outline: none;
}}
input[type="range"]::-webkit-slider-thumb {{
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
}}
input[type="range"]::-moz-range-thumb {{
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
border: none;
}}
.k-value {{
background: #667eea;
color: white;
padding: 5px 15px;
border-radius: 20px;
font-weight: bold;
min-width: 40px;
text-align: center;
}}
.result-box {{
background: white;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}}
.result-box h3 {{
margin-bottom: 15px;
color: #333;
}}
.prediction {{
font-size: 1.3em;
font-weight: bold;
padding: 15px;
border-radius: 8px;
text-align: center;
margin-bottom: 15px;
}}
.prediction.corse-sud {{
background: #ffebee;
color: #c62828;
}}
.prediction.haute-corse {{
background: #e3f2fd;
color: #1565c0;
}}
.prediction.no-result {{
background: #f5f5f5;
color: #666;
}}
.coords {{
font-size: 0.9em;
color: #666;
text-align: center;
margin-bottom: 10px;
}}
.votes {{
display: flex;
justify-content: space-around;
margin-bottom: 15px;
}}
.vote-item {{
text-align: center;
}}
.vote-count {{
font-size: 2em;
font-weight: bold;
}}
.vote-count.red {{
color: #c62828;
}}
.vote-count.blue {{
color: #1565c0;
}}
.neighbors-list {{
max-height: 300px;
overflow-y: auto;
background: #fafafa;
padding: 10px;
border-radius: 5px;
}}
.neighbor-item {{
padding: 10px;
margin-bottom: 8px;
background: white;
border-radius: 5px;
border-left: 4px solid #ddd;
}}
.neighbor-item.dept-2a {{
border-left-color: #c62828;
}}
.neighbor-item.dept-2b {{
border-left-color: #1565c0;
}}
.neighbor-name {{
font-weight: bold;
margin-bottom: 3px;
}}
.neighbor-corse {{
font-style: italic;
color: #666;
font-size: 0.9em;
}}
.neighbor-distance {{
font-size: 0.9em;
color: #666;
}}
.instructions {{
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}}
.instructions h4 {{
margin-bottom: 10px;
color: #856404;
}}
.instructions ul {{
margin-left: 20px;
color: #856404;
}}
.instructions li {{
margin-bottom: 5px;
}}
.legend {{
background: white;
padding: 15px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}}
.legend h4 {{
margin-bottom: 10px;
color: #333;
}}
.legend-item {{
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}}
.legend-circle {{
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #333;
}}
.legend-circle.red {{
background: #e74c3c;
}}
.legend-circle.blue {{
background: #3498db;
}}
.legend-circle.marker {{
background: #95a5a6;
border: 3px solid #000;
}}
#map {{
height: 900px;
cursor: crosshair;
}}
.leaflet-popup-content {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}}
button {{
padding: 10px 20px;
border: none;
border-radius: 5px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
width: 100%;
margin-bottom: 10px;
}}
button:hover {{
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}}
.btn-reset {{
background: #f44336;
color: white;
}}
.btn-random {{
background: #4CAF50;
color: white;
}}
.stats {{
background: #e3f2fd;
padding: 10px;
border-radius: 5px;
font-size: 0.9em;
text-align: center;
margin-top: 15px;
color: #1565c0;
}}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🗺 Classification k-NN Interactive</h1>
<p>Haute-Corse ou Corse du Sud ?</p>
<div class="stats">
<strong>{len(villages)}</strong> villages chargés
</div>
</div>
<div class="main-content">
<div class="sidebar">
<div class="instructions">
<h4>📋 Instructions</h4>
<ul>
<li><strong>Cliquez</strong> n'importe où sur la carte</li>
<li>Ajustez la valeur de <strong>k</strong> avec le curseur</li>
<li>Observez les <strong>k plus proches villages</strong></li>
<li>La <strong>classification</strong> se fait par vote majoritaire</li>
</ul>
</div>
<div class="controls">
<h3> Paramètres</h3>
<div class="control-group">
<label>Nombre de voisins (k) :</label>
<div class="slider-container">
<input type="range" id="kSlider" min="1" max="21" value="5" step="2">
<span class="k-value" id="kValue">5</span>
</div>
</div>
<button class="btn-random" onclick="placeRandomPoint()">🎲 Point Aléatoire</button>
<button class="btn-reset" onclick="resetClassification()">🔄 Réinitialiser</button>
</div>
<div class="result-box" id="resultBox">
<h3>🎯 Résultat</h3>
<div class="prediction no-result" id="prediction">
Cliquez sur la carte
</div>
<div class="coords" id="coords"></div>
<div id="votesContainer" style="display: none;">
<div class="votes">
<div class="vote-item">
<div class="vote-count red" id="votes2A">0</div>
<div>Corse du Sud</div>
</div>
<div class="vote-item">
<div class="vote-count blue" id="votes2B">0</div>
<div>Haute-Corse</div>
</div>
</div>
<h4>🏘 Plus proches voisins :</h4>
<div class="neighbors-list" id="neighborsList"></div>
</div>
</div>
<div class="legend">
<h4>Légende</h4>
<div class="legend-item">
<div class="legend-circle red"></div>
<span>Corse du Sud (2A)</span>
</div>
<div class="legend-item">
<div class="legend-circle blue"></div>
<span>Haute-Corse (2B)</span>
</div>
<div class="legend-item">
<div class="legend-circle marker"></div>
<span>Point à classifier</span>
</div>
</div>
</div>
<div id="map"></div>
</div>
</div>
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// Données des villages (embarquées depuis le CSV)
const villages = {villages_json};
let map, testMarker, neighborMarkers = [], neighborLines = [];
let currentK = 5;
// Initialiser la carte
function initMap() {{
map = L.map('map').setView([42.15, 9.05], 9);
L.tileLayer('https://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png', {{
attribution: '© OpenStreetMap contributors'
}}).addTo(map);
// Ajouter tous les villages
villages.forEach(village => {{
const color = village.dept === '2A' ? '#e74c3c' : '#3498db';
L.circleMarker([village.lat, village.lon], {{
radius: 3,
fillColor: color,
color: '#333',
weight: 1,
opacity: 1,
fillOpacity: 0.5
}}).bindPopup(`<b>${{village.name}}</b><br>${{village.nameCorse}}<br>${{village.dept}}`)
.addTo(map);
}});
// Ajouter le gestionnaire de clic
map.on('click', onMapClick);
}}
// Calcul de distance Haversine
function haversineDistance(lat1, lon1, lat2, lon2) {{
const R = 6371; // Rayon de la Terre en km
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}}
// Classification k-NN
function knnClassify(lat, lon, k) {{
// Calculer distances
const distances = villages.map(village => ({{
...village,
distance: haversineDistance(lat, lon, village.lat, village.lon)
}}));
// Trier par distance
distances.sort((a, b) => a.distance - b.distance);
// Prendre les k plus proches
const neighbors = distances.slice(0, k);
// Voter
const votes = {{ '2A': 0, '2B': 0 }};
neighbors.forEach(n => votes[n.dept]++);
const prediction = votes['2A'] > votes['2B'] ? '2A' : '2B';
return {{ prediction, neighbors, votes }};
}}
// Gestionnaire de clic sur la carte
function onMapClick(e) {{
const lat = e.latlng.lat;
const lon = e.latlng.lng;
classifyPoint(lat, lon);
}}
// Classifier un point
function classifyPoint(lat, lon) {{
// Supprimer les anciens marqueurs
if (testMarker) map.removeLayer(testMarker);
neighborMarkers.forEach(m => map.removeLayer(m));
neighborLines.forEach(l => map.removeLayer(l));
neighborMarkers = [];
neighborLines = [];
// Classifier
const result = knnClassify(lat, lon, currentK);
// Ajouter le marqueur du point test
testMarker = L.circleMarker([lat, lon], {{
radius: 12,
fillColor: '#95a5a6',
color: '#000',
weight: 3,
opacity: 1,
fillOpacity: 0.8
}}).addTo(map);
// Ajouter les marqueurs et lignes des voisins
result.neighbors.forEach(neighbor => {{
const nColor = neighbor.dept === '2A' ? '#e74c3c' : '#3498db';
// Ligne
const line = L.polyline(
[[lat, lon], [neighbor.lat, neighbor.lon]],
{{color: nColor, weight: 2, opacity: 0.5}}
).addTo(map);
neighborLines.push(line);
// Marqueur
const marker = L.circleMarker([neighbor.lat, neighbor.lon], {{
radius: 8,
fillColor: nColor,
color: '#333',
weight: 2,
opacity: 1,
fillOpacity: 0.8
}}).bindPopup(`<b>${{neighbor.name}}</b><br>${{neighbor.nameCorse}}<br>${{neighbor.dept}}<br>Distance: ${{neighbor.distance.toFixed(2)}} km`)
.addTo(map);
neighborMarkers.push(marker);
}});
// Afficher les résultats
displayResults(lat, lon, result);
}}
// Afficher les résultats
function displayResults(lat, lon, result) {{
const predictionDiv = document.getElementById('prediction');
const coordsDiv = document.getElementById('coords');
const votesContainer = document.getElementById('votesContainer');
const votes2A = document.getElementById('votes2A');
const votes2B = document.getElementById('votes2B');
const neighborsList = document.getElementById('neighborsList');
// Coordonnées
coordsDiv.textContent = `(${{lat.toFixed(4)}}, ${{lon.toFixed(4)}})`;
// Prédiction
const deptName = result.prediction === '2A' ? 'Corse du Sud (2A)' : 'Haute-Corse (2B)';
const cssClass = result.prediction === '2A' ? 'corse-sud' : 'haute-corse';
predictionDiv.textContent = deptName;
predictionDiv.className = 'prediction ' + cssClass;
// Votes
votes2A.textContent = result.votes['2A'];
votes2B.textContent = result.votes['2B'];
votesContainer.style.display = 'block';
// Liste des voisins
neighborsList.innerHTML = '';
result.neighbors.forEach(neighbor => {{
const div = document.createElement('div');
div.className = `neighbor-item dept-${{neighbor.dept.toLowerCase()}}`;
div.innerHTML = `
<div class="neighbor-name">${{neighbor.name}} (${{neighbor.dept}})</div>
<div class="neighbor-corse">${{neighbor.nameCorse}}</div>
<div class="neighbor-distance">Distance: ${{neighbor.distance.toFixed(2)}} km</div>
`;
neighborsList.appendChild(div);
}});
}}
// Point aléatoire
function placeRandomPoint() {{
const lat = 41.3 + Math.random() * (43.0 - 41.3);
const lon = 8.5 + Math.random() * (9.6 - 8.5);
classifyPoint(lat, lon);
map.setView([lat, lon], 10);
}}
// Réinitialiser
function resetClassification() {{
if (testMarker) map.removeLayer(testMarker);
neighborMarkers.forEach(m => map.removeLayer(m));
neighborLines.forEach(l => map.removeLayer(l));
neighborMarkers = [];
neighborLines = [];
testMarker = null;
document.getElementById('prediction').textContent = 'Cliquez sur la carte';
document.getElementById('prediction').className = 'prediction no-result';
document.getElementById('coords').textContent = '';
document.getElementById('votesContainer').style.display = 'none';
map.setView([42.15, 9.05], 9);
}}
// Gestionnaire du slider k
document.getElementById('kSlider').addEventListener('input', function(e) {{
currentK = parseInt(e.target.value);
document.getElementById('kValue').textContent = currentK;
// Reclassifier si un point existe
if (testMarker) {{
const latlng = testMarker.getLatLng();
classifyPoint(latlng.lat, latlng.lng);
}}
}});
// Initialisation
initMap();
</script>
</body>
</html>'''
with open(output_file, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f"✅ Fichier HTML généré : {output_file}")
print(f"📊 {len(villages)} villages inclus")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python generate_interactive_map.py villages_corse.csv")
sys.exit(1)
csv_file = sys.argv[1]
villages = load_villages_from_csv(csv_file)
generate_html(villages)

View file

@ -0,0 +1,137 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 12 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 13 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 11 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
9 0 obj
<<
/PageMode /UseNone /Pages 11 0 R /Type /Catalog
>>
endobj
10 0 obj
<<
/Author (anonymous) /CreationDate (D:20251023100834+00'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20251023100834+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
11 0 obj
<<
/Count 4 /Kids [ 5 0 R 6 0 R 7 0 R 8 0 R ] /Type /Pages
>>
endobj
12 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2409
>>
stream
Gat%$CQI5[(&dQ-EPH@r8@a,3>+d9%qe-??]@1rM:BM;gX<^DSfp1pgU;+EtPXs3qfM45Ya)c3FmZX!('ZBMdib,SDHM^7jr?=d'HMg#p1JNr!ki]ud`$ItrE*8iC-8:b=8lgP62b[2ZU;nk!qOookce[PO)+!TXq0o:>k#;'+deECq&&8,?RN=]Bj0s^TTqcYOr%0d,1*\7be\#ZfqEb^^j%']uY5*`8s1.I8Xrl!CiL5ShMTK)hdPJekjMZ!*5I^.B!t>0K\(qR3^E-QnG2$lg+)(7?^%o/W]#1F_)]bYb;ibG_TkioF;nkCX\+PmW]<4Ag>'$ZC#c9+&U=QcNj.Y4L@i^f`ZlaJ+GM>-DolJm7#&ZoaOk/F>qdA'M)oqebbO-da'f,*g%#SqZ3<q:AU-0#Sf/MM,BmZ9'ETXAlm]>MD]20_Sod$'&hg/IMj*iqq0GH6Uqm"tkhr([r3tU3Dr1l0qi=!^t:Tn)Jn`f^01ULWFC:fl'YWE=fEe]M=]V/V,.%UJ>BoF@G%jeWU9Bu>LP.K-n/^q_N7IRj7db<-XrZ!DamSH.FHJ!Dj6o?bVipkg3;nD-,lf5)SMRu<rH8a"(W+T$H-CpQVnal3gZ"mMKTVCUo2"dPpqm!B>clYimY]Jgd(Us*tEJA2(V@(<YCcZl&hr?H2J%qt07Uc0PYUL:YYWI;M6e\=7ms\+]C0tgipsba6:TnKf+`L73#O[@+GP6QlJk8o:BPPoLeAEuj*)&M%2kg7T'A`r>-AR`%DRdjaQ`H)4GbC6pd159pk0^0Cs*5pS5HCC&H-rs_,K25J=u_Zn7d%oIW4[V]R$URCNL^"Q'/PbCTKt&Gr'Ies0V]noK[R4.=/f6FD.Q?IXj!QjAnVe\'6?dG'AA+FV+%HZ$9Pek:!cRlh8c(1-aX2l8m;TK!a.gYTUE7Z9M6U+BG5QK<f;hQkt5_I1l:@"'XSai8uj!(:7&%<16WUr]<M6e1gsHWSRk]>;mI``VY,!H/SPlANRi'nN5Z(,ct4\^MPY.,Qf6ssL8%lYiL!Wj(Bc$rTaZJgk]KYb_!/]&X.h9]dU8Vr29ln6]OF4d9OF/&ACcNY$RV8UhGV2.R1cAr2ZZ3K[OK=/ZSTk:F3X";\%uj&(AVeJ@19EtUE`a>i^btfj6:LtdP57Ya"d]H,eCYH^6F5Kgmp-1A6'MtAPAen,U/G?S7%WTVU1ZkYV'(DV6]':khN`0Zo5#V)Ok&XjtrF@l\nD'g]omBnV*ad,V#pZU1b;KJJkIS5'.sDk.,%Hb",DHQ=\8qm!Mc'+qetG>-oRYbHaj#<;%UM?$M^k`bZo>8<U,P-Xj2p92%YhI)b2W;@#J+1olT<!^:MGK"qkkO:Wd4.D`)_,uFkYD.-Sa]OtIge4:qWo+k]_,p]Qb7V/Q8G@nGUm_$J:'3c$c;&>&X;G0J7+`1(q1JlYHQ:ZeBcm3.&<E;&a@UoaDk/!!iA%<sm1JlYGP0#m5Q8>Ek;N*Dh@i(`4fP1NnO^5h<Yq](_7F2]Gk'3"\l!'N11@$HSCatB*U%r7Hj-Zm+.eG$_9QHHAQ=m'&s,uCP(*V$Ph0Zt9cZKl`V^pJA5,X>$D4t9U>tA+N+iTbf^k+,^HbiV3?'sco]Vs#u4.DI&ZI+Nj_R8V!1f<6PS%df#$\pgDc#K8k#Zr(#EKB442Z:Vu(?.aqrPq0TP_Y6Sp2rs&e%mt@W4b0s?Bkp"n.8E0^m83t("u[OOk*j*`*j:GmQ6YtCQ@GjaD5DMWKj(qs3#)P2<'YEMW:!3(cYO*<Zt*T@)u8+O9;AU[h0"O%LB\d9O`!uNYpmmM45>G:_k6A8VQ0QL>%aM5tmPQ&e<h<X%G:,_DCB_V,iG1d1VX>@GRhX)=rieMUO]6%iKZLku[ATdcd4E1pnni_\@2+][B\W)MjCI97fqdAg&DDWX@<l34_ZNfV;H_Zll\=XBRBpN&MId9N0@IFVB:*MbUP%@WnKVE%^UGk^ILn'7B3lJ^#AbnNQ[,I#0qslca\agOFO?8J^*]ZSQ`<qnJrpmD[UjhU:X$jlb;Nbj45^)gP+0,YT0"<E&a)fWP=ni@K()'kag@CYcoETlE2X`),UP"D&<WH9D@b&f'V8V3GVXo_O4L'e1b<rJ=Do<nc!3<0esE;Y-!Fl80&JMO/P3(LA'K^B$lb4qWr"#lf(d't2lij8$%/=$A#8pU'(HFb8"JfAQl=[f&-KJ#W(3&Dt@Ia-u\+]QsNapMNH]6f#s)f%kSLqkbD&]rBt`?t_IdcC5aK)WR)@d30_1.Ikm]oWRg-h>Hl)0fUpc.72iF7Q=XWoTUfHkTN/^V7=5Gc^aI9[_I&nTg)6Ud8.r48&F[3B@/&<[C=(.=5bEmhQ.Ed=I]=S[[U"B=RZ"WE/7;%lWkT=7*DAZDct2dF6dN45:6%N)?~>endstream
endobj
13 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 845
>>
stream
GauHJD+iYL&H;+$QuCMAVjVs?TnjHl"Y$S7j$ANA:K)>VR2;"bqG&q]c^/D5J[`[Rc#/n]k':QNQQY6/`Flmb3(i/i(BP52c@HZZ85J/'h21G!8B,e3B"^qi'AB,L_@p%LOhC4G/n"GK2Df]A#8"*M?`SJ*LPk!7HWXlS[[9XWFA7:d4\1&gqYi,`qiF2snIgusW6*eMF;gH>W5<I$!t9@l,/?X2/ME%J5/?Y@hh=.1#Tj/+<rn1(@V)l/34oPX>eqfETC!8uTeGB%0&!%gmJTg;2F1sa.@ph;?;O&bd>&?$gC;O]l_5:FA`(A1WUn:5#Oq?TG_l47^2XW'\P\^>A_+</]Z@F^W2lje7&fIG@ATPOqF[?<8PiQ`,1P:oZ8@cA=$3l0&nR:qAX&&&:PuT=U:4r#`mD_lHX*rh!d\HPOXE83A27VCWu#E=[-%J\J]7\FG6l"EamRR4mM#jA(6P@D#c+"WCMBl?r4YF^"mYB%,]TYZN9)f6C1n#i6fGEBBT7+P8YXcS[85")80j%K9u_cGjd&:*1>E@)q\uq!jWt8m`Z-4VPACYV*<;!o?%`aELJW"QBLBmWAHk(r)>[qfl\bSVpUY:Gqmq<1IoEbpF6b<(kqchsP0qZ/Q=dFe2Cl0mSlY("W8L=@.=i[?G&(u8#>iRR.CWu\7CNC$2f][k:HM<\(9T'Z/QemD[<G?YKOsA)Nb^8=,[?.hU*UGcZkHb::WT)[[RH4`%[GCMat:M4#NOpsgsUSGP+9[6W=gIn`se<`Rdme[3aZT%NK's=];uu%E'/_Y+f#ef<C0Vu0)68pPhoT4bCn5&5F(BJGpFj;>IXhuIfKgqcK"~>endstream
endobj
14 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 832
>>
stream
GasbY95i9E'Lqim'pi4Li\Ksm,o.1%6=PM]b=K^a;rj+oOWT,Koit;jRT=;tUt@\rSF=a^kCs)62ijTM&`>^&=78.g!SJK4KaP+]E0KZ5(VjVC)U6.pW6ba.(S68%)S%dJZ6NW0r!?(p(',[c_-Sl$^ZrOegAptj*u]BD$/%IP0BWlRB/)e:'k%5[mVRo-g[(d!i@gV2-GZU[:NU<oY0X_cY(j%;OLK(P<u,G3rsAr-K\%>d(!g@3QOc.f^N\3@-4S5OGR78&jP&n\L2t#rcj?a0LPJqdTo:I)&15)tMs@f+b;B173&m"8*U=Fq8tiN<)g%OJKq68)/l=[sf%ug3H'JphN=]mobXSeqBVgfIG@I%Jc-S54e2t"aCDennP'*/FVUp-)RauQIS_30!%[GBbnP3oDX-lDq\64/kFri/e6#1aDn'!]';PR5Ed>hnIC-!Hln\dJn9rjtYpIZgeM2bgh;&NpXn&.,t?D(3?-f0]Na%FY)nYFqHD-;jkI<S_oXYUouo3kg:-ar8>*k@M,[5/c8`hB8nQ$=[bl*[neNlf4$Z!m"Ks.4.';@2u%nCX0n<c-I\`R&^1\9crqI+0lm:C2_En!&dJ4gu1j+7b$;?/EK(/kJ`:S`lrG#gcCE_``YgR_&MbQi0?hIKA<l0-PGTJ@p^ZZ\@k'd'#oDmk<-&+4i:9qnl>.._q_DlLGLZW_7)cqhnPjEQ.&E*1CLrKXYWjF\>9V`/nD*&oPn$bH$6_L[V,C9q\H^V@2d4hWZH4hKQ6cclC5Dd-!*c_ejm0cT%&BS+^2"JM?,j*rhk\5G,Qnb%[!@i7n05A\d^UQPRA0~>endstream
endobj
15 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1422
>>
stream
Gau0B?#SIW&:ErMfXGo3#pY<?,o%g<\b6(E&-TPE+8nN![#\jJKbTMOIslMi\$G%iDK7<1,dq1./8&U.aW\MC*e'Fb_!c?S]]R">R'2#f/:mU+r%W[7T#^UO4I7UkT(<sj.[_jIJjYj%N#/dMGltCbc<F+fXY'1QG>NL\4bNRF0`Q8;QNpd3ic!f8X#u@S_S*StO1mFi@?8fJE7O]j.Fhh;eq%+_P\Vhk6)A"2EI7Sm*'AZa!1kScMc_SXb)hI5nP$m[O:.Xkn@($^[T1=-eWq,R?\kYfB(/hgUK[-MNBUl7`f6`"o&G4;5a82bMm^XQ+Arr7!fPaSe;ZPF`]J81of;ZQX1T>*ip7@PPd3E;q*anlW--k*_3E;Ci=u]#,=P`ckKIZg+'$^e>#e%a-BSIE1)9$p#pBhjquYu+eNft8/(>'b-r[`VTNT9t4;-!*^/Ce)odQ<*'MLn4T4%)=0t,)!D*\5dSp.WD]/@_-9%V3fZ6Y^gMd?4Hf5@rH[@V,9ebT:gI#hV:i3P&-MMhV\Z=7V^B5k7Ym@`%ZCr"el9Eu&V,RTZ"RMSXeEpOD=N,COJ?Y`c""LFt@HE5d-7mdgI,Pj'aZI/'4mF2$'#dT[@6LY)/469kL*@;1i+/2kkGd>kQ(`6,bB8ePG9?uP(a:Eg)]/FoBeZ^mAKq:W56BtT[CBm3OC@PSfcDaN2LJS0s4Q2[V/P2.b7;,RKi!4Bb'eq5K#f/NZ);LV!%-jn&r_K/3cE\^Q&(J06\^a`IfF6lbcM,7TTmS#0*MuHZ)=30Z92CISkkq*o%&f+(BT/QXQ\daq==SN!k,ZIClc]u9VYn=qUKVDJdFsY.EeKkq&IU8c;/\gbCWsU\do"8;3fF@Q[=VsD`>/P'3!)"9n2&2G3(a_O0sr?`p#KS&R57-lOMLYCU",g1;B5YHpSKjlELXYeBo.dOP[s:pFBX:Yc*Pf2K#)e==(1fGJo0GT=4n!0SRkZ?30Y@!CtD%X#P?GR[X#n0BCH\lA-#e9gkP!"NPkZ($ch!0ePl#IZnL".dNIKP9B/]07D))W<CkbX>E.JK97qE?!G1HMb;aK#M_mH<cM'<!g=/ZK*ZfKk.>+L=47bJTd4[PIFM@iu8=0DuWb_+iis13LS?FXK:5snA(!^lL(pb;G^W"*\UC`gGQulgZNpDmD,<C.[<j`6,PX^*(mm*C1H4Cg&m.#=MpGs%&g0>oo`ToA94][:aefW/[[p1mi-Q&UI4GrZAUXl<mT>759(^tl++*@sBQ\pm',`5Ucc-QQN+2k4Dhr7(9^B<ie%SW[<c>oM;1&$5SLe(0%%/[EqlVPYpHg3A>K]psR%ce&sJ6--#jJPi*^$c@kefZ=HE,ct8&BfZ62$1!#'Ru?sG)'Z6I[RtT>[_qqa(@PWVg]A*r%l1.cNI$=J]!u'N7!,N~>endstream
endobj
xref
0 16
0000000000 65535 f
0000000073 00000 n
0000000124 00000 n
0000000231 00000 n
0000000343 00000 n
0000000426 00000 n
0000000631 00000 n
0000000836 00000 n
0000001041 00000 n
0000001246 00000 n
0000001315 00000 n
0000001612 00000 n
0000001690 00000 n
0000004191 00000 n
0000005127 00000 n
0000006050 00000 n
trailer
<<
/ID
[<2232646b4bd42a525eb8afd576232bc1><2232646b4bd42a525eb8afd576232bc1>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 10 0 R
/Root 9 0 R
/Size 16
>>
startxref
7564
%%EOF

Binary file not shown.

View file

@ -0,0 +1,561 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🗺️ Classification k-NN : Haute-Corse ou Corse du Sud ?\n",
"\n",
"## Objectif\n",
"Utiliser l'algorithme des **k plus proches voisins (k-NN)** pour déterminer si un point de la carte de Corse se situe en **Haute-Corse (2B)** ou en **Corse du Sud (2A)**, en se basant sur les villages les plus proches.\n",
"\n",
"## Principe\n",
"1. On charge les données des villages corses avec leurs coordonnées GPS et leur département\n",
"2. On choisit un point sur la carte\n",
"3. On calcule les distances entre ce point et tous les villages\n",
"4. On identifie les k villages les plus proches\n",
"5. On vote : le département majoritaire parmi ces k villages devient la prédiction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📦 Installation et imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques nécessaires (si besoin)\n",
"import sys\n",
"!{sys.executable} -m pip install folium pandas numpy -q"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import folium\n",
"from folium.plugins import MarkerCluster\n",
"import math\n",
"from collections import Counter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📊 Chargement des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Charger le fichier CSV\n",
"# Remplacez 'villages_corse.csv' par le chemin de votre fichier\n",
"df = pd.read_csv('villages_corse.csv', sep=';', encoding='utf-8')\n",
"\n",
"# Afficher les premières lignes\n",
"print(f\"Nombre de villages : {len(df)}\")\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🔧 Préparation des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def parse_coordinates(point_geo_str):\n",
" \"\"\"\n",
" Parse la colonne Point_Geo pour extraire latitude et longitude.\n",
" Format attendu : \"POINT(longitude latitude)\" ou similaire\n",
" \"\"\"\n",
" try:\n",
" # Supprimer 'POINT(' et ')'\n",
" coords = point_geo_str.replace('POINT(', '').replace(')', '').strip()\n",
" lon, lat = coords.split()\n",
" return float(lat), float(lon)\n",
" except:\n",
" return None, None\n",
"\n",
"# Extraire les coordonnées\n",
"df[['latitude', 'longitude']] = df['Point_Geo'].apply(\n",
" lambda x: pd.Series(parse_coordinates(x))\n",
")\n",
"\n",
"# Supprimer les lignes sans coordonnées valides\n",
"df = df.dropna(subset=['latitude', 'longitude'])\n",
"\n",
"# Simplifier les noms de départements\n",
"df['dept_simple'] = df['Code Département'].apply(lambda x: '2A' if x == '2A' else '2B')\n",
"\n",
"print(f\"Villages avec coordonnées valides : {len(df)}\")\n",
"print(f\"\\nRépartition par département :\")\n",
"print(df['dept_simple'].value_counts())\n",
"\n",
"df[['Nom français', 'dept_simple', 'latitude', 'longitude']].head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📏 Fonction de calcul de distance\n",
"\n",
"Nous utilisons la **formule de Haversine** pour calculer la distance entre deux points GPS sur la surface de la Terre."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def haversine_distance(lat1, lon1, lat2, lon2):\n",
" \"\"\"\n",
" Calcule la distance en kilomètres entre deux points GPS.\n",
" Formule de Haversine.\n",
" \"\"\"\n",
" R = 6371 # Rayon de la Terre en km\n",
" \n",
" # Conversion en radians\n",
" lat1_rad = math.radians(lat1)\n",
" lat2_rad = math.radians(lat2)\n",
" delta_lat = math.radians(lat2 - lat1)\n",
" delta_lon = math.radians(lon2 - lon1)\n",
" \n",
" # Formule de Haversine\n",
" a = math.sin(delta_lat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2\n",
" c = 2 * math.asin(math.sqrt(a))\n",
" \n",
" return R * c\n",
"\n",
"# Test de la fonction\n",
"# Distance entre Ajaccio et Bastia (environ 100 km)\n",
"dist_test = haversine_distance(41.9267, 8.7369, 42.7028, 9.4500)\n",
"print(f\"Distance Ajaccio-Bastia : {dist_test:.1f} km\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎯 Algorithme k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def knn_classify(test_lat, test_lon, df, k=5):\n",
" \"\"\"\n",
" Classifie un point (test_lat, test_lon) en utilisant k-NN.\n",
" \n",
" Retourne :\n",
" - prediction : le département prédit ('2A' ou '2B')\n",
" - neighbors : DataFrame des k plus proches voisins\n",
" - votes : dictionnaire des votes\n",
" \"\"\"\n",
" # Calculer les distances pour tous les villages\n",
" distances = []\n",
" for idx, row in df.iterrows():\n",
" dist = haversine_distance(test_lat, test_lon, row['latitude'], row['longitude'])\n",
" distances.append({\n",
" 'village': row['Nom français'],\n",
" 'departement': row['dept_simple'],\n",
" 'latitude': row['latitude'],\n",
" 'longitude': row['longitude'],\n",
" 'distance': dist\n",
" })\n",
" \n",
" # Créer un DataFrame et trier par distance\n",
" dist_df = pd.DataFrame(distances)\n",
" dist_df = dist_df.sort_values('distance')\n",
" \n",
" # Sélectionner les k plus proches\n",
" neighbors = dist_df.head(k)\n",
" \n",
" # Voter\n",
" votes = Counter(neighbors['departement'])\n",
" prediction = votes.most_common(1)[0][0]\n",
" \n",
" return prediction, neighbors, votes\n",
"\n",
"# Test de l'algorithme avec un point au centre de la Corse\n",
"test_lat, test_lon = 42.15, 9.05\n",
"k = 5\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
"\n",
"print(f\"\\n🎯 Point de test : ({test_lat}, {test_lon})\")\n",
"print(f\"\\nAvec k={k} :\")\n",
"print(f\"Prédiction : {prediction}\")\n",
"print(f\"Votes : {dict(votes)}\")\n",
"print(f\"\\nLes {k} plus proches voisins :\")\n",
"print(neighbors[['village', 'departement', 'distance']])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🗺️ Visualisation avec Folium"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def create_map(test_lat=None, test_lon=None, k=5, show_all_villages=False):\n",
" \"\"\"\n",
" Crée une carte interactive avec Folium.\n",
" \"\"\"\n",
" # Centre de la Corse\n",
" center_lat = 42.15\n",
" center_lon = 9.05\n",
" \n",
" # Créer la carte\n",
" m = folium.Map(\n",
" location=[center_lat, center_lon],\n",
" zoom_start=9,\n",
" tiles='OpenStreetMap'\n",
" )\n",
" \n",
" # Afficher tous les villages (optionnel, peut être lourd)\n",
" if show_all_villages:\n",
" marker_cluster = MarkerCluster().add_to(m)\n",
" \n",
" for idx, row in df.iterrows():\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" folium.CircleMarker(\n",
" location=[row['latitude'], row['longitude']],\n",
" radius=2,\n",
" color=color,\n",
" fill=True,\n",
" fillColor=color,\n",
" fillOpacity=0.3,\n",
" popup=f\"{row['Nom français']} ({row['dept_simple']})\"\n",
" ).add_to(marker_cluster)\n",
" \n",
" # Si un point de test est fourni\n",
" if test_lat is not None and test_lon is not None:\n",
" # Classification\n",
" prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
" \n",
" # Marqueur pour le point de test\n",
" color = 'darkred' if prediction == '2A' else 'darkblue'\n",
" folium.Marker(\n",
" location=[test_lat, test_lon],\n",
" popup=f\"Point à classifier<br>Prédiction : {prediction}<br>Votes : {dict(votes)}\",\n",
" icon=folium.Icon(color=color, icon='star', prefix='fa')\n",
" ).add_to(m)\n",
" \n",
" # Afficher les k plus proches voisins\n",
" for idx, neighbor in neighbors.iterrows():\n",
" # Marqueur pour chaque voisin\n",
" color = 'red' if neighbor['departement'] == '2A' else 'blue'\n",
" folium.Marker(\n",
" location=[neighbor['latitude'], neighbor['longitude']],\n",
" popup=f\"{neighbor['village']}<br>{neighbor['departement']}<br>Distance: {neighbor['distance']:.2f} km\",\n",
" icon=folium.Icon(color=color, icon='info-sign')\n",
" ).add_to(m)\n",
" \n",
" # Ligne entre le point test et le voisin\n",
" folium.PolyLine(\n",
" locations=[\n",
" [test_lat, test_lon],\n",
" [neighbor['latitude'], neighbor['longitude']]\n",
" ],\n",
" color=color,\n",
" weight=2,\n",
" opacity=0.5\n",
" ).add_to(m)\n",
" \n",
" # Légende\n",
" legend_html = '''\n",
" <div style=\"position: fixed; \n",
" bottom: 50px; right: 50px; width: 200px; height: 120px; \n",
" background-color: white; border:2px solid grey; z-index:9999; \n",
" font-size:14px; padding: 10px\">\n",
" <p><strong>Légende</strong></p>\n",
" <p><i class=\"fa fa-circle\" style=\"color:red\"></i> Corse du Sud (2A)</p>\n",
" <p><i class=\"fa fa-circle\" style=\"color:blue\"></i> Haute-Corse (2B)</p>\n",
" <p><i class=\"fa fa-star\" style=\"color:darkred\"></i> Point à classifier</p>\n",
" </div>\n",
" '''\n",
" m.get_root().html.add_child(folium.Element(legend_html))\n",
" \n",
" return m\n",
"\n",
"# Créer la carte avec le point de test\n",
"map_with_test = create_map(test_lat=42.15, test_lon=9.05, k=5, show_all_villages=False)\n",
"map_with_test"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🔬 Expérimentation : Influence de k"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Test avec différentes valeurs de k\n",
"test_point = (42.15, 9.05) # Point au centre de la Corse\n",
"\n",
"print(f\"Point testé : {test_point}\\n\")\n",
"print(f\"{'k':<5} {'Prédiction':<12} {'Votes 2A':<10} {'Votes 2B':<10}\")\n",
"print(\"-\" * 45)\n",
"\n",
"for k in [1, 3, 5, 7, 9, 15]:\n",
" prediction, neighbors, votes = knn_classify(test_point[0], test_point[1], df, k=k)\n",
" votes_2a = votes.get('2A', 0)\n",
" votes_2b = votes.get('2B', 0)\n",
" print(f\"{k:<5} {prediction:<12} {votes_2a:<10} {votes_2b:<10}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎮 Mode interactif : Testez vos propres points !\n",
"\n",
"Modifiez les coordonnées ci-dessous pour tester différents points de la Corse."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# === MODIFIEZ CES VALEURS ===\n",
"test_latitude = 42.5 # Entre 41.3 (sud) et 43.0 (nord)\n",
"test_longitude = 9.2 # Entre 8.5 (ouest) et 9.5 (est)\n",
"k_value = 7 # Nombre de voisins\n",
"# =============================\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_latitude, test_longitude, df, k=k_value)\n",
"\n",
"print(f\"📍 Point : ({test_latitude}, {test_longitude})\")\n",
"print(f\"🔢 k = {k_value}\")\n",
"print(f\"\\n🎯 Prédiction : {'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'}\")\n",
"print(f\"\\n📊 Votes : {dict(votes)}\")\n",
"print(f\"\\n🏘 Les {k_value} plus proches villages :\")\n",
"print(neighbors[['village', 'departement', 'distance']].to_string(index=False))\n",
"\n",
"# Afficher la carte\n",
"map_interactive = create_map(test_latitude, test_longitude, k=k_value, show_all_villages=False)\n",
"map_interactive"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🌍 Carte complète avec tous les villages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Afficher tous les villages de Corse (peut être lent)\n",
"# Attention : cette cellule peut prendre du temps à s'exécuter\n",
"\n",
"map_all = create_map(show_all_villages=True)\n",
"map_all"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📈 Visualisation de la frontière entre départements"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Créer une grille de points et classifier chacun\n",
"# Cela permet de visualiser la \"frontière\" selon k-NN\n",
"\n",
"def create_decision_boundary_map(k=5, grid_resolution=50):\n",
" \"\"\"\n",
" Crée une carte montrant la frontière de décision de k-NN.\n",
" \"\"\"\n",
" # Limites de la Corse\n",
" lat_min, lat_max = 41.3, 43.0\n",
" lon_min, lon_max = 8.5, 9.6\n",
" \n",
" # Créer une grille\n",
" lats = np.linspace(lat_min, lat_max, grid_resolution)\n",
" lons = np.linspace(lon_min, lon_max, grid_resolution)\n",
" \n",
" m = folium.Map(\n",
" location=[42.15, 9.05],\n",
" zoom_start=8,\n",
" tiles='OpenStreetMap'\n",
" )\n",
" \n",
" # Classifier chaque point de la grille\n",
" print(\"Classification de la grille en cours...\")\n",
" for i, lat in enumerate(lats[::5]): # Réduire la résolution pour la vitesse\n",
" for lon in lons[::5]:\n",
" prediction, _, _ = knn_classify(lat, lon, df, k=k)\n",
" color = 'red' if prediction == '2A' else 'blue'\n",
" \n",
" folium.CircleMarker(\n",
" location=[lat, lon],\n",
" radius=3,\n",
" color=color,\n",
" fill=True,\n",
" fillColor=color,\n",
" fillOpacity=0.2,\n",
" weight=0\n",
" ).add_to(m)\n",
" \n",
" if (i+1) % 5 == 0:\n",
" print(f\" {(i+1)*100//len(lats[::5])}% complété\")\n",
" \n",
" print(\"Terminé !\")\n",
" return m\n",
"\n",
"# Créer la carte (peut prendre quelques secondes)\n",
"print(f\"Création de la carte de frontière avec k=5...\")\n",
"boundary_map = create_decision_boundary_map(k=5, grid_resolution=30)\n",
"boundary_map"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎓 Questions de réflexion\n",
"\n",
"1. **Influence de k** : Testez différentes valeurs de k (1, 3, 5, 10, 20). Comment la prédiction change-t-elle ?\n",
"\n",
"2. **Points frontières** : Trouvez des points où la classification change selon la valeur de k.\n",
"\n",
"3. **Zones ambiguës** : Où se situent les zones les plus difficiles à classifier ?\n",
"\n",
"4. **Validité** : Cette méthode est-elle toujours fiable ? Dans quels cas pourrait-elle échouer ?\n",
"\n",
"5. **Amélioration** : Comment pourrait-on améliorer l'algorithme ? (pondération par distance, normalisation, etc.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 Pour aller plus loin\n",
"\n",
"### Exercices supplémentaires :\n",
"\n",
"1. **Pondération par distance** : Modifier l'algorithme pour donner plus de poids aux villages plus proches\n",
"2. **Validation croisée** : Tester la précision en utilisant les villages eux-mêmes comme points de test\n",
"3. **Autres critères** : Ajouter l'altitude comme dimension supplémentaire\n",
"4. **Clustering** : Identifier des groupes de villages similaires"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# BONUS : Validation croisée\n",
"# Tester la précision en utilisant les villages eux-mêmes\n",
"\n",
"def cross_validation(df, k=5, sample_size=100):\n",
" \"\"\"\n",
" Teste la précision de k-NN en utilisant un échantillon de villages.\n",
" \"\"\"\n",
" # Prendre un échantillon aléatoire\n",
" sample = df.sample(n=min(sample_size, len(df)), random_state=42)\n",
" \n",
" correct = 0\n",
" total = 0\n",
" \n",
" for idx, row in sample.iterrows():\n",
" # Créer un dataset sans ce village\n",
" df_without = df.drop(idx)\n",
" \n",
" # Classifier ce village\n",
" prediction, _, _ = knn_classify(\n",
" row['latitude'], \n",
" row['longitude'], \n",
" df_without, \n",
" k=k\n",
" )\n",
" \n",
" if prediction == row['dept_simple']:\n",
" correct += 1\n",
" total += 1\n",
" \n",
" accuracy = (correct / total) * 100\n",
" return accuracy, correct, total\n",
"\n",
"print(\"Test de précision de l'algorithme k-NN...\\n\")\n",
"\n",
"for k in [1, 3, 5, 10]:\n",
" accuracy, correct, total = cross_validation(df, k=k, sample_size=100)\n",
" print(f\"k={k:2d} : {accuracy:.1f}% de précision ({correct}/{total} corrects)\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View file

@ -0,0 +1,375 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🗺️ k-NN Corse : Version Interactive avec Clic sur Carte\n",
"\n",
"## 🎮 Mode d'emploi\n",
"1. Exécutez toutes les cellules\n",
"2. **Cliquez sur la carte** pour choisir un point\n",
"3. Ajustez k avec le curseur\n",
"4. Observez la classification en temps réel !"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📦 Installation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques\n",
"import sys\n",
"!{sys.executable} -m pip install ipyleaflet ipywidgets pandas numpy -q"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import math\n",
"from collections import Counter\n",
"from ipyleaflet import Map, Marker, CircleMarker, Polyline, AwesomeIcon, LayerGroup\n",
"from ipywidgets import HTML, VBox, HBox, IntSlider, Output, Label\n",
"from IPython.display import display, clear_output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📊 Chargement des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Charger les données\n",
"df = pd.read_csv('villages_corse.csv', sep='\\t', encoding='utf-8')\n",
"\n",
"def parse_coordinates(point_geo_str):\n",
" try:\n",
" parts = str(point_geo_str).split(',')\n",
" lat = float(parts[0].strip())\n",
" lon = float(parts[1].strip())\n",
" return lat, lon\n",
" except:\n",
" return None, None\n",
"\n",
"df[['latitude', 'longitude']] = df['Point_Geo'].apply(\n",
" lambda x: pd.Series(parse_coordinates(x))\n",
")\n",
"\n",
"df = df.dropna(subset=['latitude', 'longitude'])\n",
"df['dept_simple'] = df['Code Département'].apply(lambda x: '2A' if str(x) == '2A' else '2B')\n",
"\n",
"print(f\"✅ {len(df)} villages chargés\")\n",
"print(f\" - Corse du Sud (2A) : {len(df[df['dept_simple']=='2A'])}\")\n",
"print(f\" - Haute-Corse (2B) : {len(df[df['dept_simple']=='2B'])}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🧮 Fonctions k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def haversine_distance(lat1, lon1, lat2, lon2):\n",
" \"\"\"Calcule la distance en km entre deux points GPS.\"\"\"\n",
" R = 6371\n",
" lat1_rad = math.radians(lat1)\n",
" lat2_rad = math.radians(lat2)\n",
" delta_lat = math.radians(lat2 - lat1)\n",
" delta_lon = math.radians(lon2 - lon1)\n",
" \n",
" a = math.sin(delta_lat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2\n",
" c = 2 * math.asin(math.sqrt(a))\n",
" \n",
" return R * c\n",
"\n",
"def knn_classify(test_lat, test_lon, df, k=5):\n",
" \"\"\"Classifie un point avec k-NN.\"\"\"\n",
" distances = []\n",
" for idx, row in df.iterrows():\n",
" dist = haversine_distance(test_lat, test_lon, row['latitude'], row['longitude'])\n",
" distances.append({\n",
" 'village': row['Nom français'],\n",
" 'nom_corse': row['Nom corse'],\n",
" 'departement': row['dept_simple'],\n",
" 'latitude': row['latitude'],\n",
" 'longitude': row['longitude'],\n",
" 'distance': dist\n",
" })\n",
" \n",
" dist_df = pd.DataFrame(distances).sort_values('distance')\n",
" neighbors = dist_df.head(k)\n",
" votes = Counter(neighbors['departement'])\n",
" prediction = votes.most_common(1)[0][0]\n",
" \n",
" return prediction, neighbors, votes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🗺️ Carte Interactive\n",
"\n",
"**Instructions :**\n",
"- 🖱️ **Cliquez sur la carte** pour placer un point\n",
"- 🎚️ **Ajustez k** avec le curseur\n",
"- 👁️ La classification se met à jour automatiquement"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Créer la carte\n",
"m = Map(center=(42.15, 9.05), zoom=9, scroll_wheel_zoom=True)\n",
"\n",
"# Couches pour les éléments dynamiques\n",
"test_point_layer = LayerGroup()\n",
"neighbors_layer = LayerGroup()\n",
"lines_layer = LayerGroup()\n",
"\n",
"m.add_layer(test_point_layer)\n",
"m.add_layer(neighbors_layer)\n",
"m.add_layer(lines_layer)\n",
"\n",
"# Afficher quelques villages de référence\n",
"sample_villages = df.sample(n=min(50, len(df)), random_state=42)\n",
"for idx, row in sample_villages.iterrows():\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" circle = CircleMarker(\n",
" location=(row['latitude'], row['longitude']),\n",
" radius=3,\n",
" color=color,\n",
" fill_color=color,\n",
" fill_opacity=0.4,\n",
" weight=1\n",
" )\n",
" m.add_layer(circle)\n",
"\n",
"# Widget pour k\n",
"k_slider = IntSlider(\n",
" value=5,\n",
" min=1,\n",
" max=20,\n",
" step=1,\n",
" description='k:',\n",
" continuous_update=False\n",
")\n",
"\n",
"# Zone de résultats\n",
"result_output = Output()\n",
"info_html = HTML(value=\"<p style='font-size:16px; padding:10px; background:#f0f0f0; border-radius:5px;'>👆 <b>Cliquez sur la carte pour classifier un point</b></p>\")\n",
"\n",
"# Variable globale pour stocker les coordonnées\n",
"current_coords = {'lat': None, 'lon': None}\n",
"\n",
"def update_classification(lat, lon, k):\n",
" \"\"\"Met à jour la classification et la visualisation.\"\"\"\n",
" # Effacer les couches précédentes\n",
" test_point_layer.clear_layers()\n",
" neighbors_layer.clear_layers()\n",
" lines_layer.clear_layers()\n",
" \n",
" # Classification\n",
" prediction, neighbors, votes = knn_classify(lat, lon, df, k=k)\n",
" \n",
" # Couleur selon prédiction\n",
" color = 'red' if prediction == '2A' else 'blue'\n",
" dept_name = 'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'\n",
" \n",
" # Marqueur du point test\n",
" icon = AwesomeIcon(\n",
" name='star',\n",
" marker_color='darkred' if prediction == '2A' else 'darkblue',\n",
" icon_color='white'\n",
" )\n",
" test_marker = Marker(location=(lat, lon), icon=icon, draggable=False)\n",
" test_point_layer.add_layer(test_marker)\n",
" \n",
" # Afficher les k plus proches voisins\n",
" for idx, neighbor in neighbors.iterrows():\n",
" n_color = 'red' if neighbor['departement'] == '2A' else 'blue'\n",
" \n",
" # Marqueur du voisin\n",
" n_marker = CircleMarker(\n",
" location=(neighbor['latitude'], neighbor['longitude']),\n",
" radius=8,\n",
" color=n_color,\n",
" fill_color=n_color,\n",
" fill_opacity=0.7,\n",
" weight=2\n",
" )\n",
" neighbors_layer.add_layer(n_marker)\n",
" \n",
" # Ligne vers le voisin\n",
" line = Polyline(\n",
" locations=[\n",
" (lat, lon),\n",
" (neighbor['latitude'], neighbor['longitude'])\n",
" ],\n",
" color=n_color,\n",
" weight=2,\n",
" opacity=0.5\n",
" )\n",
" lines_layer.add_layer(line)\n",
" \n",
" # Afficher les résultats\n",
" with result_output:\n",
" clear_output(wait=True)\n",
" print(f\"📍 Coordonnées : ({lat:.4f}, {lon:.4f})\")\n",
" print(f\"🔢 k = {k}\")\n",
" print(f\"\\n🎯 Prédiction : {dept_name}\")\n",
" print(f\"📊 Votes : 2A={votes.get('2A', 0)}, 2B={votes.get('2B', 0)}\")\n",
" print(f\"\\n🏘 Les {k} plus proches villages :\")\n",
" print(neighbors[['village', 'nom_corse', 'departement', 'distance']].to_string(index=False))\n",
" \n",
" # Mettre à jour l'info\n",
" info_html.value = f\"<div style='font-size:16px; padding:10px; background:{'#ffebee' if prediction=='2A' else '#e3f2fd'}; border-radius:5px; border-left: 4px solid {color};'><b>Classification : {dept_name}</b><br>Votes : 2A={votes.get('2A', 0)}, 2B={votes.get('2B', 0)}</div>\"\n",
"\n",
"def handle_click(**kwargs):\n",
" \"\"\"Gestionnaire de clic sur la carte.\"\"\"\n",
" if kwargs.get('type') == 'click':\n",
" coords = kwargs.get('coordinates')\n",
" lat, lon = coords\n",
" current_coords['lat'] = lat\n",
" current_coords['lon'] = lon\n",
" update_classification(lat, lon, k_slider.value)\n",
"\n",
"def on_k_change(change):\n",
" \"\"\"Gestionnaire de changement de k.\"\"\"\n",
" if current_coords['lat'] is not None:\n",
" update_classification(current_coords['lat'], current_coords['lon'], change['new'])\n",
"\n",
"# Connecter les événements\n",
"m.on_interaction(handle_click)\n",
"k_slider.observe(on_k_change, names='value')\n",
"\n",
"# Afficher l'interface\n",
"display(VBox([\n",
" info_html,\n",
" HBox([Label('Nombre de voisins (k):'), k_slider]),\n",
" m,\n",
" result_output\n",
"]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎯 Points d'intérêt à tester\n",
"\n",
"Essayez de cliquer sur ces zones :\n",
"\n",
"- **Ajaccio** : (41.9267, 8.7369) - Capitale 2A\n",
"- **Bastia** : (42.7028, 9.4500) - Préfecture 2B\n",
"- **Corte** : (42.3062, 9.1509) - Centre de la Corse\n",
"- **Frontière approximative** : Zone entre 42.0 et 42.3 latitude\n",
"\n",
"### Questions à explorer :\n",
"1. 🤔 Où se situe la \"frontière\" k-NN entre les deux départements ?\n",
"2. 📊 Comment k influence-t-il la classification près de cette frontière ?\n",
"3. 🏔️ Y a-t-il des zones ambiguës où le résultat change souvent ?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 Mode manuel (si la carte ne fonctionne pas)\n",
"\n",
"Si le clic sur carte ne fonctionne pas, utilisez cette cellule :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Mode manuel : entrez les coordonnées\n",
"test_lat = 42.3 # Modifiez ici\n",
"test_lon = 9.15 # Modifiez ici\n",
"k = 5\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
"dept_name = 'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'\n",
"\n",
"print(f\"📍 Point : ({test_lat}, {test_lon})\")\n",
"print(f\"🎯 Prédiction : {dept_name}\")\n",
"print(f\"📊 Votes : {dict(votes)}\")\n",
"print(f\"\\n🏘 Les {k} plus proches villages :\")\n",
"print(neighbors[['village', 'nom_corse', 'departement', 'distance']].to_string(index=False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📝 Notes techniques\n",
"\n",
"Cette version utilise **ipyleaflet** qui offre une vraie interactivité bidirectionnelle entre Python et JavaScript dans Jupyter.\n",
"\n",
"**Avantages :**\n",
"- ✅ Clic directement sur la carte\n",
"- ✅ Mise à jour en temps réel\n",
"- ✅ Curseur interactif pour k\n",
"- ✅ Pas besoin de recharger\n",
"\n",
"**Prérequis :**\n",
"- Jupyter Notebook ou JupyterLab\n",
"- Extension widgets activée : `jupyter nbextension enable --py widgetsnbextension`"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View file

@ -0,0 +1,375 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🗺️ k-NN Corse : Version Interactive avec Clic sur Carte\n",
"\n",
"## 🎮 Mode d'emploi\n",
"1. Exécutez toutes les cellules\n",
"2. **Cliquez sur la carte** pour choisir un point\n",
"3. Ajustez k avec le curseur\n",
"4. Observez la classification en temps réel !"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📦 Installation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques\n",
"import sys\n",
"!{sys.executable} -m pip install ipyleaflet ipywidgets pandas numpy -q"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import math\n",
"from collections import Counter\n",
"from ipyleaflet import Map, Marker, CircleMarker, Polyline, AwesomeIcon, LayerGroup\n",
"from ipywidgets import HTML, VBox, HBox, IntSlider, Output, Label\n",
"from IPython.display import display, clear_output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📊 Chargement des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Charger les données\n",
"df = pd.read_csv('villages_corse.csv', sep='\\t', encoding='utf-8')\n",
"\n",
"def parse_coordinates(point_geo_str):\n",
" try:\n",
" parts = str(point_geo_str).split(',')\n",
" lat = float(parts[0].strip())\n",
" lon = float(parts[1].strip())\n",
" return lat, lon\n",
" except:\n",
" return None, None\n",
"\n",
"df[['latitude', 'longitude']] = df['Point_Geo'].apply(\n",
" lambda x: pd.Series(parse_coordinates(x))\n",
")\n",
"\n",
"df = df.dropna(subset=['latitude', 'longitude'])\n",
"df['dept_simple'] = df['Code Département'].apply(lambda x: '2A' if str(x) == '2A' else '2B')\n",
"\n",
"print(f\"✅ {len(df)} villages chargés\")\n",
"print(f\" - Corse du Sud (2A) : {len(df[df['dept_simple']=='2A'])}\")\n",
"print(f\" - Haute-Corse (2B) : {len(df[df['dept_simple']=='2B'])}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🧮 Fonctions k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def haversine_distance(lat1, lon1, lat2, lon2):\n",
" \"\"\"Calcule la distance en km entre deux points GPS.\"\"\"\n",
" R = 6371\n",
" lat1_rad = math.radians(lat1)\n",
" lat2_rad = math.radians(lat2)\n",
" delta_lat = math.radians(lat2 - lat1)\n",
" delta_lon = math.radians(lon2 - lon1)\n",
" \n",
" a = math.sin(delta_lat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2\n",
" c = 2 * math.asin(math.sqrt(a))\n",
" \n",
" return R * c\n",
"\n",
"def knn_classify(test_lat, test_lon, df, k=5):\n",
" \"\"\"Classifie un point avec k-NN.\"\"\"\n",
" distances = []\n",
" for idx, row in df.iterrows():\n",
" dist = haversine_distance(test_lat, test_lon, row['latitude'], row['longitude'])\n",
" distances.append({\n",
" 'village': row['Nom français'],\n",
" 'nom_corse': row['Nom corse'],\n",
" 'departement': row['dept_simple'],\n",
" 'latitude': row['latitude'],\n",
" 'longitude': row['longitude'],\n",
" 'distance': dist\n",
" })\n",
" \n",
" dist_df = pd.DataFrame(distances).sort_values('distance')\n",
" neighbors = dist_df.head(k)\n",
" votes = Counter(neighbors['departement'])\n",
" prediction = votes.most_common(1)[0][0]\n",
" \n",
" return prediction, neighbors, votes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🗺️ Carte Interactive\n",
"\n",
"**Instructions :**\n",
"- 🖱️ **Cliquez sur la carte** pour placer un point\n",
"- 🎚️ **Ajustez k** avec le curseur\n",
"- 👁️ La classification se met à jour automatiquement"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Créer la carte\n",
"m = Map(center=(42.15, 9.05), zoom=9, scroll_wheel_zoom=True)\n",
"\n",
"# Couches pour les éléments dynamiques\n",
"test_point_layer = LayerGroup()\n",
"neighbors_layer = LayerGroup()\n",
"lines_layer = LayerGroup()\n",
"\n",
"m.add_layer(test_point_layer)\n",
"m.add_layer(neighbors_layer)\n",
"m.add_layer(lines_layer)\n",
"\n",
"# Afficher quelques villages de référence\n",
"sample_villages = df.sample(n=min(50, len(df)), random_state=42)\n",
"for idx, row in sample_villages.iterrows():\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" circle = CircleMarker(\n",
" location=(row['latitude'], row['longitude']),\n",
" radius=3,\n",
" color=color,\n",
" fill_color=color,\n",
" fill_opacity=0.4,\n",
" weight=1\n",
" )\n",
" m.add_layer(circle)\n",
"\n",
"# Widget pour k\n",
"k_slider = IntSlider(\n",
" value=5,\n",
" min=1,\n",
" max=20,\n",
" step=1,\n",
" description='k:',\n",
" continuous_update=False\n",
")\n",
"\n",
"# Zone de résultats\n",
"result_output = Output()\n",
"info_html = HTML(value=\"<p style='font-size:16px; padding:10px; background:#f0f0f0; border-radius:5px;'>👆 <b>Cliquez sur la carte pour classifier un point</b></p>\")\n",
"\n",
"# Variable globale pour stocker les coordonnées\n",
"current_coords = {'lat': None, 'lon': None}\n",
"\n",
"def update_classification(lat, lon, k):\n",
" \"\"\"Met à jour la classification et la visualisation.\"\"\"\n",
" # Effacer les couches précédentes\n",
" test_point_layer.clear_layers()\n",
" neighbors_layer.clear_layers()\n",
" lines_layer.clear_layers()\n",
" \n",
" # Classification\n",
" prediction, neighbors, votes = knn_classify(lat, lon, df, k=k)\n",
" \n",
" # Couleur selon prédiction\n",
" color = 'red' if prediction == '2A' else 'blue'\n",
" dept_name = 'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'\n",
" \n",
" # Marqueur du point test\n",
" icon = AwesomeIcon(\n",
" name='star',\n",
" marker_color='darkred' if prediction == '2A' else 'darkblue',\n",
" icon_color='white'\n",
" )\n",
" test_marker = Marker(location=(lat, lon), icon=icon, draggable=False)\n",
" test_point_layer.add_layer(test_marker)\n",
" \n",
" # Afficher les k plus proches voisins\n",
" for idx, neighbor in neighbors.iterrows():\n",
" n_color = 'red' if neighbor['departement'] == '2A' else 'blue'\n",
" \n",
" # Marqueur du voisin\n",
" n_marker = CircleMarker(\n",
" location=(neighbor['latitude'], neighbor['longitude']),\n",
" radius=8,\n",
" color=n_color,\n",
" fill_color=n_color,\n",
" fill_opacity=0.7,\n",
" weight=2\n",
" )\n",
" neighbors_layer.add_layer(n_marker)\n",
" \n",
" # Ligne vers le voisin\n",
" line = Polyline(\n",
" locations=[\n",
" (lat, lon),\n",
" (neighbor['latitude'], neighbor['longitude'])\n",
" ],\n",
" color=n_color,\n",
" weight=2,\n",
" opacity=0.5\n",
" )\n",
" lines_layer.add_layer(line)\n",
" \n",
" # Afficher les résultats\n",
" with result_output:\n",
" clear_output(wait=True)\n",
" print(f\"📍 Coordonnées : ({lat:.4f}, {lon:.4f})\")\n",
" print(f\"🔢 k = {k}\")\n",
" print(f\"\\n🎯 Prédiction : {dept_name}\")\n",
" print(f\"📊 Votes : 2A={votes.get('2A', 0)}, 2B={votes.get('2B', 0)}\")\n",
" print(f\"\\n🏘 Les {k} plus proches villages :\")\n",
" print(neighbors[['village', 'nom_corse', 'departement', 'distance']].to_string(index=False))\n",
" \n",
" # Mettre à jour l'info\n",
" info_html.value = f\"<div style='font-size:16px; padding:10px; background:{'#ffebee' if prediction=='2A' else '#e3f2fd'}; border-radius:5px; border-left: 4px solid {color};'><b>Classification : {dept_name}</b><br>Votes : 2A={votes.get('2A', 0)}, 2B={votes.get('2B', 0)}</div>\"\n",
"\n",
"def handle_click(**kwargs):\n",
" \"\"\"Gestionnaire de clic sur la carte.\"\"\"\n",
" if kwargs.get('type') == 'click':\n",
" coords = kwargs.get('coordinates')\n",
" lat, lon = coords\n",
" current_coords['lat'] = lat\n",
" current_coords['lon'] = lon\n",
" update_classification(lat, lon, k_slider.value)\n",
"\n",
"def on_k_change(change):\n",
" \"\"\"Gestionnaire de changement de k.\"\"\"\n",
" if current_coords['lat'] is not None:\n",
" update_classification(current_coords['lat'], current_coords['lon'], change['new'])\n",
"\n",
"# Connecter les événements\n",
"m.on_interaction(handle_click)\n",
"k_slider.observe(on_k_change, names='value')\n",
"\n",
"# Afficher l'interface\n",
"display(VBox([\n",
" info_html,\n",
" HBox([Label('Nombre de voisins (k):'), k_slider]),\n",
" m,\n",
" result_output\n",
"]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎯 Points d'intérêt à tester\n",
"\n",
"Essayez de cliquer sur ces zones :\n",
"\n",
"- **Ajaccio** : (41.9267, 8.7369) - Capitale 2A\n",
"- **Bastia** : (42.7028, 9.4500) - Préfecture 2B\n",
"- **Corte** : (42.3062, 9.1509) - Centre de la Corse\n",
"- **Frontière approximative** : Zone entre 42.0 et 42.3 latitude\n",
"\n",
"### Questions à explorer :\n",
"1. 🤔 Où se situe la \"frontière\" k-NN entre les deux départements ?\n",
"2. 📊 Comment k influence-t-il la classification près de cette frontière ?\n",
"3. 🏔️ Y a-t-il des zones ambiguës où le résultat change souvent ?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 Mode manuel (si la carte ne fonctionne pas)\n",
"\n",
"Si le clic sur carte ne fonctionne pas, utilisez cette cellule :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Mode manuel : entrez les coordonnées\n",
"test_lat = 42.3 # Modifiez ici\n",
"test_lon = 9.15 # Modifiez ici\n",
"k = 5\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
"dept_name = 'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'\n",
"\n",
"print(f\"📍 Point : ({test_lat}, {test_lon})\")\n",
"print(f\"🎯 Prédiction : {dept_name}\")\n",
"print(f\"📊 Votes : {dict(votes)}\")\n",
"print(f\"\\n🏘 Les {k} plus proches villages :\")\n",
"print(neighbors[['village', 'nom_corse', 'departement', 'distance']].to_string(index=False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📝 Notes techniques\n",
"\n",
"Cette version utilise **ipyleaflet** qui offre une vraie interactivité bidirectionnelle entre Python et JavaScript dans Jupyter.\n",
"\n",
"**Avantages :**\n",
"- ✅ Clic directement sur la carte\n",
"- ✅ Mise à jour en temps réel\n",
"- ✅ Curseur interactif pour k\n",
"- ✅ Pas besoin de recharger\n",
"\n",
"**Prérequis :**\n",
"- Jupyter Notebook ou JupyterLab\n",
"- Extension widgets activée : `jupyter nbextension enable --py widgetsnbextension`"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View file

@ -0,0 +1,744 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 🗺️ Classification k-NN : Haute-Corse ou Corse du Sud ?\n",
"\n",
"## Objectif\n",
"Utiliser l'algorithme des **k plus proches voisins (k-NN)** pour déterminer si un point de la carte de Corse se situe en **Haute-Corse (2B)** ou en **Corse du Sud (2A)**, en se basant sur les villages les plus proches.\n",
"\n",
"## Principe\n",
"1. On charge les données des villages corses avec leurs coordonnées GPS et leur département\n",
"2. On choisit un point sur la carte\n",
"3. On calcule les distances entre ce point et tous les villages\n",
"4. On identifie les k villages les plus proches\n",
"5. On vote : le département majoritaire parmi ces k villages devient la prédiction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📦 Installation et imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques nécessaires (si besoin)\n",
"import sys\n",
"!{sys.executable} -m pip install folium pandas numpy -q"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import folium\n",
"from folium.plugins import MarkerCluster\n",
"import math\n",
"import json\n",
"from collections import Counter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📊 Chargement des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Charger le fichier CSV\n",
"# Remplacez 'villages_corse.csv' par le chemin de votre fichier\n",
"df = pd.read_csv('villages_corse.csv', sep='\\t', encoding='utf-8')\n",
"\n",
"# Afficher les premières lignes\n",
"print(f\"Nombre de villages : {len(df)}\")\n",
"print(f\"\\nColonnes : {list(df.columns)}\")\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🔧 Préparation des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def parse_coordinates(point_geo_str):\n",
" \"\"\"\n",
" Parse la colonne Point_Geo pour extraire latitude et longitude.\n",
" Format attendu : \"latitude, longitude\"\n",
" Exemple : \"41.984099158, 8.798384636\"\n",
" \"\"\"\n",
" try:\n",
" # Séparer par la virgule\n",
" parts = str(point_geo_str).split(',')\n",
" lat = float(parts[0].strip())\n",
" lon = float(parts[1].strip())\n",
" return lat, lon\n",
" except Exception as e:\n",
" print(f\"Erreur parsing: {point_geo_str} - {e}\")\n",
" return None, None\n",
"\n",
"# Extraire les coordonnées\n",
"df[['latitude', 'longitude']] = df['Point_Geo'].apply(\n",
" lambda x: pd.Series(parse_coordinates(x))\n",
")\n",
"\n",
"# Supprimer les lignes sans coordonnées valides\n",
"df = df.dropna(subset=['latitude', 'longitude'])\n",
"\n",
"# Simplifier les noms de départements\n",
"df['dept_simple'] = df['Code Département'].apply(lambda x: '2A' if str(x) == '2A' else '2B')\n",
"\n",
"print(f\"Villages avec coordonnées valides : {len(df)}\")\n",
"print(f\"\\nRépartition par département :\")\n",
"print(df['dept_simple'].value_counts())\n",
"\n",
"df[['Nom français', 'dept_simple', 'latitude', 'longitude']].head(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📏 Fonction de calcul de distance\n",
"\n",
"Nous utilisons la **formule de Haversine** pour calculer la distance entre deux points GPS sur la surface de la Terre."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def haversine_distance(lat1, lon1, lat2, lon2):\n",
" \"\"\"\n",
" Calcule la distance en kilomètres entre deux points GPS.\n",
" Formule de Haversine.\n",
" \"\"\"\n",
" R = 6371 # Rayon de la Terre en km\n",
" \n",
" # Conversion en radians\n",
" lat1_rad = math.radians(lat1)\n",
" lat2_rad = math.radians(lat2)\n",
" delta_lat = math.radians(lat2 - lat1)\n",
" delta_lon = math.radians(lon2 - lon1)\n",
" \n",
" # Formule de Haversine\n",
" a = math.sin(delta_lat/2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2\n",
" c = 2 * math.asin(math.sqrt(a))\n",
" \n",
" return R * c\n",
"\n",
"# Test de la fonction\n",
"# Distance entre Ajaccio (41.9267, 8.7369) et Bastia (42.7028, 9.4500)\n",
"dist_test = haversine_distance(41.9267, 8.7369, 42.7028, 9.4500)\n",
"print(f\"Distance Ajaccio-Bastia : {dist_test:.1f} km\")\n",
"\n",
"# Test avec Afa et Alando (vos exemples)\n",
"afa = df[df['Nom français'] == 'Afa'].iloc[0]\n",
"alando = df[df['Nom français'] == 'Alando'].iloc[0]\n",
"dist_afa_alando = haversine_distance(afa['latitude'], afa['longitude'], \n",
" alando['latitude'], alando['longitude'])\n",
"print(f\"Distance Afa-Alando : {dist_afa_alando:.1f} km\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎯 Algorithme k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def knn_classify(test_lat, test_lon, df, k=5):\n",
" \"\"\"\n",
" Classifie un point (test_lat, test_lon) en utilisant k-NN.\n",
" \n",
" Retourne :\n",
" - prediction : le département prédit ('2A' ou '2B')\n",
" - neighbors : DataFrame des k plus proches voisins\n",
" - votes : dictionnaire des votes\n",
" \"\"\"\n",
" # Calculer les distances pour tous les villages\n",
" distances = []\n",
" for idx, row in df.iterrows():\n",
" dist = haversine_distance(test_lat, test_lon, row['latitude'], row['longitude'])\n",
" distances.append({\n",
" 'village': row['Nom français'],\n",
" 'nom_corse': row['Nom corse'],\n",
" 'departement': row['dept_simple'],\n",
" 'latitude': row['latitude'],\n",
" 'longitude': row['longitude'],\n",
" 'distance': dist\n",
" })\n",
" \n",
" # Créer un DataFrame et trier par distance\n",
" dist_df = pd.DataFrame(distances)\n",
" dist_df = dist_df.sort_values('distance')\n",
" \n",
" # Sélectionner les k plus proches\n",
" neighbors = dist_df.head(k)\n",
" \n",
" # Voter\n",
" votes = Counter(neighbors['departement'])\n",
" prediction = votes.most_common(1)[0][0]\n",
" \n",
" return prediction, neighbors, votes\n",
"\n",
"# Test de l'algorithme avec un point au centre de la Corse\n",
"test_lat, test_lon = 42.15, 9.05\n",
"k = 5\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
"\n",
"print(f\"\\n🎯 Point de test : ({test_lat}, {test_lon})\")\n",
"print(f\"\\nAvec k={k} :\")\n",
"print(f\"Prédiction : {'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'}\")\n",
"print(f\"Votes : {dict(votes)}\")\n",
"print(f\"\\nLes {k} plus proches voisins :\")\n",
"print(neighbors[['village', 'nom_corse', 'departement', 'distance']])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🗺️ Visualisation avec Folium"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def create_map(test_lat=None, test_lon=None, k=5, show_all_villages=False, show_boundaries=False):\n",
" \"\"\"\n",
" Crée une carte interactive avec Folium.\n",
" \n",
" Paramètres:\n",
" - test_lat, test_lon: coordonnées du point à tester\n",
" - k: nombre de voisins\n",
" - show_all_villages: afficher tous les villages\n",
" - show_boundaries: afficher les frontières des communes (peut être lent)\n",
" \"\"\"\n",
" # Centre de la Corse\n",
" center_lat = 42.15\n",
" center_lon = 9.05\n",
" \n",
" # Créer la carte\n",
" m = folium.Map(\n",
" location=[center_lat, center_lon],\n",
" zoom_start=9,\n",
" tiles='OpenStreetMap'\n",
" )\n",
" \n",
" # Afficher les frontières des communes (optionnel)\n",
" if show_boundaries:\n",
" print(\"Affichage des frontières des communes...\")\n",
" for idx, row in df.iterrows():\n",
" try:\n",
" zone_geo = json.loads(row['Zone_geo'])\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" \n",
" folium.GeoJson(\n",
" zone_geo,\n",
" style_function=lambda x, color=color: {\n",
" 'fillColor': color,\n",
" 'color': color,\n",
" 'weight': 1,\n",
" 'fillOpacity': 0.1\n",
" },\n",
" tooltip=row['Nom français']\n",
" ).add_to(m)\n",
" except:\n",
" pass\n",
" \n",
" # Afficher tous les villages (optionnel)\n",
" if show_all_villages:\n",
" marker_cluster = MarkerCluster().add_to(m)\n",
" \n",
" for idx, row in df.iterrows():\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" folium.CircleMarker(\n",
" location=[row['latitude'], row['longitude']],\n",
" radius=3,\n",
" color=color,\n",
" fill=True,\n",
" fillColor=color,\n",
" fillOpacity=0.4,\n",
" popup=f\"<b>{row['Nom français']}</b><br>{row['Nom corse']}<br>({row['dept_simple']})\"\n",
" ).add_to(marker_cluster)\n",
" \n",
" # Si un point de test est fourni\n",
" if test_lat is not None and test_lon is not None:\n",
" # Classification\n",
" prediction, neighbors, votes = knn_classify(test_lat, test_lon, df, k=k)\n",
" \n",
" # Marqueur pour le point de test\n",
" color = 'darkred' if prediction == '2A' else 'darkblue'\n",
" dept_name = 'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'\n",
" \n",
" folium.Marker(\n",
" location=[test_lat, test_lon],\n",
" popup=f\"<b>Point à classifier</b><br>Prédiction : {dept_name}<br>Votes : {dict(votes)}\",\n",
" icon=folium.Icon(color=color, icon='star', prefix='fa')\n",
" ).add_to(m)\n",
" \n",
" # Afficher les k plus proches voisins\n",
" for idx, neighbor in neighbors.iterrows():\n",
" # Marqueur pour chaque voisin\n",
" color = 'red' if neighbor['departement'] == '2A' else 'blue'\n",
" folium.Marker(\n",
" location=[neighbor['latitude'], neighbor['longitude']],\n",
" popup=f\"<b>{neighbor['village']}</b><br>{neighbor['nom_corse']}<br>{neighbor['departement']}<br>Distance: {neighbor['distance']:.2f} km\",\n",
" icon=folium.Icon(color=color, icon='info-sign')\n",
" ).add_to(m)\n",
" \n",
" # Ligne entre le point test et le voisin\n",
" folium.PolyLine(\n",
" locations=[\n",
" [test_lat, test_lon],\n",
" [neighbor['latitude'], neighbor['longitude']]\n",
" ],\n",
" color=color,\n",
" weight=2,\n",
" opacity=0.5,\n",
" tooltip=f\"{neighbor['distance']:.2f} km\"\n",
" ).add_to(m)\n",
" \n",
" # Légende\n",
" legend_html = '''\n",
" <div style=\"position: fixed; \n",
" bottom: 50px; right: 50px; width: 220px; height: 130px; \n",
" background-color: white; border:2px solid grey; z-index:9999; \n",
" font-size:14px; padding: 10px\">\n",
" <p><strong>Légende</strong></p>\n",
" <p><i class=\"fa fa-circle\" style=\"color:red\"></i> Corse du Sud (2A)</p>\n",
" <p><i class=\"fa fa-circle\" style=\"color:blue\"></i> Haute-Corse (2B)</p>\n",
" <p><i class=\"fa fa-star\" style=\"color:darkred\"></i> Point à classifier</p>\n",
" </div>\n",
" '''\n",
" m.get_root().html.add_child(folium.Element(legend_html))\n",
" \n",
" return m\n",
"\n",
"# Créer la carte avec le point de test\n",
"map_with_test = create_map(test_lat=42.15, test_lon=9.05, k=5, show_all_villages=False)\n",
"map_with_test"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🔬 Expérimentation : Influence de k"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Test avec différentes valeurs de k\n",
"test_point = (42.15, 9.05) # Point au centre de la Corse\n",
"\n",
"print(f\"Point testé : {test_point}\\n\")\n",
"print(f\"{'k':<5} {'Prédiction':<15} {'Votes 2A':<10} {'Votes 2B':<10}\")\n",
"print(\"-\" * 50)\n",
"\n",
"for k in [1, 3, 5, 7, 9, 15, 21]:\n",
" prediction, neighbors, votes = knn_classify(test_point[0], test_point[1], df, k=k)\n",
" votes_2a = votes.get('2A', 0)\n",
" votes_2b = votes.get('2B', 0)\n",
" dept_name = 'Corse du Sud' if prediction == '2A' else 'Haute-Corse'\n",
" print(f\"{k:<5} {dept_name:<15} {votes_2a:<10} {votes_2b:<10}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎮 Mode interactif : Testez vos propres points !\n",
"\n",
"Modifiez les coordonnées ci-dessous pour tester différents points de la Corse.\n",
"\n",
"**Quelques repères géographiques :**\n",
"- Ajaccio : (41.9267, 8.7369)\n",
"- Bastia : (42.7028, 9.4500)\n",
"- Corte : (42.3062, 9.1509)\n",
"- Porto-Vecchio : (41.5914, 9.2795)\n",
"- Calvi : (42.5679, 8.7575)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# === MODIFIEZ CES VALEURS ===\n",
"test_latitude = 42.3 # Entre 41.3 (sud) et 43.0 (nord)\n",
"test_longitude = 9.15 # Entre 8.5 (ouest) et 9.5 (est)\n",
"k_value = 7 # Nombre de voisins\n",
"# =============================\n",
"\n",
"prediction, neighbors, votes = knn_classify(test_latitude, test_longitude, df, k=k_value)\n",
"\n",
"print(f\"📍 Point : ({test_latitude}, {test_longitude})\")\n",
"print(f\"🔢 k = {k_value}\")\n",
"print(f\"\\n🎯 Prédiction : {'Corse du Sud (2A)' if prediction == '2A' else 'Haute-Corse (2B)'}\")\n",
"print(f\"\\n📊 Votes : {dict(votes)}\")\n",
"print(f\"\\n🏘 Les {k_value} plus proches villages :\")\n",
"print(neighbors[['village', 'nom_corse', 'departement', 'distance']].to_string(index=False))\n",
"\n",
"# Afficher la carte\n",
"map_interactive = create_map(test_latitude, test_longitude, k=k_value, show_all_villages=False)\n",
"map_interactive"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🌍 Carte complète avec tous les villages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Afficher tous les villages de Corse\n",
"# Note : cette cellule peut prendre quelques secondes à s'exécuter\n",
"\n",
"map_all = create_map(show_all_villages=True, show_boundaries=False)\n",
"map_all"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🗺️ Carte avec frontières des communes (BONUS)\n",
"\n",
"Cette cellule affiche les frontières réelles des communes. **Attention : cela peut prendre du temps à charger !**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Carte avec frontières - peut être lent !\n",
"# Décommentez la ligne suivante pour l'exécuter\n",
"# map_boundaries = create_map(test_lat=42.15, test_lon=9.05, k=5, show_boundaries=True)\n",
"# map_boundaries"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📈 Visualisation de la frontière de décision"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Créer une grille de points et classifier chacun\n",
"# Cela permet de visualiser la \"frontière\" selon k-NN\n",
"\n",
"def create_decision_boundary_map(k=5, grid_resolution=40):\n",
" \"\"\"\n",
" Crée une carte montrant la frontière de décision de k-NN.\n",
" \"\"\"\n",
" # Limites de la Corse\n",
" lat_min, lat_max = 41.3, 43.0\n",
" lon_min, lon_max = 8.5, 9.6\n",
" \n",
" # Créer une grille\n",
" lats = np.linspace(lat_min, lat_max, grid_resolution)\n",
" lons = np.linspace(lon_min, lon_max, grid_resolution)\n",
" \n",
" m = folium.Map(\n",
" location=[42.15, 9.05],\n",
" zoom_start=8,\n",
" tiles='OpenStreetMap'\n",
" )\n",
" \n",
" # Classifier chaque point de la grille\n",
" print(f\"Classification d'une grille de {grid_resolution}x{grid_resolution} points...\")\n",
" total = len(lats) * len(lons)\n",
" count = 0\n",
" \n",
" for lat in lats:\n",
" for lon in lons:\n",
" prediction, _, _ = knn_classify(lat, lon, df, k=k)\n",
" color = '#ffcccc' if prediction == '2A' else '#ccccff'\n",
" \n",
" folium.CircleMarker(\n",
" location=[lat, lon],\n",
" radius=4,\n",
" color=color,\n",
" fill=True,\n",
" fillColor=color,\n",
" fillOpacity=0.3,\n",
" weight=0\n",
" ).add_to(m)\n",
" \n",
" count += 1\n",
" if count % 100 == 0:\n",
" print(f\" {count}/{total} points traités ({100*count/total:.1f}%)\")\n",
" \n",
" print(\"Terminé !\")\n",
" \n",
" # Ajouter les villages\n",
" for idx, row in df.iterrows():\n",
" color = 'red' if row['dept_simple'] == '2A' else 'blue'\n",
" folium.CircleMarker(\n",
" location=[row['latitude'], row['longitude']],\n",
" radius=2,\n",
" color=color,\n",
" fill=True,\n",
" fillColor=color,\n",
" fillOpacity=0.8,\n",
" popup=row['Nom français']\n",
" ).add_to(m)\n",
" \n",
" return m\n",
"\n",
"# Créer la carte (réduire grid_resolution si c'est trop lent)\n",
"print(f\"Création de la carte de frontière avec k=5...\")\n",
"print(\"Note : cela peut prendre 1-2 minutes...\")\n",
"boundary_map = create_decision_boundary_map(k=5, grid_resolution=30)\n",
"boundary_map"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 Validation de l'algorithme"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# BONUS : Validation croisée\n",
"# Tester la précision en utilisant les villages eux-mêmes\n",
"\n",
"def cross_validation(df, k=5, sample_size=100):\n",
" \"\"\"\n",
" Teste la précision de k-NN en utilisant un échantillon de villages.\n",
" \"\"\"\n",
" # Prendre un échantillon aléatoire\n",
" sample = df.sample(n=min(sample_size, len(df)), random_state=42)\n",
" \n",
" correct = 0\n",
" total = 0\n",
" errors = []\n",
" \n",
" for idx, row in sample.iterrows():\n",
" # Créer un dataset sans ce village\n",
" df_without = df.drop(idx)\n",
" \n",
" # Classifier ce village\n",
" prediction, neighbors, votes = knn_classify(\n",
" row['latitude'], \n",
" row['longitude'], \n",
" df_without, \n",
" k=k\n",
" )\n",
" \n",
" if prediction == row['dept_simple']:\n",
" correct += 1\n",
" else:\n",
" errors.append({\n",
" 'village': row['Nom français'],\n",
" 'vrai_dept': row['dept_simple'],\n",
" 'prediction': prediction,\n",
" 'votes': dict(votes)\n",
" })\n",
" total += 1\n",
" \n",
" accuracy = (correct / total) * 100\n",
" return accuracy, correct, total, errors\n",
"\n",
"print(\"Test de précision de l'algorithme k-NN...\\n\")\n",
"print(\"Validation croisée : chaque village est classifié en fonction de ses voisins.\\n\")\n",
"\n",
"for k in [1, 3, 5, 10, 15]:\n",
" accuracy, correct, total, errors = cross_validation(df, k=k, sample_size=100)\n",
" print(f\"k={k:2d} : {accuracy:.1f}% de précision ({correct}/{total} corrects)\")\n",
"\n",
"# Afficher quelques erreurs pour k=5\n",
"print(\"\\n📋 Exemples d'erreurs avec k=5 :\")\n",
"_, _, _, errors_k5 = cross_validation(df, k=5, sample_size=100)\n",
"if errors_k5:\n",
" for error in errors_k5[:5]:\n",
" print(f\" • {error['village']} : prédit {error['prediction']} (vrai: {error['vrai_dept']}) - votes: {error['votes']}\")\n",
"else:\n",
" print(\" Aucune erreur !\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 🎓 Questions de réflexion\n",
"\n",
"1. **Influence de k** : Comment la prédiction change-t-elle avec différentes valeurs de k ?\n",
"\n",
"2. **Points frontières** : Trouvez des coordonnées où la classification est ambiguë (votes proches).\n",
"\n",
"3. **Zones problématiques** : Où se situent les villages difficiles à classifier correctement ?\n",
"\n",
"4. **Validité géographique** : Cette méthode respecte-t-elle toujours les vraies frontières administratives ?\n",
"\n",
"5. **Améliorations** : Comment pourrait-on améliorer l'algorithme ?\n",
" - Pondération par distance inverse\n",
" - Prise en compte d'autres critères (altitude, population...)\n",
" - k adaptatif selon la densité de villages"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 💡 Exercices supplémentaires\n",
"\n",
"1. **Trouver la frontière** : Trouvez des points sur la \"frontière\" k-NN (là où un changement de k change la classification)\n",
"\n",
"2. **Villages isolés** : Identifiez les villages dont le département diffère de leurs k plus proches voisins\n",
"\n",
"3. **Pondération** : Implémentez une version pondérée où les villages plus proches ont plus d'influence\n",
"\n",
"4. **Comparaison** : Comparez la frontière k-NN avec la vraie frontière administrative"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# EXERCICE : Villages \"anomaliques\"\n",
"# Trouver les villages dont les k plus proches voisins sont majoritairement de l'autre département\n",
"\n",
"def find_anomalous_villages(df, k=5):\n",
" \"\"\"\n",
" Trouve les villages qui seraient mal classifiés par k-NN.\n",
" \"\"\"\n",
" anomalies = []\n",
" \n",
" for idx, row in df.iterrows():\n",
" # Créer un dataset sans ce village\n",
" df_without = df.drop(idx)\n",
" \n",
" # Classifier ce village\n",
" prediction, neighbors, votes = knn_classify(\n",
" row['latitude'], \n",
" row['longitude'], \n",
" df_without, \n",
" k=k\n",
" )\n",
" \n",
" # Si la prédiction ne correspond pas au vrai département\n",
" if prediction != row['dept_simple']:\n",
" anomalies.append({\n",
" 'village': row['Nom français'],\n",
" 'nom_corse': row['Nom corse'],\n",
" 'vrai_dept': row['dept_simple'],\n",
" 'prediction': prediction,\n",
" 'votes_2A': votes.get('2A', 0),\n",
" 'votes_2B': votes.get('2B', 0),\n",
" 'latitude': row['latitude'],\n",
" 'longitude': row['longitude']\n",
" })\n",
" \n",
" return pd.DataFrame(anomalies)\n",
"\n",
"print(\"Recherche des villages 'anomaliques' avec k=5...\\n\")\n",
"anomalies_df = find_anomalous_villages(df, k=5)\n",
"\n",
"print(f\"Nombre de villages anomaliques : {len(anomalies_df)}\")\n",
"print(f\"\\nVillages qui seraient classifiés dans le mauvais département :\\n\")\n",
"print(anomalies_df[['village', 'nom_corse', 'vrai_dept', 'prediction', 'votes_2A', 'votes_2B']])\n",
"\n",
"# Afficher ces villages sur une carte\n",
"if len(anomalies_df) > 0:\n",
" m_anomalies = folium.Map(location=[42.15, 9.05], zoom_start=9)\n",
" \n",
" for idx, row in anomalies_df.iterrows():\n",
" folium.Marker(\n",
" location=[row['latitude'], row['longitude']],\n",
" popup=f\"<b>{row['village']}</b><br>Vrai: {row['vrai_dept']}<br>Prédit: {row['prediction']}<br>Votes: {row['votes_2A']}-{row['votes_2B']}\",\n",
" icon=folium.Icon(color='orange', icon='exclamation-triangle', prefix='fa')\n",
" ).add_to(m_anomalies)\n",
" \n",
" display(m_anomalies)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,688 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Classification des Micro-régions de Corse par K-NN\n",
"\n",
"Ce notebook implémente un système de classification des micro-régions corses basé sur l'algorithme des k plus proches voisins (k-NN). Cliquez sur la carte pour identifier la micro-région correspondante.\n",
"\n",
"**Fichiers nécessaires :**\n",
"- `communes-de-corse-en-corse-et-francais.csv` : Liste des communes avec coordonnées GPS\n",
"- `communes-par-territoire-de-projet-de-la-collectivite-territoriale-de-corse0.csv` : Territoires de projet par commune"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques nécessaires\n",
"!pip install folium pandas numpy scikit-learn --quiet"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import folium\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"from IPython.display import display, HTML\n",
"import json\n",
"import re"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Chargement et préparation des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Chargement du fichier avec les coordonnées GPS\n",
"df_coords = pd.read_csv('communes-de-corse-en-corse-et-francais.csv', \n",
" sep=';', encoding='utf-8')\n",
"\n",
"print(f\"Fichier coordonnées: {len(df_coords)} communes\")\n",
"print(\"\\nPremières lignes:\")\n",
"display(df_coords.head())\n",
"print(\"\\nColonnes disponibles:\")\n",
"print(df_coords.columns.tolist())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Chargement du fichier avec les territoires de projet\n",
"df_territoires = pd.read_csv('communes-par-territoire-de-projet-de-la-collectivite-territoriale-de-corse0.csv',\n",
" sep=';', encoding='utf-8')\n",
"\n",
"print(f\"Fichier territoires: {len(df_territoires)} communes\")\n",
"print(\"\\nPremières lignes:\")\n",
"display(df_territoires.head())\n",
"print(\"\\nTerritoires de projet (micro-régions):\")\n",
"print(sorted(df_territoires['Territoire de projet'].unique()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Extraction des coordonnées GPS"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def extract_coordinates(point_geo_str):\n",
" \"\"\"\n",
" Extrait latitude et longitude de la colonne Point_Geo\n",
" Format attendu: \"41.984099158, 8.798384636\"\n",
" \"\"\"\n",
" if pd.isna(point_geo_str):\n",
" return None, None\n",
" \n",
" try:\n",
" # Supprimer les espaces et split par virgule\n",
" coords = str(point_geo_str).strip().split(',')\n",
" if len(coords) == 2:\n",
" lat = float(coords[0].strip())\n",
" lon = float(coords[1].strip())\n",
" return lat, lon\n",
" except:\n",
" pass\n",
" \n",
" return None, None\n",
"\n",
"# Extraction des coordonnées\n",
"df_coords[['Latitude', 'Longitude']] = df_coords['Point_Geo'].apply(\n",
" lambda x: pd.Series(extract_coordinates(x))\n",
")\n",
"\n",
"# Vérification\n",
"print(\"Extraction des coordonnées:\")\n",
"print(f\"Communes avec coordonnées: {df_coords['Latitude'].notna().sum()}/{len(df_coords)}\")\n",
"print(\"\\nExemple:\")\n",
"display(df_coords[['Nom français', 'Latitude', 'Longitude']].head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Fusion des deux fichiers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Normalisation des noms de communes pour la jointure\n",
"def normalize_commune_name(name):\n",
" \"\"\"\n",
" Normalise le nom d'une commune pour faciliter la jointure\n",
" \"\"\"\n",
" if pd.isna(name):\n",
" return ''\n",
" # Convertir en majuscules et supprimer les espaces multiples\n",
" return str(name).upper().strip()\n",
"\n",
"df_coords['Commune_norm'] = df_coords['Nom français'].apply(normalize_commune_name)\n",
"df_territoires['Commune_norm'] = df_territoires['Commune'].apply(normalize_commune_name)\n",
"\n",
"# Fusion des deux dataframes\n",
"df = pd.merge(\n",
" df_coords,\n",
" df_territoires[['Commune_norm', 'Territoire de projet']],\n",
" on='Commune_norm',\n",
" how='inner'\n",
")\n",
"\n",
"# Renommer pour cohérence\n",
"df['Commune'] = df['Nom français']\n",
"\n",
"print(f\"Fusion réussie: {len(df)} communes avec coordonnées ET territoire de projet\")\n",
"print(\"\\nAperçu des données fusionnées:\")\n",
"display(df[['Commune', 'Latitude', 'Longitude', 'Territoire de projet']].head(10))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Nettoyage: supprimer les lignes sans coordonnées\n",
"df_clean = df.dropna(subset=['Latitude', 'Longitude', 'Territoire de projet']).copy()\n",
"\n",
"print(f\"\\n✅ Données finales: {len(df_clean)} communes prêtes pour la classification\")\n",
"print(f\"\\nRépartition par micro-région:\")\n",
"print(df_clean['Territoire de projet'].value_counts().sort_index())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Entraînement du modèle k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Préparation des données pour k-NN\n",
"X = df_clean[['Latitude', 'Longitude']].values\n",
"y = df_clean['Territoire de projet'].values\n",
"\n",
"# Création du modèle k-NN avec k=5 (ajustable)\n",
"k = 5\n",
"knn = KNeighborsClassifier(n_neighbors=k, weights='distance', metric='haversine')\n",
"\n",
"# Conversion des coordonnées en radians pour la distance haversine\n",
"X_rad = np.radians(X)\n",
"\n",
"# Entraînement du modèle\n",
"knn.fit(X_rad, y)\n",
"\n",
"print(f\"✅ Modèle k-NN entraîné avec k={k} voisins\")\n",
"print(f\"📊 Nombre de micro-régions: {len(np.unique(y))}\")\n",
"print(f\"\\n🗺 Micro-régions identifiées:\")\n",
"for i, region in enumerate(sorted(np.unique(y)), 1):\n",
" count = (y == region).sum()\n",
" print(f\" {i:2d}. {region} ({count} communes)\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Création de la carte interactive avec Folium"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Couleurs pour chaque micro-région\n",
"microregions = sorted(df_clean['Territoire de projet'].unique())\n",
"colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', \n",
" 'lightred', 'beige', 'darkblue', 'darkgreen', 'cadetblue', \n",
" 'darkpurple', 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']\n",
"\n",
"color_map = {region: colors[i % len(colors)] for i, region in enumerate(microregions)}\n",
"\n",
"print(\"🎨 Carte des couleurs par micro-région:\")\n",
"for region, color in sorted(color_map.items()):\n",
" print(f\" • {region}: {color}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Coordonnées du centre de la Corse\n",
"center_lat = df_clean['Latitude'].mean()\n",
"center_lon = df_clean['Longitude'].mean()\n",
"\n",
"print(f\"Centre de la carte: {center_lat:.4f}°N, {center_lon:.4f}°E\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Carte interactive avec prédiction au clic"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Création de la carte interactive\n",
"m_interactive = folium.Map(\n",
" location=[center_lat, center_lon],\n",
" zoom_start=9,\n",
" tiles='OpenStreetMap'\n",
")\n",
"\n",
"# Ajout des marqueurs pour chaque commune\n",
"for idx, row in df_clean.iterrows():\n",
" folium.CircleMarker(\n",
" location=[row['Latitude'], row['Longitude']],\n",
" radius=3,\n",
" popup=f\"<b>{row['Commune']}</b><br>{row['Territoire de projet']}<br><small>({row['Latitude']:.4f}, {row['Longitude']:.4f})</small>\",\n",
" tooltip=row['Commune'],\n",
" color=color_map[row['Territoire de projet']],\n",
" fill=True,\n",
" fillColor=color_map[row['Territoire de projet']],\n",
" fillOpacity=0.7\n",
" ).add_to(m_interactive)\n",
"\n",
"# Préparer les données des communes pour JavaScript\n",
"communes_data = df_clean[['Latitude', 'Longitude', 'Commune', 'Territoire de projet']].to_dict('records')\n",
"\n",
"# JavaScript pour la prédiction k-NN au clic\n",
"click_js = f\"\"\"\n",
"<script>\n",
"// Données des communes\n",
"var communesData = {json.dumps(communes_data)};\n",
"\n",
"// Carte des couleurs\n",
"var colorMap = {json.dumps(color_map)};\n",
"\n",
"// Fonction pour calculer la distance haversine\n",
"function haversineDistance(lat1, lon1, lat2, lon2) {{\n",
" const R = 6371; // Rayon de la Terre en km\n",
" const dLat = (lat2 - lat1) * Math.PI / 180;\n",
" const dLon = (lon2 - lon1) * Math.PI / 180;\n",
" const a = Math.sin(dLat/2) * Math.sin(dLat/2) +\n",
" Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *\n",
" Math.sin(dLon/2) * Math.sin(dLon/2);\n",
" const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\n",
" return R * c;\n",
"}}\n",
"\n",
"// Fonction k-NN\n",
"function predictRegion(lat, lon, k) {{\n",
" // Calculer les distances\n",
" var distances = communesData.map(function(commune) {{\n",
" return {{\n",
" distance: haversineDistance(lat, lon, commune.Latitude, commune.Longitude),\n",
" region: commune['Territoire de projet'],\n",
" commune: commune.Commune\n",
" }};\n",
" }});\n",
" \n",
" // Trier par distance\n",
" distances.sort((a, b) => a.distance - b.distance);\n",
" \n",
" // Prendre les k plus proches\n",
" var kNearest = distances.slice(0, k);\n",
" \n",
" // Vote pondéré par l'inverse de la distance\n",
" var votes = {{}};\n",
" kNearest.forEach(function(neighbor) {{\n",
" var weight = 1 / (neighbor.distance + 0.001); // +0.001 pour éviter division par 0\n",
" if (votes[neighbor.region]) {{\n",
" votes[neighbor.region] += weight;\n",
" }} else {{\n",
" votes[neighbor.region] = weight;\n",
" }}\n",
" }});\n",
" \n",
" // Trouver la région gagnante\n",
" var maxVote = 0;\n",
" var predictedRegion = '';\n",
" for (var region in votes) {{\n",
" if (votes[region] > maxVote) {{\n",
" maxVote = votes[region];\n",
" predictedRegion = region;\n",
" }}\n",
" }}\n",
" \n",
" return {{\n",
" region: predictedRegion,\n",
" neighbors: kNearest\n",
" }};\n",
"}}\n",
"\n",
"// Variable pour stocker le marqueur de prédiction\n",
"var predictionMarker = null;\n",
"var neighborLines = [];\n",
"\n",
"// Attendre que la carte soit chargée\n",
"setTimeout(function() {{\n",
" var maps = document.querySelectorAll('.folium-map');\n",
" if (maps.length > 0) {{\n",
" var mapElement = maps[maps.length - 1];\n",
" var leafletMap = mapElement._leaflet_map;\n",
" \n",
" if (leafletMap) {{\n",
" leafletMap.on('click', function(e) {{\n",
" var lat = e.latlng.lat;\n",
" var lon = e.latlng.lng;\n",
" \n",
" // Prédiction avec k={k}\n",
" var result = predictRegion(lat, lon, {k});\n",
" \n",
" // Supprimer l'ancien marqueur et lignes\n",
" if (predictionMarker) {{\n",
" leafletMap.removeLayer(predictionMarker);\n",
" }}\n",
" neighborLines.forEach(function(line) {{\n",
" leafletMap.removeLayer(line);\n",
" }});\n",
" neighborLines = [];\n",
" \n",
" // Créer le popup avec informations détaillées\n",
" var popupContent = '<div style=\"min-width: 200px;\">' +\n",
" '<h4 style=\"margin: 5px 0; color: ' + colorMap[result.region] + ';\">🎯 ' + result.region + '</h4>' +\n",
" '<p style=\"margin: 5px 0; font-size: 11px;\"><b>Coordonnées cliquées:</b><br>' + \n",
" 'Lat: ' + lat.toFixed(5) + '°<br>Lon: ' + lon.toFixed(5) + '°</p>' +\n",
" '<hr style=\"margin: 5px 0;\">' +\n",
" '<p style=\"margin: 5px 0; font-size: 11px;\"><b>{k} plus proches communes:</b></p>' +\n",
" '<ul style=\"margin: 5px 0; padding-left: 20px; font-size: 10px;\">';\n",
" \n",
" result.neighbors.forEach(function(neighbor, i) {{\n",
" popupContent += '<li><b>' + neighbor.commune + '</b> (' + neighbor.distance.toFixed(2) + ' km)</li>';\n",
" }});\n",
" \n",
" popupContent += '</ul></div>';\n",
" \n",
" // Ajouter le nouveau marqueur\n",
" predictionMarker = L.marker([lat, lon], {{\n",
" icon: L.divIcon({{\n",
" className: 'prediction-marker',\n",
" html: '<div style=\"background-color: ' + colorMap[result.region] + \n",
" '; width: 20px; height: 20px; border-radius: 50%; ' +\n",
" 'border: 3px solid white; box-shadow: 0 0 10px rgba(0,0,0,0.5);\"></div>',\n",
" iconSize: [20, 20]\n",
" }})\n",
" }}).addTo(leafletMap);\n",
" \n",
" predictionMarker.bindPopup(popupContent, {{maxWidth: 300}}).openPopup();\n",
" \n",
" // Ajouter des lignes vers les k plus proches voisins\n",
" result.neighbors.forEach(function(neighbor) {{\n",
" var commune = communesData.find(c => c.Commune === neighbor.commune);\n",
" if (commune) {{\n",
" var line = L.polyline(\n",
" [[lat, lon], [commune.Latitude, commune.Longitude]],\n",
" {{\n",
" color: 'gray',\n",
" weight: 1,\n",
" opacity: 0.5,\n",
" dashArray: '5, 5'\n",
" }}\n",
" ).addTo(leafletMap);\n",
" neighborLines.push(line);\n",
" }}\n",
" }});\n",
" }});\n",
" \n",
" console.log('✅ Gestionnaire de clic k-NN activé');\n",
" console.log('📊 ' + communesData.length + ' communes chargées');\n",
" }}\n",
" }}\n",
"}}, 1000);\n",
"</script>\n",
"\"\"\"\n",
"\n",
"m_interactive.get_root().html.add_child(folium.Element(click_js))\n",
"\n",
"# Ajout de la légende\n",
"legend_html = '''\n",
"<div style=\"position: fixed; \n",
" top: 10px; right: 10px; width: 250px; max-height: 85vh; overflow-y: auto;\n",
" background-color: white; border:2px solid grey; z-index:9999; border-radius: 5px;\n",
" font-size:12px; padding: 10px; box-shadow: 0 0 15px rgba(0,0,0,0.2);\">\n",
"<p style=\"margin-bottom: 8px; font-weight: bold; font-size: 14px;\">🗺️ Micro-régions de Corse</p>\n",
"'''\n",
"\n",
"for region, color in sorted(color_map.items()):\n",
" legend_html += f'<p style=\"margin: 3px 0;\"><i class=\"fa fa-circle\" style=\"color:{color}\"></i> {region}</p>'\n",
"\n",
"legend_html += f'<hr style=\"margin: 8px 0;\"><p style=\"margin: 3px 0; font-size: 11px; color: #666;\">k = {k} voisins<br>Distance: Haversine</p></div>'\n",
"\n",
"m_interactive.get_root().html.add_child(folium.Element(legend_html))\n",
"\n",
"# Ajout d'instructions\n",
"instructions_html = '''\n",
"<div style=\"position: fixed; \n",
" bottom: 10px; left: 10px; width: 320px; \n",
" background-color: white; border:2px solid grey; z-index:9999; border-radius: 5px;\n",
" font-size:13px; padding: 12px; box-shadow: 0 0 15px rgba(0,0,0,0.2);\">\n",
"<p style=\"margin: 0 0 8px 0; font-weight: bold;\">🖱️ Mode d'emploi</p>\n",
"<p style=\"margin: 5px 0; line-height: 1.4;\"><b>Cliquez</b> n'importe où sur la carte pour prédire la micro-région.</p>\n",
"<p style=\"margin: 5px 0; line-height: 1.4; font-size: 11px;\">• Un marqueur coloré apparaît au point cliqué<br>\n",
"• Les lignes pointillées montrent les k communes les plus proches<br>\n",
"• Le popup affiche la prédiction détaillée</p>\n",
"</div>\n",
"'''\n",
"\n",
"m_interactive.get_root().html.add_child(folium.Element(instructions_html))\n",
"\n",
"print(\"\\n✅ Carte interactive créée avec succès!\")\n",
"print(f\"\\n🖱 Cliquez sur n'importe quel point de la carte pour prédire sa micro-région avec k={k} voisins.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Affichage de la carte interactive\n",
"m_interactive"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Sauvegarde de la carte"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sauvegarder la carte interactive\n",
"m_interactive.save('carte_corse_knn_interactive.html')\n",
"print(\"✅ Carte sauvegardée dans 'carte_corse_knn_interactive.html'\")\n",
"print(\"📁 Vous pouvez ouvrir ce fichier dans un navigateur pour une utilisation autonome.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Test de la prédiction (optionnel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fonction pour tester la prédiction sur des coordonnées spécifiques\n",
"def predict_region(lat, lon, k_value=5):\n",
" \"\"\"\n",
" Prédit la micro-région pour des coordonnées données\n",
" \"\"\"\n",
" # Conversion en radians\n",
" coords_rad = np.radians([[lat, lon]])\n",
" \n",
" # Prédiction\n",
" prediction = knn.predict(coords_rad)[0]\n",
" \n",
" # Trouver les k plus proches voisins\n",
" distances, indices = knn.kneighbors(coords_rad)\n",
" \n",
" # Convertir les distances de radians en km\n",
" distances_km = distances[0] * 6371 # Rayon de la Terre en km\n",
" \n",
" print(f\"\\n📍 Coordonnées: {lat:.5f}°N, {lon:.5f}°E\")\n",
" print(f\"🎯 Micro-région prédite: {prediction}\")\n",
" print(f\"\\n{k_value} plus proches communes:\")\n",
" \n",
" for i, idx in enumerate(indices[0]):\n",
" commune_info = df_clean.iloc[idx]\n",
" print(f\" {i+1}. {commune_info['Commune']:30s} ({commune_info['Territoire de projet']:30s}) - {distances_km[i]:6.2f} km\")\n",
" \n",
" return prediction\n",
"\n",
"# Exemples de test\n",
"print(\"=\" * 100)\n",
"print(\"TESTS DE PRÉDICTION k-NN\")\n",
"print(\"=\" * 100)\n",
"\n",
"# Test 1: Centre approximatif de la Corse (vers Corte)\n",
"print(\"\\n🔍 Test 1: Centre de la Corse\")\n",
"predict_region(42.15, 9.15, k)\n",
"\n",
"# Test 2: Nord de la Corse (Balagne/Bastia)\n",
"print(\"\\n🔍 Test 2: Nord de la Corse\")\n",
"predict_region(42.55, 8.85, k)\n",
"\n",
"# Test 3: Sud de la Corse (vers Porto-Vecchio)\n",
"print(\"\\n🔍 Test 3: Sud de la Corse\")\n",
"predict_region(41.65, 9.15, k)\n",
"\n",
"# Test 4: Ouest (vers Ajaccio)\n",
"print(\"\\n🔍 Test 4: Ouest de la Corse (Ajaccio)\")\n",
"predict_region(41.93, 8.74, k)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 9. Analyse de performance (optionnel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Évaluation de la cohérence du modèle (cross-validation)\n",
"from sklearn.model_selection import cross_val_score\n",
"\n",
"# Test avec différentes valeurs de k\n",
"k_values = [3, 5, 7, 9, 11, 15]\n",
"scores = []\n",
"\n",
"print(\"📊 Évaluation de la précision pour différentes valeurs de k:\\n\")\n",
"print(f\"{'k':<5} {'Précision moyenne':<20} {'Écart-type':<15}\")\n",
"print(\"-\" * 50)\n",
"\n",
"for k_val in k_values:\n",
" knn_temp = KNeighborsClassifier(n_neighbors=k_val, weights='distance', metric='haversine')\n",
" cv_scores = cross_val_score(knn_temp, X_rad, y, cv=5)\n",
" mean_score = cv_scores.mean()\n",
" std_score = cv_scores.std()\n",
" scores.append(mean_score)\n",
" print(f\"{k_val:<5} {mean_score:.4f} ({mean_score*100:5.2f}%) ± {std_score:.4f}\")\n",
"\n",
"best_k = k_values[scores.index(max(scores))]\n",
"best_score = max(scores)\n",
"print(\"\\n\" + \"=\" * 50)\n",
"print(f\"✨ Meilleure valeur de k: {best_k} (précision: {best_score:.4f} / {best_score*100:.2f}%)\")\n",
"print(\"=\" * 50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 10. Statistiques par micro-région"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Statistiques descriptives par micro-région\n",
"print(\"📈 STATISTIQUES PAR MICRO-RÉGION\\n\")\n",
"print(f\"{'Micro-région':<35} {'Nb communes':<15} {'% du total'}\")\n",
"print(\"=\" * 65)\n",
"\n",
"total_communes = len(df_clean)\n",
"stats = df_clean['Territoire de projet'].value_counts().sort_index()\n",
"\n",
"for region, count in stats.items():\n",
" pct = (count / total_communes) * 100\n",
" print(f\"{region:<35} {count:<15} {pct:>5.1f}%\")\n",
"\n",
"print(\"=\" * 65)\n",
"print(f\"{'TOTAL':<35} {total_communes:<15} 100.0%\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"✅ **Notebook k-NN Corse - Résumé**\n",
"\n",
"Ce notebook implémente un classificateur k-NN pour les micro-régions de Corse avec:\n",
"1. ✅ Chargement des données depuis 2 fichiers CSV (coordonnées + territoires)\n",
"2. ✅ Extraction automatique des coordonnées GPS depuis la colonne Point_Geo\n",
"3. ✅ Fusion intelligente des deux sources de données\n",
"4. ✅ Entraînement d'un modèle k-NN avec distance haversine\n",
"5. ✅ Carte interactive Folium avec prédiction au clic\n",
"6. ✅ Visualisation des k plus proches voisins\n",
"7. ✅ Tests de performance et validation\n",
"8. ✅ Export HTML pour utilisation autonome\n",
"\n",
"**🖱️ Utilisation:**\n",
"- Cliquez n'importe où sur la carte\n",
"- Un marqueur coloré apparaît avec la micro-région prédite\n",
"- Des lignes pointillées montrent les k communes les plus proches\n",
"- Un popup détaille la prédiction et les voisins\n",
"\n",
"**📁 Fichier exporté:** `carte_corse_knn_interactive.html`\n",
"\n",
"La carte HTML peut être ouverte dans n'importe quel navigateur pour une utilisation autonome!"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View file

@ -0,0 +1,620 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Classification des Micro-régions de Corse par K-NN\n",
"\n",
"Ce notebook implémente un système de classification des micro-régions corses basé sur l'algorithme des k plus proches voisins (k-NN). Cliquez sur la carte pour identifier la micro-région correspondante."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Installation des bibliothèques nécessaires\n",
"!pip install folium pandas numpy scikit-learn geopy --quiet"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import folium\n",
"from folium import plugins\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"from geopy.geocoders import Nominatim\n",
"from geopy.extra.rate_limiter import RateLimiter\n",
"import time\n",
"from IPython.display import display, HTML\n",
"import json"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Chargement et préparation des données"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Chargement du fichier CSV\n",
"df = pd.read_csv('communes-par-territoire-de-projet-de-la-collectivite-territoriale-de-corse0.csv', \n",
" sep=';', encoding='utf-8')\n",
"\n",
"print(f\"Nombre de communes: {len(df)}\")\n",
"print(\"\\nPremières lignes:\")\n",
"display(df.head())\n",
"print(\"\\nTerritoires de projet (micro-régions):\")\n",
"print(df['Territoire de projet'].unique())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Géocodage des communes\n",
"\n",
"Si le fichier ne contient pas déjà les coordonnées GPS, nous les récupérons via géocodage."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fonction pour obtenir les coordonnées GPS d'une commune\n",
"def geocode_commune(commune, departement, code_postal):\n",
" \"\"\"\n",
" Géocode une commune corse pour obtenir ses coordonnées GPS\n",
" \"\"\"\n",
" geolocator = Nominatim(user_agent=\"corse_knn_classifier\")\n",
" \n",
" try:\n",
" # Essai avec le nom de la commune et Corse\n",
" query = f\"{commune}, Corse, France\"\n",
" location = geolocator.geocode(query, timeout=10)\n",
" \n",
" if location:\n",
" return location.latitude, location.longitude\n",
" \n",
" # Essai avec le code postal\n",
" query = f\"{commune}, {code_postal}, France\"\n",
" location = geolocator.geocode(query, timeout=10)\n",
" \n",
" if location:\n",
" return location.latitude, location.longitude\n",
" \n",
" except Exception as e:\n",
" print(f\"Erreur pour {commune}: {e}\")\n",
" \n",
" return None, None\n",
"\n",
"# Vérifier si les colonnes GPS existent déjà\n",
"if 'Latitude' not in df.columns or 'Longitude' not in df.columns:\n",
" print(\"Géocodage des communes en cours... (cela peut prendre quelques minutes)\")\n",
" \n",
" # Géocodage avec rate limiting pour respecter les limites de l'API\n",
" latitudes = []\n",
" longitudes = []\n",
" \n",
" for idx, row in df.iterrows():\n",
" lat, lon = geocode_commune(row['Commune'], row['Département'], row['Code Postal'])\n",
" latitudes.append(lat)\n",
" longitudes.append(lon)\n",
" \n",
" # Affichage de la progression\n",
" if (idx + 1) % 10 == 0:\n",
" print(f\"Progression: {idx + 1}/{len(df)} communes géocodées\")\n",
" \n",
" # Pause pour respecter les limites de l'API\n",
" time.sleep(1.5)\n",
" \n",
" df['Latitude'] = latitudes\n",
" df['Longitude'] = longitudes\n",
" \n",
" # Sauvegarde du dataframe avec coordonnées\n",
" df.to_csv('communes_corse_avec_gps.csv', sep=';', index=False, encoding='utf-8')\n",
" print(\"\\nGéocodage terminé et sauvegardé dans 'communes_corse_avec_gps.csv'\")\n",
"else:\n",
" print(\"Les coordonnées GPS sont déjà présentes dans le fichier.\")\n",
"\n",
"# Supprimer les lignes sans coordonnées\n",
"df_clean = df.dropna(subset=['Latitude', 'Longitude']).copy()\n",
"print(f\"\\nCommunes avec coordonnées GPS: {len(df_clean)}/{len(df)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Entraînement du modèle k-NN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Préparation des données pour k-NN\n",
"X = df_clean[['Latitude', 'Longitude']].values\n",
"y = df_clean['Territoire de projet'].values\n",
"\n",
"# Création du modèle k-NN avec k=5 (ajustable)\n",
"k = 5\n",
"knn = KNeighborsClassifier(n_neighbors=k, weights='distance', metric='haversine')\n",
"\n",
"# Conversion des coordonnées en radians pour la distance haversine\n",
"X_rad = np.radians(X)\n",
"\n",
"# Entraînement du modèle\n",
"knn.fit(X_rad, y)\n",
"\n",
"print(f\"Modèle k-NN entraîné avec k={k} voisins\")\n",
"print(f\"Nombre de micro-régions: {len(np.unique(y))}\")\n",
"print(f\"Micro-régions: {sorted(np.unique(y))}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Création de la carte interactive avec Folium"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Couleurs pour chaque micro-région\n",
"microregions = sorted(df_clean['Territoire de projet'].unique())\n",
"colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', \n",
" 'lightred', 'beige', 'darkblue', 'darkgreen', 'cadetblue', \n",
" 'darkpurple', 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']\n",
"\n",
"color_map = {region: colors[i % len(colors)] for i, region in enumerate(microregions)}\n",
"\n",
"print(\"Carte des couleurs par micro-région:\")\n",
"for region, color in color_map.items():\n",
" print(f\" {region}: {color}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Coordonnées du centre de la Corse\n",
"center_lat = df_clean['Latitude'].mean()\n",
"center_lon = df_clean['Longitude'].mean()\n",
"\n",
"# Création de la carte\n",
"m = folium.Map(\n",
" location=[center_lat, center_lon],\n",
" zoom_start=9,\n",
" tiles='OpenStreetMap'\n",
")\n",
"\n",
"# Ajout des marqueurs pour chaque commune\n",
"for idx, row in df_clean.iterrows():\n",
" folium.CircleMarker(\n",
" location=[row['Latitude'], row['Longitude']],\n",
" radius=3,\n",
" popup=f\"<b>{row['Commune']}</b><br>{row['Territoire de projet']}\",\n",
" tooltip=row['Commune'],\n",
" color=color_map[row['Territoire de projet']],\n",
" fill=True,\n",
" fillColor=color_map[row['Territoire de projet']],\n",
" fillOpacity=0.7\n",
" ).add_to(m)\n",
"\n",
"# Ajout d'une légende\n",
"legend_html = '''\n",
"<div style=\"position: fixed; \n",
" top: 10px; right: 10px; width: 250px; height: auto; \n",
" background-color: white; border:2px solid grey; z-index:9999; \n",
" font-size:12px; padding: 10px\">\n",
"<p style=\"margin-bottom: 5px;\"><b>Micro-régions de Corse</b></p>\n",
"'''\n",
"\n",
"for region, color in sorted(color_map.items()):\n",
" legend_html += f'<p style=\"margin: 3px 0;\"><i class=\"fa fa-circle\" style=\"color:{color}\"></i> {region}</p>'\n",
"\n",
"legend_html += '</div>'\n",
"\n",
"m.get_root().html.add_child(folium.Element(legend_html))\n",
"\n",
"# Ajout du plugin de clic\n",
"# Note: Folium ne supporte pas nativement l'interactivité côté Python en temps réel\n",
"# Nous allons créer une version avec JavaScript pour la prédiction\n",
"\n",
"print(\"Carte de base créée avec les communes colorées par micro-région\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Carte interactive avec prédiction au clic\n",
"\n",
"Cette version utilise JavaScript pour permettre de cliquer sur la carte et afficher la micro-région prédite."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Création d'une nouvelle carte avec interaction JavaScript\n",
"m_interactive = folium.Map(\n",
" location=[center_lat, center_lon],\n",
" zoom_start=9,\n",
" tiles='OpenStreetMap'\n",
")\n",
"\n",
"# Ajout des communes\n",
"for idx, row in df_clean.iterrows():\n",
" folium.CircleMarker(\n",
" location=[row['Latitude'], row['Longitude']],\n",
" radius=3,\n",
" popup=f\"<b>{row['Commune']}</b><br>{row['Territoire de projet']}\",\n",
" tooltip=row['Commune'],\n",
" color=color_map[row['Territoire de projet']],\n",
" fill=True,\n",
" fillColor=color_map[row['Territoire de projet']],\n",
" fillOpacity=0.7\n",
" ).add_to(m_interactive)\n",
"\n",
"# Préparer les données des communes pour JavaScript\n",
"communes_data = df_clean[['Latitude', 'Longitude', 'Commune', 'Territoire de projet']].to_dict('records')\n",
"\n",
"# JavaScript pour la prédiction k-NN au clic\n",
"click_js = f\"\"\"\n",
"<script>\n",
"// Données des communes\n",
"var communesData = {json.dumps(communes_data)};\n",
"\n",
"// Carte des couleurs\n",
"var colorMap = {json.dumps(color_map)};\n",
"\n",
"// Fonction pour calculer la distance haversine\n",
"function haversineDistance(lat1, lon1, lat2, lon2) {{\n",
" const R = 6371; // Rayon de la Terre en km\n",
" const dLat = (lat2 - lat1) * Math.PI / 180;\n",
" const dLon = (lon2 - lon1) * Math.PI / 180;\n",
" const a = Math.sin(dLat/2) * Math.sin(dLat/2) +\n",
" Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *\n",
" Math.sin(dLon/2) * Math.sin(dLon/2);\n",
" const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\n",
" return R * c;\n",
"}}\n",
"\n",
"// Fonction k-NN\n",
"function predictRegion(lat, lon, k) {{\n",
" // Calculer les distances\n",
" var distances = communesData.map(function(commune) {{\n",
" return {{\n",
" distance: haversineDistance(lat, lon, commune.Latitude, commune.Longitude),\n",
" region: commune['Territoire de projet'],\n",
" commune: commune.Commune\n",
" }};\n",
" }});\n",
" \n",
" // Trier par distance\n",
" distances.sort((a, b) => a.distance - b.distance);\n",
" \n",
" // Prendre les k plus proches\n",
" var kNearest = distances.slice(0, k);\n",
" \n",
" // Vote pondéré par l'inverse de la distance\n",
" var votes = {{}};\n",
" kNearest.forEach(function(neighbor) {{\n",
" var weight = 1 / (neighbor.distance + 0.001); // +0.001 pour éviter division par 0\n",
" if (votes[neighbor.region]) {{\n",
" votes[neighbor.region] += weight;\n",
" }} else {{\n",
" votes[neighbor.region] = weight;\n",
" }}\n",
" }});\n",
" \n",
" // Trouver la région gagnante\n",
" var maxVote = 0;\n",
" var predictedRegion = '';\n",
" for (var region in votes) {{\n",
" if (votes[region] > maxVote) {{\n",
" maxVote = votes[region];\n",
" predictedRegion = region;\n",
" }}\n",
" }}\n",
" \n",
" return {{\n",
" region: predictedRegion,\n",
" neighbors: kNearest\n",
" }};\n",
"}}\n",
"\n",
"// Variable pour stocker le marqueur de prédiction\n",
"var predictionMarker = null;\n",
"var neighborLines = [];\n",
"\n",
"// Attendre que la carte soit chargée\n",
"setTimeout(function() {{\n",
" var maps = document.querySelectorAll('.folium-map');\n",
" if (maps.length > 0) {{\n",
" var mapElement = maps[maps.length - 1];\n",
" var leafletMap = mapElement._leaflet_map;\n",
" \n",
" if (leafletMap) {{\n",
" leafletMap.on('click', function(e) {{\n",
" var lat = e.latlng.lat;\n",
" var lon = e.latlng.lng;\n",
" \n",
" // Prédiction avec k={k}\n",
" var result = predictRegion(lat, lon, {k});\n",
" \n",
" // Supprimer l'ancien marqueur et lignes\n",
" if (predictionMarker) {{\n",
" leafletMap.removeLayer(predictionMarker);\n",
" }}\n",
" neighborLines.forEach(function(line) {{\n",
" leafletMap.removeLayer(line);\n",
" }});\n",
" neighborLines = [];\n",
" \n",
" // Créer le popup avec informations détaillées\n",
" var popupContent = '<div style=\"min-width: 200px;\">' +\n",
" '<h4 style=\"margin: 5px 0;\">Prédiction k-NN</h4>' +\n",
" '<p style=\"margin: 5px 0;\"><b>Micro-région:</b> ' + result.region + '</p>' +\n",
" '<p style=\"margin: 5px 0;\"><b>Coordonnées:</b><br>' + \n",
" 'Lat: ' + lat.toFixed(5) + '<br>Lon: ' + lon.toFixed(5) + '</p>' +\n",
" '<p style=\"margin: 5px 0;\"><b>{k} plus proches communes:</b></p>' +\n",
" '<ul style=\"margin: 5px 0; padding-left: 20px; font-size: 11px;\">';\n",
" \n",
" result.neighbors.forEach(function(neighbor) {{\n",
" popupContent += '<li>' + neighbor.commune + \n",
" ' (' + neighbor.distance.toFixed(2) + ' km)</li>';\n",
" }});\n",
" \n",
" popupContent += '</ul></div>';\n",
" \n",
" // Ajouter le nouveau marqueur\n",
" predictionMarker = L.marker([lat, lon], {{\n",
" icon: L.divIcon({{\n",
" className: 'prediction-marker',\n",
" html: '<div style=\"background-color: ' + colorMap[result.region] + \n",
" '; width: 20px; height: 20px; border-radius: 50%; ' +\n",
" 'border: 3px solid white; box-shadow: 0 0 10px rgba(0,0,0,0.5);\"></div>',\n",
" iconSize: [20, 20]\n",
" }})\n",
" }}).addTo(leafletMap);\n",
" \n",
" predictionMarker.bindPopup(popupContent).openPopup();\n",
" \n",
" // Ajouter des lignes vers les k plus proches voisins\n",
" result.neighbors.forEach(function(neighbor) {{\n",
" var commune = communesData.find(c => c.Commune === neighbor.commune);\n",
" if (commune) {{\n",
" var line = L.polyline(\n",
" [[lat, lon], [commune.Latitude, commune.Longitude]],\n",
" {{\n",
" color: 'gray',\n",
" weight: 1,\n",
" opacity: 0.5,\n",
" dashArray: '5, 5'\n",
" }}\n",
" ).addTo(leafletMap);\n",
" neighborLines.push(line);\n",
" }}\n",
" }});\n",
" }});\n",
" \n",
" console.log('Gestionnaire de clic k-NN activé');\n",
" }}\n",
" }}\n",
"}}, 1000);\n",
"</script>\n",
"\"\"\"\n",
"\n",
"m_interactive.get_root().html.add_child(folium.Element(click_js))\n",
"\n",
"# Ajout de la légende\n",
"m_interactive.get_root().html.add_child(folium.Element(legend_html))\n",
"\n",
"# Ajout d'instructions\n",
"instructions_html = '''\n",
"<div style=\"position: fixed; \n",
" bottom: 10px; left: 10px; width: 300px; \n",
" background-color: white; border:2px solid grey; z-index:9999; \n",
" font-size:13px; padding: 10px\">\n",
"<p style=\"margin: 0;\"><b>🖱️ Instructions:</b></p>\n",
"<p style=\"margin: 5px 0;\">Cliquez n'importe où sur la carte pour prédire la micro-région à partir de l'algorithme k-NN.</p>\n",
"<p style=\"margin: 5px 0;\">Les lignes pointillées montrent les k plus proches communes utilisées pour la prédiction.</p>\n",
"</div>\n",
"'''\n",
"\n",
"m_interactive.get_root().html.add_child(folium.Element(instructions_html))\n",
"\n",
"print(\"Carte interactive créée avec succès!\")\n",
"print(f\"\\nCliquez sur n'importe quel point de la carte pour prédire sa micro-région avec k={k} voisins.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Affichage de la carte interactive\n",
"m_interactive"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Sauvegarde de la carte"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sauvegarder la carte interactive\n",
"m_interactive.save('carte_corse_knn_interactive.html')\n",
"print(\"Carte sauvegardée dans 'carte_corse_knn_interactive.html'\")\n",
"print(\"Vous pouvez ouvrir ce fichier dans un navigateur pour une utilisation autonome.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Test de la prédiction (optionnel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Fonction pour tester la prédiction sur des coordonnées spécifiques\n",
"def predict_region(lat, lon, k_value=5):\n",
" \"\"\"\n",
" Prédit la micro-région pour des coordonnées données\n",
" \"\"\"\n",
" # Conversion en radians\n",
" coords_rad = np.radians([[lat, lon]])\n",
" \n",
" # Prédiction\n",
" prediction = knn.predict(coords_rad)[0]\n",
" \n",
" # Trouver les k plus proches voisins\n",
" distances, indices = knn.kneighbors(coords_rad)\n",
" \n",
" # Convertir les distances de radians en km\n",
" distances_km = distances[0] * 6371 # Rayon de la Terre en km\n",
" \n",
" print(f\"\\n📍 Coordonnées: {lat:.5f}, {lon:.5f}\")\n",
" print(f\"🎯 Micro-région prédite: {prediction}\")\n",
" print(f\"\\n{k_value} plus proches communes:\")\n",
" \n",
" for i, idx in enumerate(indices[0]):\n",
" commune_info = df_clean.iloc[idx]\n",
" print(f\" {i+1}. {commune_info['Commune']} ({commune_info['Territoire de projet']}) - {distances_km[i]:.2f} km\")\n",
" \n",
" return prediction\n",
"\n",
"# Exemples de test\n",
"print(\"=\" * 60)\n",
"print(\"TESTS DE PRÉDICTION\")\n",
"print(\"=\" * 60)\n",
"\n",
"# Test 1: Centre approximatif de la Corse\n",
"predict_region(42.15, 9.15, k)\n",
"\n",
"# Test 2: Nord de la Corse (Balagne)\n",
"predict_region(42.55, 8.85, k)\n",
"\n",
"# Test 3: Sud de la Corse\n",
"predict_region(41.65, 9.15, k)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Analyse de performance (optionnel)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Évaluation de la cohérence du modèle (cross-validation)\n",
"from sklearn.model_selection import cross_val_score\n",
"\n",
"# Test avec différentes valeurs de k\n",
"k_values = [3, 5, 7, 9, 11]\n",
"scores = []\n",
"\n",
"print(\"Évaluation de la précision pour différentes valeurs de k:\\n\")\n",
"\n",
"for k_val in k_values:\n",
" knn_temp = KNeighborsClassifier(n_neighbors=k_val, weights='distance', metric='haversine')\n",
" cv_scores = cross_val_score(knn_temp, X_rad, y, cv=5)\n",
" mean_score = cv_scores.mean()\n",
" scores.append(mean_score)\n",
" print(f\"k={k_val:2d}: Précision moyenne = {mean_score:.3f} (+/- {cv_scores.std():.3f})\")\n",
"\n",
"# Visualisation simple\n",
"print(f\"\\n✨ Meilleure valeur de k: {k_values[scores.index(max(scores))]} (précision: {max(scores):.3f})\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"Ce notebook implémente un classificateur k-NN pour les micro-régions de Corse avec:\n",
"- ✅ Chargement et géocodage des communes corses\n",
"- ✅ Entraînement d'un modèle k-NN avec distance haversine\n",
"- ✅ Carte interactive Folium avec prédiction au clic\n",
"- ✅ Visualisation des k plus proches voisins\n",
"- ✅ Légende et instructions pour l'utilisateur\n",
"\n",
"**Utilisation:**\n",
"1. Cliquez n'importe où sur la carte\n",
"2. Un marqueur coloré apparaît avec la micro-région prédite\n",
"3. Des lignes pointillées montrent les k communes les plus proches\n",
"4. Un popup détaille la prédiction et les voisins\n",
"\n",
"La carte HTML peut être ouverte dans n'importe quel navigateur pour une utilisation autonome!"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,361 @@
Code Postal;Commune;Canton;Département;Territoire de projet;CODE_REG;INSEE_COM
20224;ALBERTACCE;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B007
20212;ALZI;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B013
20225;AVAPESSA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B025
20228;BARRETTALI;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;94;2B030
20119;BASTELICA;BASTELICA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A031
20200;BASTIA;BASTIA;HAUTE-CORSE;PAYS BASTIAIS;94;2B033
20226;BELGODERE;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B034
20620;BIGUGLIA;BORGO;HAUTE-CORSE;PAYS BASTIAIS;94;2B037
20229;CAMPANA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B052
20290;CAMPILE;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;94;2B054
20130;CARGESE;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A065
20244;CARTICASI;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B068
20250;CASANOVA;VENACO;HAUTE-CORSE;CENTRE CORSE;94;2B074
20236;CASTIRLA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B083
20221;CERVIONE;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B087
20256;CORBARA;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B093
20167;CUTTOLI-CORTICCHIATO;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A103
20212;ERBAJOLO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B105
20244;ERONE;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B106
20253;FARINOLE;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;94;2B109
20245;GALERIA;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;94;2B121
20243;ISOLACCIO-DI-FIUMORBO;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B135
20244;LAVATOGGIO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B138
20224;LOZZI;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B147
20260;LUMIO;CALVI;HAUTE-CORSE;PAYS DE BALAGNE;;2B150
20112;MELA;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A158
20270;MOITA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B161
20218;MOLTIFAO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;;2B162
20239;MURATO;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B172
20225;NESSA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B175
20219;NOCETA;VEZZANI;HAUTE-CORSE;CENTRE CORSE;;2B177
20234;NOVALE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B179
20234;ORTALE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B194
20125;ORTO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A196
20150;OTA;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A198
20167;PERI;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A209
20230;PIETRA-DI-VERDE;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B225
20234;PIETRICAGGIO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B227
20250;POGGIO-DI-VENACO;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B238
20237;POGGIO-MARINACCIO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B241
20137;PORTO-VECCHIO;PORTO-VECCHIO;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A247
20218;PRATO-DI-GIOVELLINA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B248
20110;PROPRIANO;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A249
20290;PRUNELLI-DI-CASACCONI;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B250
20229;RAPAGGIO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B256
20217;SAINT-FLORENT;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B298
20121;SALICE;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A266
20243;SAN-GAVINO-DI-FIUMORBO;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B365
20230;SAN-GIOVANNI-DI-MORIANI;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B302
20244;SAN-LORENZO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B304
20230;SANTA-LUCIA-DI-MORIANI;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B307
20221;SANTA-MARIA-POGGIO;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B311
20190;SANTA-MARIA-SICHE;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A312
20230;TALASANI;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B319
20250;TRALONCA;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B329
20229;VALLE-D'OREZZA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B338
20240;VENTISERI;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B342
20110;VIGGIANELLO;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A349
20200;VILLE-DI-PIETRABUGNO;SAN-MARTINO-DI-LOTA;HAUTE-CORSE;PAYS BASTIAIS;;2B353
20116;ZERUBIA;TALLANO-SCOPAMENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A357
20173;ZEVACO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A358
20124;ZONZA;LEVIE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A362
20244;AITI;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B003
20212;ALANDO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B005
20167;ALATA;AJACCIO 7E CANTON;CORSE-DU-SUD;PAYS AJACCIEN;94;2A006
20251;ALTIANI;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B012
20270;ANTISANTI;VEZZANI;HAUTE-CORSE;PLAINE ORIENTALE;94;2B016
20167;APPIETTO;AJACCIO 7E CANTON;CORSE-DU-SUD;PAYS AJACCIEN;94;2A017
20140;ARGIUSTA-MORICCIO;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A021
20151;ARRO;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A022
20276;ASCO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B023
20121;AZZANA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A027
20169;BONIFACIO;BONIFACIO;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A041
20290;BORGO;BORGO;HAUTE-CORSE;PAYS BASTIAIS;94;2B042
20222;BRANDO;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;94;2B043
20212;BUSTANICO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B045
20224;CALACUCCIA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B047
20111;CALCATOGGIO;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A048
20142;CAMPO;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A056
20230;CANALE-DI-VERDE;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;94;2B057
20217;CANARI;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;94;2B058
20229;CARPINETO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B067
20111;CASAGLIONE;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A070
20225;CATERI;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B084
20160;COGGIA;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A090
20123;COGNOCOLI-MONTICCHI;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A091
20138;COTI-CHIAVARI;SANTA-MARIA-SICHE;CORSE-DU-SUD;PAYS AJACCIEN;94;2A098
20148;COZZANO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A099
20237;CROCE;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B101
20117;ECCICA-SUARELLA;BASTELICA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A104
20143;FOZZANO;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A118
20600;FURIANI;BASTIA (FURIANI-MONTESORO);HAUTE-CORSE;PAYS BASTIAIS;94;2B120
20218;GAVIGNANO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B122
20227;GHISONI;GHISONI;HAUTE-CORSE;PLAINE ORIENTALE;94;2B124
20100;GRANACE;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A128
20153;GUITERA-LES-BAINS;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A133
20220;LA PORTA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B246
20237;LAMA;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS DE BALAGNE;;2B136
20252;LETIA;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A141
20165;LORETO-DI-TALLANO;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A146
20290;LUCCIANA;BORGO;HAUTE-CORSE;PAYS BASTIAIS;;2B148
20228;LURI;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B152
20287;MERIA;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B159
20140;MOCA-CROCE;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A160
20218;MOROSAGLIA;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;;2B169
20225;MURO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B173
20117;OCANA;BASTELICA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A181
20217;OLCANI;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B184
20140;OLIVESE;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A186
20113;OLMETO;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A189
20112;OLMICCIA;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A191
20236;OMESSA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B193
20147;OSANI;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A197
20226;PALASCA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B199
20134;PALNECA;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A200
20251;PANCHERACCIA;BUSTANICO;HAUTE-CORSE;PLAINE ORIENTALE;;2B201
20251;PIEDICORTE-DI-GAGGIO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B218
20229;PIEDICROCE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B219
20218;PIEDIGRIGGIO;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B220
20251;PIETRASERENA;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B226
20166;PIETROSELLA;SANTA-MARIA-SICHE;CORSE-DU-SUD;PAYS AJACCIEN;94;2A228
20242;PIETROSO;VEZZANI;HAUTE-CORSE;PLAINE ORIENTALE;;2B229
20220;PIGNA;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;;2B231
20234;PIOBETTA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B234
20125;POGGIOLO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A240
20246;RAPALE;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B257
20247;ROGLIANO;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B261
20218;SALICETO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;;2B267
20213;SAN-GAVINO-D'AMPUGNANI;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B299
20230;SAN-GIULIANO;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B303
20200;SANTA-MARIA-DI-LOTA;SAN-MARTINO-DI-LOTA;HAUTE-CORSE;PAYS BASTIAIS;;2B309
20212;SANT'ANDREA-DI-BOZIO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B292
20151;SANT'ANDREA-D'ORCINO;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A295
20230;SANTA-REPARATA-DI-MORIANI;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B317
20246;SANTO-PIETRO-DI-TENDA;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B314
20145;SARI-SOLENZARA;PORTO-VECCHIO;CORSE-DU-SUD;PLAINE ORIENTALE;94;2A269
20140;SERRA-DI-FERRO;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A276
20240;SOLARO;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B283
20152;SORBOLLANO;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A285
20146;SOTTA;FIGARI;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A288
20226;SPELONCATO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B290
20270;TOX;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B328
20234;VALLE-D'ALESANI;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B334
20167;VALLE-DI-MEZZANA;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A336
20215;VENZOLASCA;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B343
20172;VERO;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A345
20167;VILLANOVA;AJACCIO 7E CANTON;CORSE-DU-SUD;PAYS AJACCIEN;94;2A351
20272;ZALANA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B356
20132;ZICAVO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A359
20214;ZILIA;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;;2B361
20167;AFA;AJACCIO 7E CANTON;CORSE-DU-SUD;PAYS AJACCIEN;94;2A001
20270;ALERIA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;94;2B009
20220;ALGAJOLA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B010
20160;ARBORI;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A019
20116;AULLENE;TALLANO-SCOPAMENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A024
20190;AZILONE-AMPAZA;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A026
20160;BALOGNA;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A028
20252;BIGORNO;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;94;2B036
20270;CAMPI;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;94;2B053
20252;CAMPITELLO;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;94;2B055
20170;CARBINI;LEVIE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A061
20133;CARBUCCIA;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A062
20164;CARGIACA;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A066
20237;CASABIANCA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B069
20140;CASALABRIVA;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A071
20270;CASEVECCHIE;VEZZANI;HAUTE-CORSE;PLAINE ORIENTALE;94;2B075
20218;CASTIFAO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B080
20238;CENTURI;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;94;2B086
20240;CHISA;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;94;2B366
20134;CIAMANNACCE;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A089
20226;COSTA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B097
20126;CRISTINACCE;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A100
20275;ERSA;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;94;2B107
20126;EVISA;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A108
20212;FAVALELLO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B110
20225;FELICETO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B112
20100;FOCE;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A115
20190;FORCIOLO;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A117
20240;GHISONACCIA;GHISONI;HAUTE-CORSE;PLAINE ORIENTALE;94;2B123
20160;GUAGNO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A131
20137;LENTO;ALTO-DI-CASACONI;HAUTE-CORSE;CENTRE CORSE;;2B140
20170;L'ILE-ROUSSE;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;;2B134
20215;LORETO-DI-CASINCA;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B145
20245;MANSO;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;;2B153
20141;MARIGNANA;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A154
20270;MATRA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B155
20259;MAUSOLEO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B156
20171;MONACIA-D'AULLENE;FIGARI;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A163
20229;MONACIA-D'OREZZA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B164
20229;NOCARIO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B176
20226;OCCHIATANA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B182
20217;OGLIASTRO;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B183
20290;ORTIPORIO;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B195
20229;PARATA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B202
20121;PASTRICCIOLA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A204
20272;PIANELLO;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B213
20215;PIANO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B214
20229;PIE-D'OREZZA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B222
20246;PIEVE;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B230
20123;PILA-CANALE;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A232
20229;POLVEROSO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B243
20218;POPOLASCA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B244
20215;PORRI;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B245
20243;PRUNELLI-DI-FIUMORBO;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B251
20122;QUENZA;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A254
20237;QUERCITELLO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B255
20121;REZZA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A259
20244;RUSIO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B264
20239;RUTALI;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B265
20213;SAN-DAMIANO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B297
20170;SAN-GAVINO-DI-CARBINI;LEVIE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A300
20230;SAN-NICOLAO;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B313
20250;SANTA-LUCIA-DI-MERCURIO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B306
20167;SARROLA-CARCOPINO;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A271
20243;SERRA-DI-FIUMORBO;PRUNELLI-DI-FIUMORBO;HAUTE-CORSE;PLAINE ORIENTALE;;2B277
20147;SERRIERA;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A279
20125;SOCCIA;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A282
20229;STAZZONA;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B291
20270;TALLONE;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B320
20234;TARRANO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B321
20134;TASSO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A322
20259;VALLICA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B339
20231;VENACO;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B341
20229;VERDESE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B344
20290;VOLPAJOLA;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B355
20190;ZIGLIARA;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A360
20112;ZOZA;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A363
20270;AGHIONE;VEZZANI;HAUTE-CORSE;PLAINE ORIENTALE;94;2B002
20112;ALTAGENE;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A011
20272;AMPRIANI;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;94;2B015
20110;ARBELLARA;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A018
20129;BASTELICACCIA;AJACCIO 7E CANTON;CORSE-DU-SUD;PAYS AJACCIEN;94;2A032
20110;BELVEDERE-CAMPOMORO;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A035
20100;BILIA;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A038
20228;CAGNANO;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;94;2B046
20235;CASTELLO-DI-ROSTINO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B079
20218;CASTIGLIONE;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B081
20117;CAURO;BASTELICA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A085
20230;CHIATRA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;94;2B088
20168;CORRANO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A094
20250;CORTE;CORTE;HAUTE-CORSE;CENTRE CORSE;94;2B096
20290;CROCICCHIA;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;94;2B102
20234;FELCE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B111
20114;FIGARI;FIGARI;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A114
20212;FOCICCHIA;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B116
20230;LINGUIZZETTA;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B143
20139;LOPIGNA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A144
20212;MAZZOLA;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B157
20214;MONCALE;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;;2B165
20290;MONTE;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B166
20214;MONTEGROSSO;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;;2B167
20238;MORSIGLIA;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B170
20219;MURACCIOLE;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B171
20217;NONZA;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B178
20226;NOVELLA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B180
20232;OLETTA;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B185
20232;OLMETA-DI-TUDA;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B188
20259;OLMI-CAPPELLA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B190
20290;OLMO;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B192
20147;PARTINELLO;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A203
20290;PENTA-ACQUATELLA;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B206
20230;PERO-CASEVECCHIE;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B210
20140;PETRETO-BICCHISANO;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A211
20131;PIANOTTOLI-CALDARELLO;FIGARI;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A215
20234;PIAZZALI;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B216
20229;PIEDIPARTINO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B221
20218;PIETRALBA;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS DE BALAGNE;;2B223
20240;POGGIO-DI-NAZZA;GHISONI;HAUTE-CORSE;PLAINE ORIENTALE;;2B236
20213;PRUNO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B252
20142;QUASQUARA;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A253
20160;RENNO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A258
20121;ROSAZIA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A262
20112;SAINTE-LUCIE-DE-TALLANO;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A308
20134;SAMPOLO;ZICAVO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A268
20246;SAN-GAVINO-DI-TENDA;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B301
20143;SANTA-MARIA-FIGANIELLA;OLMETO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A310
20221;SANT'ANDREA-DI-COTONE;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B293
20220;SANT'ANTONINO;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;;2B296
20220;SANTA-REPARATA-DI-BALAGNA;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;;2B316
20250;SANTO-PIETRO-DI-VENACO;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B315
20100;SARTENE;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A272
20290;SCOLCA;ALTO-DI-CASACONI;HAUTE-CORSE;PAYS BASTIAIS;;2B274
20215;SILVARECCIO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B280
20140;SOLLACARO;PETRETO-BICCHISANO;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A284
20117;TOLLA;BASTELICA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A326
20248;TOMINO;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B327
20232;VALLECALLE;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B333
20221;VALLE-DI-CAMPOLORO;CAMPOLORO-DI-MORIANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B335
20230;VELONE-ORNETO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B340
20215;VESCOVATO;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B346
20242;VEZZANI;VEZZANI;HAUTE-CORSE;PLAINE ORIENTALE;;2B347
20160;VICO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A348
20290;VIGNALE;BORGO;HAUTE-CORSE;PAYS BASTIAIS;;2B350
20279;VILLE-DI-PARASO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B352
20272;ZUANI;MOITA-VERDE;HAUTE-CORSE;PLAINE ORIENTALE;;2B364
20000;AJACCIO;AJACCIO;CORSE-DU-SUD;PAYS AJACCIEN;94;2A004
20128;ALBITRECCIA;SANTA-MARIA-SICHE;CORSE-DU-SUD;PAYS AJACCIEN;94;2A008
20151;AMBIEGNA;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A014
20220;AREGNO;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;94;2B020
20253;BARBAGGIO;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;94;2B029
20235;BISINCHI;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B039
20136;BOCOGNANO;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A040
20214;CALENZANA;CALENZANA;HAUTE-CORSE;PAYS DE BALAGNE;94;2B049
20260;CALVI;CALVI;HAUTE-CORSE;PAYS DE BALAGNE;94;2B050
20244;CAMBIA;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B051
20235;CANAVAGGIA;ALTO-DI-CASACONI;HAUTE-CORSE;CENTRE CORSE;94;2B059
20151;CANNELLE;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A060
20229;CARCHETO-BRUSTICO;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B063
20190;CARDO-TORGIA;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A064
20215;CASALTA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B072
20224;CASAMACCIOLI;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B073
20213;CASTELLARE-DI-CASINCA;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B077
20212;CASTELLARE-DI-MERCURIO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;94;2B078
20218;CASTINETA;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;94;2B082
20135;CONCA;PORTO-VECCHIO;CORSE-DU-SUD;PLAINE ORIENTALE;94;2A092
20224;CORSCIA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;94;2B095
20237;FICAJA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B113
20157;FRASSETO;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A119
20237;GIOCATOJO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;94;2B125
20251;GIUNCAGGIO;BUSTANICO;HAUTE-CORSE;PLAINE ORIENTALE;;2B126
20100;GIUNCHETO;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A127
20100;GROSSA;SARTENE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A129
20128;GROSSETO-PRUGNA;SANTA-MARIA-SICHE;CORSE-DU-SUD;PAYS AJACCIEN;94;2A130
20128;GUARGUALE;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A132
20218;LANO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B137
20225;LECCI;PORTO-VECCHIO;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A139
20160;LEVIE;LEVIE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A142
20240;LUGO-DI-NAZZA;GHISONI;HAUTE-CORSE;PLAINE ORIENTALE;;2B149
20220;MONTICELLO;L'ILE-ROUSSE;HAUTE-CORSE;PAYS DE BALAGNE;;2B168
20160;MURZO;LES DEUX-SORRU;CORSE-DU-SUD;OUEST CORSE;94;2A174
20217;OLMETA-DI-CAPOCORSO;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B187
20253;PATRIMONIO;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B205
20213;PENTA-DI-CASINCA;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B207
20234;PERELLI;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B208
20115;PIANA;LES DEUX-SEVI;CORSE-DU-SUD;OUEST CORSE;94;2A212
20229;PIAZZOLE;OREZZA-ALESANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B217
20233;PIETRACORBARA;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B224
20228;PINO;CAPOBIANCO;HAUTE-CORSE;PAYS BASTIAIS;;2B233
20259;PIOGGIOLA;BELGODERE;HAUTE-CORSE;PAYS DE BALAGNE;;2B235
20232;POGGIO-D'OLETTA;LA CONCA-D'ORO;HAUTE-CORSE;PAYS BASTIAIS;;2B239
20230;POGGIO-MEZZANA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B242
20250;RIVENTOSA;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B260
20219;ROSPIGLIANI;VEZZANI;HAUTE-CORSE;CENTRE CORSE;;2B263
20200;SAN-MARTINO-DI-LOTA;SAN-MARTINO-DI-LOTA;HAUTE-CORSE;PAYS BASTIAIS;;2B305
20151;SARI-D'ORCINO;CRUZINI-CINARCA;CORSE-DU-SUD;OUEST CORSE;94;2A270
20213;SCATA;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B273
20212;SERMANO;BUSTANICO;HAUTE-CORSE;CENTRE CORSE;;2B275
20127;SERRA-DI-SCOPAMENE;TALLANO-SCOPAMENE;CORSE-DU-SUD;EXTREME SUD / ALTA ROCCA;94;2A278
20233;SISCO;SAGRO-DI-SANTA-GIULIA;HAUTE-CORSE;PAYS BASTIAIS;;2B281
20213;SORBO-OCAGNANO;VESCOVATO;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B286
20246;SORIO;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS BASTIAIS;;2B287
20250;SOVERIA;NIOLU-OMESSA;HAUTE-CORSE;CENTRE CORSE;;2B289
20230;TAGLIO-ISOLACCIO;FIUMALTO-D'AMPUGNANI;HAUTE-CORSE;CASTAGNICCIA / MARE E MONTI;;2B318
20167;TAVACO;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A323
20163;TAVERA;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A324
20133;UCCIANI;CELAVO-MEZZANA;CORSE-DU-SUD;PAYS AJACCIEN;94;2A330
20128;URBALACONE;SANTA-MARIA-SICHE;CORSE-DU-SUD;TARAVO / VALINCO / SARTENAIS;94;2A331
20218;URTACA;LE HAUT-NEBBIO;HAUTE-CORSE;PAYS DE BALAGNE;;2B332
20235;VALLE-DI-ROSTINO;CASTIFAO-MOROSAGLIA;HAUTE-CORSE;CENTRE CORSE;;2B337
20219;VIVARIO;VENACO;HAUTE-CORSE;CENTRE CORSE;;2B354
1 Code Postal Commune Canton Département Territoire de projet CODE_REG INSEE_COM
2 20224 ALBERTACCE NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B007
3 20212 ALZI BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B013
4 20225 AVAPESSA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B025
5 20228 BARRETTALI CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 94 2B030
6 20119 BASTELICA BASTELICA CORSE-DU-SUD PAYS AJACCIEN 94 2A031
7 20200 BASTIA BASTIA HAUTE-CORSE PAYS BASTIAIS 94 2B033
8 20226 BELGODERE BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B034
9 20620 BIGUGLIA BORGO HAUTE-CORSE PAYS BASTIAIS 94 2B037
10 20229 CAMPANA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B052
11 20290 CAMPILE ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 94 2B054
12 20130 CARGESE LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A065
13 20244 CARTICASI BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B068
14 20250 CASANOVA VENACO HAUTE-CORSE CENTRE CORSE 94 2B074
15 20236 CASTIRLA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B083
16 20221 CERVIONE CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B087
17 20256 CORBARA L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 94 2B093
18 20167 CUTTOLI-CORTICCHIATO CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A103
19 20212 ERBAJOLO BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B105
20 20244 ERONE BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B106
21 20253 FARINOLE LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 94 2B109
22 20245 GALERIA CALENZANA HAUTE-CORSE PAYS DE BALAGNE 94 2B121
23 20243 ISOLACCIO-DI-FIUMORBO PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B135
24 20244 LAVATOGGIO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B138
25 20224 LOZZI NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B147
26 20260 LUMIO CALVI HAUTE-CORSE PAYS DE BALAGNE 2B150
27 20112 MELA TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A158
28 20270 MOITA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B161
29 20218 MOLTIFAO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 2B162
30 20239 MURATO LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B172
31 20225 NESSA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B175
32 20219 NOCETA VEZZANI HAUTE-CORSE CENTRE CORSE 2B177
33 20234 NOVALE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B179
34 20234 ORTALE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B194
35 20125 ORTO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A196
36 20150 OTA LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A198
37 20167 PERI CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A209
38 20230 PIETRA-DI-VERDE MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B225
39 20234 PIETRICAGGIO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B227
40 20250 POGGIO-DI-VENACO VENACO HAUTE-CORSE CENTRE CORSE 2B238
41 20237 POGGIO-MARINACCIO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B241
42 20137 PORTO-VECCHIO PORTO-VECCHIO CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A247
43 20218 PRATO-DI-GIOVELLINA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B248
44 20110 PROPRIANO OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A249
45 20290 PRUNELLI-DI-CASACCONI ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B250
46 20229 RAPAGGIO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B256
47 20217 SAINT-FLORENT LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B298
48 20121 SALICE CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A266
49 20243 SAN-GAVINO-DI-FIUMORBO PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B365
50 20230 SAN-GIOVANNI-DI-MORIANI CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B302
51 20244 SAN-LORENZO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B304
52 20230 SANTA-LUCIA-DI-MORIANI CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B307
53 20221 SANTA-MARIA-POGGIO CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B311
54 20190 SANTA-MARIA-SICHE SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A312
55 20230 TALASANI FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B319
56 20250 TRALONCA BUSTANICO HAUTE-CORSE CENTRE CORSE 2B329
57 20229 VALLE-D'OREZZA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B338
58 20240 VENTISERI PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B342
59 20110 VIGGIANELLO OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A349
60 20200 VILLE-DI-PIETRABUGNO SAN-MARTINO-DI-LOTA HAUTE-CORSE PAYS BASTIAIS 2B353
61 20116 ZERUBIA TALLANO-SCOPAMENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A357
62 20173 ZEVACO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A358
63 20124 ZONZA LEVIE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A362
64 20244 AITI BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B003
65 20212 ALANDO BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B005
66 20167 ALATA AJACCIO 7E CANTON CORSE-DU-SUD PAYS AJACCIEN 94 2A006
67 20251 ALTIANI BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B012
68 20270 ANTISANTI VEZZANI HAUTE-CORSE PLAINE ORIENTALE 94 2B016
69 20167 APPIETTO AJACCIO 7E CANTON CORSE-DU-SUD PAYS AJACCIEN 94 2A017
70 20140 ARGIUSTA-MORICCIO PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A021
71 20151 ARRO CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A022
72 20276 ASCO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B023
73 20121 AZZANA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A027
74 20169 BONIFACIO BONIFACIO CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A041
75 20290 BORGO BORGO HAUTE-CORSE PAYS BASTIAIS 94 2B042
76 20222 BRANDO SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 94 2B043
77 20212 BUSTANICO BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B045
78 20224 CALACUCCIA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B047
79 20111 CALCATOGGIO CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A048
80 20142 CAMPO SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A056
81 20230 CANALE-DI-VERDE MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 94 2B057
82 20217 CANARI SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 94 2B058
83 20229 CARPINETO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B067
84 20111 CASAGLIONE CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A070
85 20225 CATERI BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B084
86 20160 COGGIA LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A090
87 20123 COGNOCOLI-MONTICCHI SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A091
88 20138 COTI-CHIAVARI SANTA-MARIA-SICHE CORSE-DU-SUD PAYS AJACCIEN 94 2A098
89 20148 COZZANO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A099
90 20237 CROCE FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B101
91 20117 ECCICA-SUARELLA BASTELICA CORSE-DU-SUD PAYS AJACCIEN 94 2A104
92 20143 FOZZANO OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A118
93 20600 FURIANI BASTIA (FURIANI-MONTESORO) HAUTE-CORSE PAYS BASTIAIS 94 2B120
94 20218 GAVIGNANO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B122
95 20227 GHISONI GHISONI HAUTE-CORSE PLAINE ORIENTALE 94 2B124
96 20100 GRANACE SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A128
97 20153 GUITERA-LES-BAINS ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A133
98 20220 LA PORTA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B246
99 20237 LAMA LE HAUT-NEBBIO HAUTE-CORSE PAYS DE BALAGNE 2B136
100 20252 LETIA LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A141
101 20165 LORETO-DI-TALLANO TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A146
102 20290 LUCCIANA BORGO HAUTE-CORSE PAYS BASTIAIS 2B148
103 20228 LURI CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B152
104 20287 MERIA CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B159
105 20140 MOCA-CROCE PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A160
106 20218 MOROSAGLIA CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 2B169
107 20225 MURO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B173
108 20117 OCANA BASTELICA CORSE-DU-SUD PAYS AJACCIEN 94 2A181
109 20217 OLCANI SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B184
110 20140 OLIVESE PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A186
111 20113 OLMETO OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A189
112 20112 OLMICCIA TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A191
113 20236 OMESSA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B193
114 20147 OSANI LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A197
115 20226 PALASCA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B199
116 20134 PALNECA ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A200
117 20251 PANCHERACCIA BUSTANICO HAUTE-CORSE PLAINE ORIENTALE 2B201
118 20251 PIEDICORTE-DI-GAGGIO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B218
119 20229 PIEDICROCE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B219
120 20218 PIEDIGRIGGIO NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B220
121 20251 PIETRASERENA BUSTANICO HAUTE-CORSE CENTRE CORSE 2B226
122 20166 PIETROSELLA SANTA-MARIA-SICHE CORSE-DU-SUD PAYS AJACCIEN 94 2A228
123 20242 PIETROSO VEZZANI HAUTE-CORSE PLAINE ORIENTALE 2B229
124 20220 PIGNA L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 2B231
125 20234 PIOBETTA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B234
126 20125 POGGIOLO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A240
127 20246 RAPALE LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B257
128 20247 ROGLIANO CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B261
129 20218 SALICETO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 2B267
130 20213 SAN-GAVINO-D'AMPUGNANI FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B299
131 20230 SAN-GIULIANO CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B303
132 20200 SANTA-MARIA-DI-LOTA SAN-MARTINO-DI-LOTA HAUTE-CORSE PAYS BASTIAIS 2B309
133 20212 SANT'ANDREA-DI-BOZIO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B292
134 20151 SANT'ANDREA-D'ORCINO CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A295
135 20230 SANTA-REPARATA-DI-MORIANI CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B317
136 20246 SANTO-PIETRO-DI-TENDA LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B314
137 20145 SARI-SOLENZARA PORTO-VECCHIO CORSE-DU-SUD PLAINE ORIENTALE 94 2A269
138 20140 SERRA-DI-FERRO SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A276
139 20240 SOLARO PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B283
140 20152 SORBOLLANO TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A285
141 20146 SOTTA FIGARI CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A288
142 20226 SPELONCATO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B290
143 20270 TOX MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B328
144 20234 VALLE-D'ALESANI OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B334
145 20167 VALLE-DI-MEZZANA CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A336
146 20215 VENZOLASCA VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B343
147 20172 VERO CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A345
148 20167 VILLANOVA AJACCIO 7E CANTON CORSE-DU-SUD PAYS AJACCIEN 94 2A351
149 20272 ZALANA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B356
150 20132 ZICAVO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A359
151 20214 ZILIA CALENZANA HAUTE-CORSE PAYS DE BALAGNE 2B361
152 20167 AFA AJACCIO 7E CANTON CORSE-DU-SUD PAYS AJACCIEN 94 2A001
153 20270 ALERIA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 94 2B009
154 20220 ALGAJOLA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B010
155 20160 ARBORI LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A019
156 20116 AULLENE TALLANO-SCOPAMENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A024
157 20190 AZILONE-AMPAZA SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A026
158 20160 BALOGNA LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A028
159 20252 BIGORNO ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 94 2B036
160 20270 CAMPI MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 94 2B053
161 20252 CAMPITELLO ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 94 2B055
162 20170 CARBINI LEVIE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A061
163 20133 CARBUCCIA CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A062
164 20164 CARGIACA TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A066
165 20237 CASABIANCA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B069
166 20140 CASALABRIVA PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A071
167 20270 CASEVECCHIE VEZZANI HAUTE-CORSE PLAINE ORIENTALE 94 2B075
168 20218 CASTIFAO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B080
169 20238 CENTURI CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 94 2B086
170 20240 CHISA PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 94 2B366
171 20134 CIAMANNACCE ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A089
172 20226 COSTA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B097
173 20126 CRISTINACCE LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A100
174 20275 ERSA CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 94 2B107
175 20126 EVISA LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A108
176 20212 FAVALELLO BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B110
177 20225 FELICETO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B112
178 20100 FOCE SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A115
179 20190 FORCIOLO SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A117
180 20240 GHISONACCIA GHISONI HAUTE-CORSE PLAINE ORIENTALE 94 2B123
181 20160 GUAGNO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A131
182 20137 LENTO ALTO-DI-CASACONI HAUTE-CORSE CENTRE CORSE 2B140
183 20170 L'ILE-ROUSSE L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 2B134
184 20215 LORETO-DI-CASINCA VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B145
185 20245 MANSO CALENZANA HAUTE-CORSE PAYS DE BALAGNE 2B153
186 20141 MARIGNANA LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A154
187 20270 MATRA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B155
188 20259 MAUSOLEO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B156
189 20171 MONACIA-D'AULLENE FIGARI CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A163
190 20229 MONACIA-D'OREZZA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B164
191 20229 NOCARIO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B176
192 20226 OCCHIATANA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B182
193 20217 OGLIASTRO SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B183
194 20290 ORTIPORIO ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B195
195 20229 PARATA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B202
196 20121 PASTRICCIOLA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A204
197 20272 PIANELLO MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B213
198 20215 PIANO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B214
199 20229 PIE-D'OREZZA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B222
200 20246 PIEVE LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B230
201 20123 PILA-CANALE SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A232
202 20229 POLVEROSO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B243
203 20218 POPOLASCA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B244
204 20215 PORRI VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B245
205 20243 PRUNELLI-DI-FIUMORBO PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B251
206 20122 QUENZA TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A254
207 20237 QUERCITELLO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B255
208 20121 REZZA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A259
209 20244 RUSIO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B264
210 20239 RUTALI LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B265
211 20213 SAN-DAMIANO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B297
212 20170 SAN-GAVINO-DI-CARBINI LEVIE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A300
213 20230 SAN-NICOLAO CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B313
214 20250 SANTA-LUCIA-DI-MERCURIO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B306
215 20167 SARROLA-CARCOPINO CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A271
216 20243 SERRA-DI-FIUMORBO PRUNELLI-DI-FIUMORBO HAUTE-CORSE PLAINE ORIENTALE 2B277
217 20147 SERRIERA LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A279
218 20125 SOCCIA LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A282
219 20229 STAZZONA OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B291
220 20270 TALLONE MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B320
221 20234 TARRANO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B321
222 20134 TASSO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A322
223 20259 VALLICA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B339
224 20231 VENACO VENACO HAUTE-CORSE CENTRE CORSE 2B341
225 20229 VERDESE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B344
226 20290 VOLPAJOLA ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B355
227 20190 ZIGLIARA SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A360
228 20112 ZOZA TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A363
229 20270 AGHIONE VEZZANI HAUTE-CORSE PLAINE ORIENTALE 94 2B002
230 20112 ALTAGENE TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A011
231 20272 AMPRIANI MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 94 2B015
232 20110 ARBELLARA OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A018
233 20129 BASTELICACCIA AJACCIO 7E CANTON CORSE-DU-SUD PAYS AJACCIEN 94 2A032
234 20110 BELVEDERE-CAMPOMORO SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A035
235 20100 BILIA SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A038
236 20228 CAGNANO CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 94 2B046
237 20235 CASTELLO-DI-ROSTINO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B079
238 20218 CASTIGLIONE NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B081
239 20117 CAURO BASTELICA CORSE-DU-SUD PAYS AJACCIEN 94 2A085
240 20230 CHIATRA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 94 2B088
241 20168 CORRANO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A094
242 20250 CORTE CORTE HAUTE-CORSE CENTRE CORSE 94 2B096
243 20290 CROCICCHIA ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 94 2B102
244 20234 FELCE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B111
245 20114 FIGARI FIGARI CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A114
246 20212 FOCICCHIA BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B116
247 20230 LINGUIZZETTA MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B143
248 20139 LOPIGNA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A144
249 20212 MAZZOLA BUSTANICO HAUTE-CORSE CENTRE CORSE 2B157
250 20214 MONCALE CALENZANA HAUTE-CORSE PAYS DE BALAGNE 2B165
251 20290 MONTE ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B166
252 20214 MONTEGROSSO CALENZANA HAUTE-CORSE PAYS DE BALAGNE 2B167
253 20238 MORSIGLIA CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B170
254 20219 MURACCIOLE VENACO HAUTE-CORSE CENTRE CORSE 2B171
255 20217 NONZA SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B178
256 20226 NOVELLA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B180
257 20232 OLETTA LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B185
258 20232 OLMETA-DI-TUDA LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B188
259 20259 OLMI-CAPPELLA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B190
260 20290 OLMO ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B192
261 20147 PARTINELLO LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A203
262 20290 PENTA-ACQUATELLA ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B206
263 20230 PERO-CASEVECCHIE FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B210
264 20140 PETRETO-BICCHISANO PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A211
265 20131 PIANOTTOLI-CALDARELLO FIGARI CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A215
266 20234 PIAZZALI OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B216
267 20229 PIEDIPARTINO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B221
268 20218 PIETRALBA LE HAUT-NEBBIO HAUTE-CORSE PAYS DE BALAGNE 2B223
269 20240 POGGIO-DI-NAZZA GHISONI HAUTE-CORSE PLAINE ORIENTALE 2B236
270 20213 PRUNO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B252
271 20142 QUASQUARA SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A253
272 20160 RENNO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A258
273 20121 ROSAZIA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A262
274 20112 SAINTE-LUCIE-DE-TALLANO TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A308
275 20134 SAMPOLO ZICAVO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A268
276 20246 SAN-GAVINO-DI-TENDA LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B301
277 20143 SANTA-MARIA-FIGANIELLA OLMETO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A310
278 20221 SANT'ANDREA-DI-COTONE CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B293
279 20220 SANT'ANTONINO L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 2B296
280 20220 SANTA-REPARATA-DI-BALAGNA L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 2B316
281 20250 SANTO-PIETRO-DI-VENACO VENACO HAUTE-CORSE CENTRE CORSE 2B315
282 20100 SARTENE SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A272
283 20290 SCOLCA ALTO-DI-CASACONI HAUTE-CORSE PAYS BASTIAIS 2B274
284 20215 SILVARECCIO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B280
285 20140 SOLLACARO PETRETO-BICCHISANO CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A284
286 20117 TOLLA BASTELICA CORSE-DU-SUD PAYS AJACCIEN 94 2A326
287 20248 TOMINO CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B327
288 20232 VALLECALLE LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B333
289 20221 VALLE-DI-CAMPOLORO CAMPOLORO-DI-MORIANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B335
290 20230 VELONE-ORNETO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B340
291 20215 VESCOVATO VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B346
292 20242 VEZZANI VEZZANI HAUTE-CORSE PLAINE ORIENTALE 2B347
293 20160 VICO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A348
294 20290 VIGNALE BORGO HAUTE-CORSE PAYS BASTIAIS 2B350
295 20279 VILLE-DI-PARASO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B352
296 20272 ZUANI MOITA-VERDE HAUTE-CORSE PLAINE ORIENTALE 2B364
297 20000 AJACCIO AJACCIO CORSE-DU-SUD PAYS AJACCIEN 94 2A004
298 20128 ALBITRECCIA SANTA-MARIA-SICHE CORSE-DU-SUD PAYS AJACCIEN 94 2A008
299 20151 AMBIEGNA CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A014
300 20220 AREGNO BELGODERE HAUTE-CORSE PAYS DE BALAGNE 94 2B020
301 20253 BARBAGGIO LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 94 2B029
302 20235 BISINCHI CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B039
303 20136 BOCOGNANO CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A040
304 20214 CALENZANA CALENZANA HAUTE-CORSE PAYS DE BALAGNE 94 2B049
305 20260 CALVI CALVI HAUTE-CORSE PAYS DE BALAGNE 94 2B050
306 20244 CAMBIA BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B051
307 20235 CANAVAGGIA ALTO-DI-CASACONI HAUTE-CORSE CENTRE CORSE 94 2B059
308 20151 CANNELLE CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A060
309 20229 CARCHETO-BRUSTICO OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B063
310 20190 CARDO-TORGIA SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A064
311 20215 CASALTA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B072
312 20224 CASAMACCIOLI NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B073
313 20213 CASTELLARE-DI-CASINCA VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B077
314 20212 CASTELLARE-DI-MERCURIO BUSTANICO HAUTE-CORSE CENTRE CORSE 94 2B078
315 20218 CASTINETA CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 94 2B082
316 20135 CONCA PORTO-VECCHIO CORSE-DU-SUD PLAINE ORIENTALE 94 2A092
317 20224 CORSCIA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 94 2B095
318 20237 FICAJA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B113
319 20157 FRASSETO SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A119
320 20237 GIOCATOJO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 94 2B125
321 20251 GIUNCAGGIO BUSTANICO HAUTE-CORSE PLAINE ORIENTALE 2B126
322 20100 GIUNCHETO SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A127
323 20100 GROSSA SARTENE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A129
324 20128 GROSSETO-PRUGNA SANTA-MARIA-SICHE CORSE-DU-SUD PAYS AJACCIEN 94 2A130
325 20128 GUARGUALE SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A132
326 20218 LANO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B137
327 20225 LECCI PORTO-VECCHIO CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A139
328 20160 LEVIE LEVIE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A142
329 20240 LUGO-DI-NAZZA GHISONI HAUTE-CORSE PLAINE ORIENTALE 2B149
330 20220 MONTICELLO L'ILE-ROUSSE HAUTE-CORSE PAYS DE BALAGNE 2B168
331 20160 MURZO LES DEUX-SORRU CORSE-DU-SUD OUEST CORSE 94 2A174
332 20217 OLMETA-DI-CAPOCORSO SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B187
333 20253 PATRIMONIO LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B205
334 20213 PENTA-DI-CASINCA VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B207
335 20234 PERELLI OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B208
336 20115 PIANA LES DEUX-SEVI CORSE-DU-SUD OUEST CORSE 94 2A212
337 20229 PIAZZOLE OREZZA-ALESANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B217
338 20233 PIETRACORBARA SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B224
339 20228 PINO CAPOBIANCO HAUTE-CORSE PAYS BASTIAIS 2B233
340 20259 PIOGGIOLA BELGODERE HAUTE-CORSE PAYS DE BALAGNE 2B235
341 20232 POGGIO-D'OLETTA LA CONCA-D'ORO HAUTE-CORSE PAYS BASTIAIS 2B239
342 20230 POGGIO-MEZZANA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B242
343 20250 RIVENTOSA VENACO HAUTE-CORSE CENTRE CORSE 2B260
344 20219 ROSPIGLIANI VEZZANI HAUTE-CORSE CENTRE CORSE 2B263
345 20200 SAN-MARTINO-DI-LOTA SAN-MARTINO-DI-LOTA HAUTE-CORSE PAYS BASTIAIS 2B305
346 20151 SARI-D'ORCINO CRUZINI-CINARCA CORSE-DU-SUD OUEST CORSE 94 2A270
347 20213 SCATA FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B273
348 20212 SERMANO BUSTANICO HAUTE-CORSE CENTRE CORSE 2B275
349 20127 SERRA-DI-SCOPAMENE TALLANO-SCOPAMENE CORSE-DU-SUD EXTREME SUD / ALTA ROCCA 94 2A278
350 20233 SISCO SAGRO-DI-SANTA-GIULIA HAUTE-CORSE PAYS BASTIAIS 2B281
351 20213 SORBO-OCAGNANO VESCOVATO HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B286
352 20246 SORIO LE HAUT-NEBBIO HAUTE-CORSE PAYS BASTIAIS 2B287
353 20250 SOVERIA NIOLU-OMESSA HAUTE-CORSE CENTRE CORSE 2B289
354 20230 TAGLIO-ISOLACCIO FIUMALTO-D'AMPUGNANI HAUTE-CORSE CASTAGNICCIA / MARE E MONTI 2B318
355 20167 TAVACO CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A323
356 20163 TAVERA CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A324
357 20133 UCCIANI CELAVO-MEZZANA CORSE-DU-SUD PAYS AJACCIEN 94 2A330
358 20128 URBALACONE SANTA-MARIA-SICHE CORSE-DU-SUD TARAVO / VALINCO / SARTENAIS 94 2A331
359 20218 URTACA LE HAUT-NEBBIO HAUTE-CORSE PAYS DE BALAGNE 2B332
360 20235 VALLE-DI-ROSTINO CASTIFAO-MOROSAGLIA HAUTE-CORSE CENTRE CORSE 2B337
361 20219 VIVARIO VENACO HAUTE-CORSE CENTRE CORSE 2B354

View file

@ -0,0 +1,9 @@
\relax
\providecommand \babel@aux [2]{\global \let \babel@toc \@gobbletwo }
\@nameuse{bbl@beforestart}
\catcode `:\active
\catcode `;\active
\catcode `!\active
\catcode `?\active
\babel@aux{french}{}
\gdef \@abspage@last{6}

View file

@ -0,0 +1,752 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux) (preloaded format=pdflatex 2025.8.2) 23 OCT 2025 13:49
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**knn_microregions_activite.tex
(./knn_microregions_activite.tex
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
(/usr/share/texmf-dist/tex/latex/base/article.cls
Document Class: article 2024/06/29 v1.4n Standard LaTeX document class
(/usr/share/texmf-dist/tex/latex/base/size11.clo
File: size11.clo 2024/06/29 v1.4n Standard LaTeX file (size option)
)
\c@part=\count196
\c@section=\count197
\c@subsection=\count198
\c@subsubsection=\count199
\c@paragraph=\count266
\c@subparagraph=\count267
\c@figure=\count268
\c@table=\count269
\abovecaptionskip=\skip49
\belowcaptionskip=\skip50
\bibindent=\dimen141
)
(/usr/share/texmf-dist/tex/latex/base/inputenc.sty
Package: inputenc 2024/02/08 v1.3d Input encoding file
\inpenc@prehook=\toks17
\inpenc@posthook=\toks18
)
(/usr/share/texmf-dist/tex/latex/base/fontenc.sty
Package: fontenc 2021/04/29 v2.0v Standard LaTeX package
)
(/usr/share/texmf-dist/tex/generic/babel/babel.sty
Package: babel 2025/02/14 v25.4 The multilingual framework for pdfLaTeX, LuaLaT
eX and XeLaTeX
\babel@savecnt=\count270
\U@D=\dimen142
\l@unhyphenated=\language5
(/usr/share/texmf-dist/tex/generic/babel/txtbabel.def)
\bbl@readstream=\read2
\bbl@dirlevel=\count271
(/usr/share/texmf-dist/tex/generic/babel-french/francais.ldf
Language: francais 2024-07-25 v3.6c French support from the babel system
Package francais.ldf Warning: Option `francais' for Babel is *deprecated*,
(francais.ldf) it might be removed sooner or later. Please
(francais.ldf) use `french' instead; reported on input line 31.
(/usr/share/texmf-dist/tex/generic/babel-french/french.ldf
Language: french 2024-07-25 v3.6c French support from the babel system
Package babel Info: Hyphen rules for 'acadian' set to \l@french
(babel) (\language4). Reported on input line 91.
Package babel Info: Hyphen rules for 'canadien' set to \l@french
(babel) (\language4). Reported on input line 92.
\FB@stdchar=\count272
Package babel Info: Making : an active character on input line 421.
Package babel Info: Making ; an active character on input line 422.
Package babel Info: Making ! an active character on input line 423.
Package babel Info: Making ? an active character on input line 424.
\FBguill@level=\count273
\FBold@everypar=\toks19
\FB@Mht=\dimen143
\mc@charclass=\count274
\mc@charfam=\count275
\mc@charslot=\count276
\std@mcc=\count277
\dec@mcc=\count278
\FB@parskip=\dimen144
\listindentFB=\dimen145
\descindentFB=\dimen146
\labelindentFB=\dimen147
\labelwidthFB=\dimen148
\leftmarginFB=\dimen149
\parindentFFN=\dimen150
\FBfnindent=\dimen151
)))
(/usr/share/texmf-dist/tex/latex/carlisle/scalefnt.sty)
(/usr/share/texmf-dist/tex/latex/geometry/geometry.sty
Package: geometry 2020/01/02 v5.9 Page Geometry
(/usr/share/texmf-dist/tex/latex/graphics/keyval.sty
Package: keyval 2022/05/29 v1.15 key=value parser (DPC)
\KV@toks@=\toks20
)
(/usr/share/texmf-dist/tex/generic/iftex/ifvtex.sty
Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead.
(/usr/share/texmf-dist/tex/generic/iftex/iftex.sty
Package: iftex 2024/12/12 v1.0g TeX engine tests
))
\Gm@cnth=\count279
\Gm@cntv=\count280
\c@Gm@tempcnt=\count281
\Gm@bindingoffset=\dimen152
\Gm@wd@mp=\dimen153
\Gm@odd@mp=\dimen154
\Gm@even@mp=\dimen155
\Gm@layoutwidth=\dimen156
\Gm@layoutheight=\dimen157
\Gm@layouthoffset=\dimen158
\Gm@layoutvoffset=\dimen159
\Gm@dimlist=\toks21
)
(/usr/share/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty
(/usr/share/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex
\pgfutil@everybye=\toks22
\pgfutil@tempdima=\dimen160
\pgfutil@tempdimb=\dimen161
)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def
\pgfutil@abb=\box52
)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex
(/usr/share/texmf-dist/tex/generic/pgf/pgf.revision.tex)
Package: pgfrcs 2023-01-15 v3.1.10 (3.1.10)
))
Package: pgf 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty
(/usr/share/texmf-dist/tex/latex/graphics/graphicx.sty
Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR)
(/usr/share/texmf-dist/tex/latex/graphics/graphics.sty
Package: graphics 2024/08/06 v1.4g Standard LaTeX Graphics (DPC,SPQR)
(/usr/share/texmf-dist/tex/latex/graphics/trig.sty
Package: trig 2023/12/02 v1.11 sin cos tan (DPC)
)
(/usr/share/texmf-dist/tex/latex/graphics-cfg/graphics.cfg
File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration
)
Package graphics Info: Driver file: pdftex.def on input line 106.
(/usr/share/texmf-dist/tex/latex/graphics-def/pdftex.def
File: pdftex.def 2024/04/13 v1.2c Graphics/color driver for pdftex
))
\Gin@req@height=\dimen162
\Gin@req@width=\dimen163
)
(/usr/share/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex
Package: pgfsys 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex
\pgfkeys@pathtoks=\toks23
\pgfkeys@temptoks=\toks24
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeyslibraryfiltered.code.te
x
\pgfkeys@tmptoks=\toks25
))
\pgf@x=\dimen164
\pgf@y=\dimen165
\pgf@xa=\dimen166
\pgf@ya=\dimen167
\pgf@xb=\dimen168
\pgf@yb=\dimen169
\pgf@xc=\dimen170
\pgf@yc=\dimen171
\pgf@xd=\dimen172
\pgf@yd=\dimen173
\w@pgf@writea=\write3
\r@pgf@reada=\read3
\c@pgf@counta=\count282
\c@pgf@countb=\count283
\c@pgf@countc=\count284
\c@pgf@countd=\count285
\t@pgf@toka=\toks26
\t@pgf@tokb=\toks27
\t@pgf@tokc=\toks28
\pgf@sys@id@count=\count286
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg
File: pgf.cfg 2023-01-15 v3.1.10 (3.1.10)
)
Driver file for pgf: pgfsys-pdftex.def
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def
File: pgfsys-pdftex.def 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def
File: pgfsys-common-pdf.def 2023-01-15 v3.1.10 (3.1.10)
)))
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex
File: pgfsyssoftpath.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfsyssoftpath@smallbuffer@items=\count287
\pgfsyssoftpath@bigbuffer@items=\count288
)
(/usr/share/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex
File: pgfsysprotocol.code.tex 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/latex/xcolor/xcolor.sty
Package: xcolor 2024/09/29 v3.02 LaTeX color extensions (UK)
(/usr/share/texmf-dist/tex/latex/graphics-cfg/color.cfg
File: color.cfg 2016/01/02 v1.6 sample color configuration
)
Package xcolor Info: Driver file: pdftex.def on input line 274.
(/usr/share/texmf-dist/tex/latex/graphics/mathcolor.ltx)
Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1349.
Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1353.
Package xcolor Info: Model `RGB' extended on input line 1365.
Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1367.
Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1368.
Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1369.
Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1370.
Package xcolor Info: Model `Gray' substituted by `gray' on input line 1371.
Package xcolor Info: Model `wave' substituted by `hsb' on input line 1372.
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex
Package: pgfcore 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex
\pgfmath@dimen=\dimen174
\pgfmath@count=\count289
\pgfmath@box=\box53
\pgfmath@toks=\toks29
\pgfmath@stack@operand=\toks30
\pgfmath@stack@operation=\toks31
)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonometric.code
.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison.code.te
x) (/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerarithmetics
.code.tex) (/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex
\c@pgfmathroundto@lastzeros=\count290
))
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfint.code.tex)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex
File: pgfcorepoints.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@picminx=\dimen175
\pgf@picmaxx=\dimen176
\pgf@picminy=\dimen177
\pgf@picmaxy=\dimen178
\pgf@pathminx=\dimen179
\pgf@pathmaxx=\dimen180
\pgf@pathminy=\dimen181
\pgf@pathmaxy=\dimen182
\pgf@xx=\dimen183
\pgf@xy=\dimen184
\pgf@yx=\dimen185
\pgf@yy=\dimen186
\pgf@zx=\dimen187
\pgf@zy=\dimen188
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.code.tex
File: pgfcorepathconstruct.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@path@lastx=\dimen189
\pgf@path@lasty=\dimen190
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
File: pgfcorepathusage.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@shorten@end@additional=\dimen191
\pgf@shorten@start@additional=\dimen192
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex
File: pgfcorescopes.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfpic=\box54
\pgf@hbox=\box55
\pgf@layerbox@main=\box56
\pgf@picture@serial@count=\count291
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex
File: pgfcoregraphicstate.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgflinewidth=\dimen193
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformations.code.t
ex
File: pgfcoretransformations.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@pt@x=\dimen194
\pgf@pt@y=\dimen195
\pgf@pt@temp=\dimen196
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex
File: pgfcorequick.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex
File: pgfcoreobjects.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.te
x
File: pgfcorepathprocessing.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex
File: pgfcorearrows.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfarrowsep=\dimen197
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex
File: pgfcoreshade.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@max=\dimen198
\pgf@sys@shading@range@num=\count292
\pgf@shadingcount=\count293
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex
File: pgfcoreimage.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex
File: pgfcoreexternal.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfexternal@startupbox=\box57
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex
File: pgfcorelayers.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.code.tex
File: pgfcoretransparency.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.tex
File: pgfcorepatterns.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.tex
File: pgfcorerdf.code.tex 2023-01-15 v3.1.10 (3.1.10)
)))
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex
File: pgfmoduleshapes.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfnodeparttextbox=\box58
)
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex
File: pgfmoduleplot.code.tex 2023-01-15 v3.1.10 (3.1.10)
)
(/usr/share/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty
Package: pgfcomp-version-0-65 2023-01-15 v3.1.10 (3.1.10)
\pgf@nodesepstart=\dimen199
\pgf@nodesepend=\dimen256
)
(/usr/share/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty
Package: pgfcomp-version-1-18 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgffor.sty
(/usr/share/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex))
(/usr/share/texmf-dist/tex/latex/pgf/math/pgfmath.sty
(/usr/share/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex))
(/usr/share/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex
Package: pgffor 2023-01-15 v3.1.10 (3.1.10)
\pgffor@iter=\dimen257
\pgffor@skip=\dimen258
\pgffor@stack=\toks32
\pgffor@toks=\toks33
))
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex
Package: tikz 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.te
x
File: pgflibraryplothandlers.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgf@plot@mark@count=\count294
\pgfplotmarksize=\dimen259
)
\tikz@lastx=\dimen260
\tikz@lasty=\dimen261
\tikz@lastxsaved=\dimen262
\tikz@lastysaved=\dimen263
\tikz@lastmovetox=\dimen264
\tikz@lastmovetoy=\dimen265
\tikzleveldistance=\dimen266
\tikzsiblingdistance=\dimen267
\tikz@figbox=\box59
\tikz@figbox@bg=\box60
\tikz@tempbox=\box61
\tikz@tempbox@bg=\box62
\tikztreelevel=\count295
\tikznumberofchildren=\count296
\tikznumberofcurrentchild=\count297
\tikz@fig@count=\count298
(/usr/share/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex
File: pgfmodulematrix.code.tex 2023-01-15 v3.1.10 (3.1.10)
\pgfmatrixcurrentrow=\count299
\pgfmatrixcurrentcolumn=\count300
\pgf@matrix@numberofcolumns=\count301
)
\tikz@expandcount=\count302
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
topaths.code.tex
File: tikzlibrarytopaths.code.tex 2023-01-15 v3.1.10 (3.1.10)
))) (/usr/share/texmf-dist/tex/latex/amsmath/amsmath.sty
Package: amsmath 2024/11/05 v2.17t AMS math features
\@mathmargin=\skip51
For additional information on amsmath, use the `?' option.
(/usr/share/texmf-dist/tex/latex/amsmath/amstext.sty
Package: amstext 2021/08/26 v2.01 AMS text
(/usr/share/texmf-dist/tex/latex/amsmath/amsgen.sty
File: amsgen.sty 1999/11/30 v2.0 generic functions
\@emptytoks=\toks34
\ex@=\dimen268
))
(/usr/share/texmf-dist/tex/latex/amsmath/amsbsy.sty
Package: amsbsy 1999/11/29 v1.2d Bold Symbols
\pmbraise@=\dimen269
)
(/usr/share/texmf-dist/tex/latex/amsmath/amsopn.sty
Package: amsopn 2022/04/08 v2.04 operator names
)
\inf@bad=\count303
LaTeX Info: Redefining \frac on input line 233.
\uproot@=\count304
\leftroot@=\count305
LaTeX Info: Redefining \overline on input line 398.
LaTeX Info: Redefining \colon on input line 409.
\classnum@=\count306
\DOTSCASE@=\count307
LaTeX Info: Redefining \ldots on input line 495.
LaTeX Info: Redefining \dots on input line 498.
LaTeX Info: Redefining \cdots on input line 619.
\Mathstrutbox@=\box63
\strutbox@=\box64
LaTeX Info: Redefining \big on input line 721.
LaTeX Info: Redefining \Big on input line 722.
LaTeX Info: Redefining \bigg on input line 723.
LaTeX Info: Redefining \Bigg on input line 724.
\big@size=\dimen270
LaTeX Font Info: Redeclaring font encoding OML on input line 742.
LaTeX Font Info: Redeclaring font encoding OMS on input line 743.
\macc@depth=\count308
LaTeX Info: Redefining \bmod on input line 904.
LaTeX Info: Redefining \pmod on input line 909.
LaTeX Info: Redefining \smash on input line 939.
LaTeX Info: Redefining \relbar on input line 969.
LaTeX Info: Redefining \Relbar on input line 970.
\c@MaxMatrixCols=\count309
\dotsspace@=\muskip17
\c@parentequation=\count310
\dspbrk@lvl=\count311
\tag@help=\toks35
\row@=\count312
\column@=\count313
\maxfields@=\count314
\andhelp@=\toks36
\eqnshift@=\dimen271
\alignsep@=\dimen272
\tagshift@=\dimen273
\tagwidth@=\dimen274
\totwidth@=\dimen275
\lineht@=\dimen276
\@envbody=\toks37
\multlinegap=\skip52
\multlinetaggap=\skip53
\mathdisplay@stack=\toks38
LaTeX Info: Redefining \[ on input line 2953.
LaTeX Info: Redefining \] on input line 2954.
)
(/usr/share/texmf-dist/tex/latex/amsfonts/amssymb.sty
Package: amssymb 2013/01/14 v3.01 AMS font symbols
(/usr/share/texmf-dist/tex/latex/amsfonts/amsfonts.sty
Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support
\symAMSa=\mathgroup4
\symAMSb=\mathgroup5
LaTeX Font Info: Redeclaring math symbol \hbar on input line 98.
LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold'
(Font) U/euf/m/n --> U/euf/b/n on input line 106.
))
(/usr/share/texmf-dist/tex/latex/enumitem/enumitem.sty
Package: enumitem 2025/02/06 v3.11 Customized lists
\labelindent=\skip54
\enit@outerparindent=\dimen277
\enit@toks=\toks39
\enit@inbox=\box65
\enit@count@id=\count315
\enitdp@description=\count316
)
(/usr/share/texmf-dist/tex/latex/tcolorbox/tcolorbox.sty
Package: tcolorbox 2024/10/22 version 6.4.1 text color boxes
(/usr/share/texmf-dist/tex/latex/tools/verbatim.sty
Package: verbatim 2024-01-22 v1.5x LaTeX2e package for verbatim enhancements
\every@verbatim=\toks40
\verbatim@line=\toks41
\verbatim@in@stream=\read4
)
(/usr/share/texmf-dist/tex/latex/environ/environ.sty
Package: environ 2014/05/04 v0.3 A new way to define environments
(/usr/share/texmf-dist/tex/latex/trimspaces/trimspaces.sty
Package: trimspaces 2009/09/17 v1.1 Trim spaces around a token list
))
(/usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
Package: etoolbox 2025/02/11 v2.5l e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count317
)
\tcb@titlebox=\box66
\tcb@upperbox=\box67
\tcb@lowerbox=\box68
\tcb@phantombox=\box69
\c@tcbbreakpart=\count318
\c@tcblayer=\count319
\c@tcolorbox@number=\count320
\l__tcobox_tmpa_box=\box70
\l__tcobox_tmpa_dim=\dimen278
\tcb@temp=\box71
\tcb@temp=\box72
\tcb@temp=\box73
\tcb@temp=\box74
)
(/usr/share/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty
Package: fancyhdr 2025/02/07 v5.2 Extensive control of page headers and footers
\f@nch@headwidth=\skip55
\f@nch@offset@elh=\skip56
\f@nch@offset@erh=\skip57
\f@nch@offset@olh=\skip58
\f@nch@offset@orh=\skip59
\f@nch@offset@elf=\skip60
\f@nch@offset@erf=\skip61
\f@nch@offset@olf=\skip62
\f@nch@offset@orf=\skip63
\f@nch@height=\skip64
\f@nch@footalignment=\skip65
\f@nch@widthL=\skip66
\f@nch@widthC=\skip67
\f@nch@widthR=\skip68
\@temptokenb=\toks42
)
(/usr/share/texmf-dist/tex/latex/tools/multicol.sty
Package: multicol 2024/09/14 v1.9i multicolumn formatting (FMi)
\c@tracingmulticols=\count321
\mult@box=\box75
\multicol@leftmargin=\dimen279
\c@unbalance=\count322
\c@collectmore=\count323
\doublecol@number=\count324
\multicoltolerance=\count325
\multicolpretolerance=\count326
\full@width=\dimen280
\page@free=\dimen281
\premulticols=\dimen282
\postmulticols=\dimen283
\multicolsep=\skip69
\multicolbaselineskip=\skip70
\partial@page=\box76
\last@line=\box77
\mc@boxedresult=\box78
\maxbalancingoverflow=\dimen284
\mult@rightbox=\box79
\mult@grightbox=\box80
\mult@firstbox=\box81
\mult@gfirstbox=\box82
\@tempa=\box83
\@tempa=\box84
\@tempa=\box85
\@tempa=\box86
\@tempa=\box87
\@tempa=\box88
\@tempa=\box89
\@tempa=\box90
\@tempa=\box91
\@tempa=\box92
\@tempa=\box93
\@tempa=\box94
\@tempa=\box95
\@tempa=\box96
\@tempa=\box97
\@tempa=\box98
\@tempa=\box99
\@tempa=\box100
\@tempa=\box101
\@tempa=\box102
\@tempa=\box103
\@tempa=\box104
\@tempa=\box105
\@tempa=\box106
\@tempa=\box107
\@tempa=\box108
\@tempa=\box109
\@tempa=\box110
\@tempa=\box111
\@tempa=\box112
\@tempa=\box113
\@tempa=\box114
\@tempa=\box115
\@tempa=\box116
\@tempa=\box117
\@tempa=\box118
\c@minrows=\count327
\c@columnbadness=\count328
\c@finalcolumnbadness=\count329
\last@try=\dimen285
\multicolovershoot=\dimen286
\multicolundershoot=\dimen287
\mult@nat@firstbox=\box119
\colbreak@box=\box120
\mc@col@check@num=\count330
)
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
shapes.geometric.code.tex
File: tikzlibraryshapes.geometric.code.tex 2023-01-15 v3.1.10 (3.1.10)
(/usr/share/texmf-dist/tex/generic/pgf/libraries/shapes/pgflibraryshapes.geomet
ric.code.tex
File: pgflibraryshapes.geometric.code.tex 2023-01-15 v3.1.10 (3.1.10)
))
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
calc.code.tex
File: tikzlibrarycalc.code.tex 2023-01-15 v3.1.10 (3.1.10)
) (/usr/share/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
File: l3backend-pdftex.def 2024-05-08 L3 backend support: PDF output (pdfTeX)
\l__color_backend_stack_int=\count331
\l__pdf_internal_box=\box121
) (./knn_microregions_activite.aux
(/usr/share/texmf-dist/tex/generic/babel/locale/fr/babel-french.tex
Package babel Info: Importing font and identification data for french
(babel) from babel-fr.ini. Reported on input line 11.
))
\openout1 = `knn_microregions_activite.aux'.
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 36.
LaTeX Font Info: ... okay on input line 36.
LaTeX Info: Redefining \degres on input line 36.
Package french.ldf Info: Setting StandardItemizeEnv=true for
(french.ldf) compatibility with enumitem package,
(french.ldf) reported on input line 36.
Package french.ldf Info: Setting StandardEnumerateEnv=true for
(french.ldf) compatibility with enumitem package,
(french.ldf) reported on input line 36.
LaTeX Info: Redefining \up on input line 36.
*geometry* driver: auto-detecting
*geometry* detected driver: pdftex
*geometry* verbose mode - [ preamble ] result:
* driver: pdftex
* paper: a4paper
* layout: <same size as paper>
* layoutoffset:(h,v)=(0.0pt,0.0pt)
* modes:
* h-part:(L,W,R)=(56.9055pt, 483.69687pt, 56.9055pt)
* v-part:(T,H,B)=(56.9055pt, 731.23584pt, 56.9055pt)
* \paperwidth=597.50787pt
* \paperheight=845.04684pt
* \textwidth=483.69687pt
* \textheight=731.23584pt
* \oddsidemargin=-15.36449pt
* \evensidemargin=-15.36449pt
* \topmargin=-52.36449pt
* \headheight=12.0pt
* \headsep=25.0pt
* \topskip=11.0pt
* \footskip=30.0pt
* \marginparwidth=50.0pt
* \marginparsep=10.0pt
* \columnsep=10.0pt
* \skip\footins=10.0pt plus 4.0pt minus 2.0pt
* \hoffset=0.0pt
* \voffset=0.0pt
* \mag=1000
* \@twocolumnfalse
* \@twosidefalse
* \@mparswitchfalse
* \@reversemarginfalse
* (1in=72.27pt=25.4mm, 1cm=28.453pt)
(/usr/share/texmf-dist/tex/context/base/mkii/supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
\scratchcounter=\count332
\scratchdimen=\dimen288
\scratchbox=\box122
\nofMPsegments=\count333
\nofMParguments=\count334
\everyMPshowfont=\toks43
\MPscratchCnt=\count335
\MPscratchDim=\dimen289
\MPnumerator=\count336
\makeMPintoPDFobject=\count337
\everyMPtoPDFconversion=\toks44
) (/usr/share/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty
Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf
Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4
85.
(/usr/share/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
e
))
LaTeX Font Info: Trying to load font information for U+msa on input line 63.
(/usr/share/texmf-dist/tex/latex/amsfonts/umsa.fd
File: umsa.fd 2013/01/14 v3.01 AMS symbols A
)
LaTeX Font Info: Trying to load font information for U+msb on input line 63.
(/usr/share/texmf-dist/tex/latex/amsfonts/umsb.fd
File: umsb.fd 2013/01/14 v3.01 AMS symbols B
)
[1
{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}{/usr/share/texmf-dist/fonts
/enc/dvips/cm-super/cm-super-t1.enc}]
[2]
[3]
[4]
[5]
[6] (./knn_microregions_activite.aux)
***********
LaTeX2e <2024-11-01> patch level 2
L3 programming layer <2025-01-18>
***********
)
Here is how much of TeX's memory you used:
19631 strings out of 475142
396220 string characters out of 5765947
785977 words of memory out of 5000000
42341 multiletter control sequences out of 15000+600000
571118 words of font info for 64 fonts, out of 8000000 for 9000
14 hyphenation exceptions out of 8191
102i,11n,107p,426b,737s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/
texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/share/texmf-dist/fon
ts/type1/public/cm-super/sfbx1095.pfb></usr/share/texmf-dist/fonts/type1/public
/cm-super/sfbx1200.pfb></usr/share/texmf-dist/fonts/type1/public/cm-super/sfbx1
440.pfb></usr/share/texmf-dist/fonts/type1/public/cm-super/sfbx2488.pfb></usr/s
hare/texmf-dist/fonts/type1/public/cm-super/sfrm1000.pfb></usr/share/texmf-dist
/fonts/type1/public/cm-super/sfrm1095.pfb></usr/share/texmf-dist/fonts/type1/pu
blic/cm-super/sfti1095.pfb>
Output written on knn_microregions_activite.pdf (6 pages, 170496 bytes).
PDF statistics:
72 PDF objects out of 1000 (max. 8388607)
45 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
13 words of extra memory for PDF output out of 10000 (max. 10000000)

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,403 @@
\documentclass[a4paper,11pt]{article}
% Packages
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[francais]{babel}
\usepackage{geometry}
\usepackage{tikz}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{enumitem}
\usepackage{xcolor}
\usepackage{tcolorbox}
\usepackage{fancyhdr}
\usepackage{multicol}
% Configuration de la page
\geometry{margin=2cm}
\pagestyle{fancy}
\fancyhf{}
\fancyfoot[C]{Page \thepage/4 -- Activité k-NN : Micro-régions}
\renewcommand{\headrulewidth}{0pt}
% Couleurs pour les micro-régions
\definecolor{region1}{RGB}{231,76,60} % Rouge
\definecolor{region2}{RGB}{52,152,219} % Bleu
\definecolor{region3}{RGB}{46,204,113} % Vert
\definecolor{region4}{RGB}{241,196,15} % Jaune
\definecolor{region5}{RGB}{155,89,182} % Violet
\definecolor{lightblue}{RGB}{227,242,253}
\definecolor{lightyellow}{RGB}{255,243,205}
% Configuration TikZ
\usetikzlibrary{shapes.geometric,calc}
\begin{document}
% ============= PAGE 1 =============
\begin{center}
{\Huge \textbf{Activité débranchée : k-NN}}\\[0.3cm]
{\Large \textbf{Classification par micro-régions}}
\end{center}
\vspace{0.5cm}
\textbf{Objectif :} Utiliser l'algorithme k-NN pour déterminer à quelle micro-région appartient un nouveau point, en se basant sur ses plus proches voisins.
\vspace{0.3cm}
\begin{tcolorbox}[colback=lightblue,colframe=blue!75!black,title=\textbf{Principe}]
\begin{itemize}[leftmargin=*]
\item On dispose de points classifiés en plusieurs \textit{zones} (micro-régions)
\item Pour classifier un nouveau point, on identifie ses \textit{k} plus proches voisins
\item La zone majoritaire parmi ces \textit{k} voisins devient la classification du point
\item \textbf{Différence avec 2 classes :} Avec plusieurs zones, les votes sont plus complexes !
\end{itemize}
\end{tcolorbox}
\vspace{0.5cm}
\section*{Exercice 1 : Classification avec 5 zones}
Voici des points répartis en 5 zones de couleurs différentes. Le point noir ($\star$) est à classifier.
\vspace{0.3cm}
\begin{center}
\begin{tikzpicture}[scale=1.1]
% Grille
\draw[gray!30, step=1] (0,0) grid (10,10);
% Cadre
\draw[thick] (0,0) rectangle (10,10);
% Zone 1 (Rouge) - En haut à gauche
\foreach \point in {(1,9), (1.5,8.5), (2,9.5), (1,8), (2.5,8.5), (1.5,7.5)} {
\fill[region1] \point circle (0.15);
}
% Zone 2 (Bleu) - En haut à droite
\foreach \point in {(8,9), (8.5,8.5), (9,9.5), (8,8), (9.5,8.5), (8.5,7.5)} {
\fill[region2] \point circle (0.15);
}
% Zone 3 (Vert) - En bas à gauche
\foreach \point in {(1,2), (1.5,1.5), (2,2.5), (1,1), (2.5,1.5), (1.5,2.5)} {
\fill[region3] \point circle (0.15);
}
% Zone 4 (Jaune) - En bas à droite
\foreach \point in {(8,2), (8.5,1.5), (9,2.5), (8,1), (9.5,1.5), (8.5,2.5)} {
\fill[region4] \point circle (0.15);
}
% Zone 5 (Violet) - Au centre
\foreach \point in {(5,5), (5.5,5.5), (4.5,5.5), (5.5,4.5), (4.5,4.5), (5,6)} {
\fill[region5] \point circle (0.15);
}
% Point à classifier (étoile noire)
\node[star,star points=5,star point ratio=2.5,fill=black,draw=black,thick,minimum size=0.6cm] at (6.5,6) {};
\end{tikzpicture}
\vspace{0.3cm}
% Légende
\begin{tabular}{ccccccccc}
\textcolor{region1}{$\bullet$} Zone 1 & \quad &
\textcolor{region2}{$\bullet$} Zone 2 & \quad &
\textcolor{region3}{$\bullet$} Zone 3 & \quad &
\textcolor{region4}{$\bullet$} Zone 4 & \quad &
\textcolor{region5}{$\bullet$} Zone 5
\end{tabular}
\end{center}
\vspace{0.5cm}
\subsection*{Questions avec k = 3 :}
\begin{enumerate}
\item Identifiez les 3 points les plus proches du point noir $\star$. Tracez les distances.
\vspace{0.3cm}
Les 3 plus proches : Zone \underline{\hspace{1cm}}, Zone \underline{\hspace{1cm}}, Zone \underline{\hspace{1cm}}
\vspace{0.3cm}
\item Comptez les votes pour chaque zone parmi ces 3 voisins :
\vspace{0.2cm}
Zone 1 : \underline{\hspace{1cm}} \quad Zone 2 : \underline{\hspace{1cm}} \quad Zone 3 : \underline{\hspace{1cm}}
Zone 4 : \underline{\hspace{1cm}} \quad Zone 5 : \underline{\hspace{1cm}}
\vspace{0.3cm}
\item Quelle est la zone majoritaire ? \underline{\hspace{4cm}}
\vspace{0.3cm}
\item Y a-t-il égalité entre plusieurs zones ? \underline{\hspace{4cm}}
\end{enumerate}
% ============= PAGE 2 =============
%\newpage
\section*{Exercice 2 : Influence de k avec plusieurs classes}
Reprenez le même graphique que l'exercice 1.
\vspace{0.5cm}
\subsection*{a) Avec k = 5 (5 voisins)}
\begin{itemize}
\item Listez les 5 points les plus proches :
\vspace{0.2cm}
Zone \underline{\hspace{1.5cm}}, Zone \underline{\hspace{1.5cm}}, Zone \underline{\hspace{1.5cm}},
Zone \underline{\hspace{1.5cm}}, Zone \underline{\hspace{1.5cm}}
\vspace{0.3cm}
\item Votes par zone :
\vspace{0.2cm}
Zone 1 : \underline{\hspace{1cm}} \quad Zone 2 : \underline{\hspace{1cm}} \quad Zone 3 : \underline{\hspace{1cm}}
Zone 4 : \underline{\hspace{1cm}} \quad Zone 5 : \underline{\hspace{1cm}}
\vspace{0.3cm}
\item Classification du point noir : Zone \underline{\hspace{3cm}}
\end{itemize}
\vspace{0.8cm}
\subsection*{b) Avec k = 7 (7 voisins)}
\begin{itemize}
\item Votes par zone :
\vspace{0.2cm}
Zone 1 : \underline{\hspace{1cm}} \quad Zone 2 : \underline{\hspace{1cm}} \quad Zone 3 : \underline{\hspace{1cm}}
Zone 4 : \underline{\hspace{1cm}} \quad Zone 5 : \underline{\hspace{1cm}}
\vspace{0.3cm}
\item Classification du point noir : Zone \underline{\hspace{3cm}}
\end{itemize}
\vspace{1cm}
\begin{tcolorbox}[colback=lightyellow,colframe=orange!75!black,title=\textbf{Réflexion : Plusieurs classes}]
\textbf{1. Qu'est-ce qui change par rapport à 2 classes seulement ?}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\vspace{0.5cm}
\textbf{2. Peut-il y avoir des égalités entre zones ? Donnez un exemple.}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\vspace{0.5cm}
\textbf{3. Comment résoudre une égalité ?}
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\end{tcolorbox}
% ============= PAGE 3 =============
%\newpage
\section*{Exercice 3 : Cas complexe avec 4 zones}
Voici une nouvelle situation avec 4 zones différentes. Classifiez le point $\star$ avec k = 5.
\vspace{0.3cm}
\begin{center}
\begin{tikzpicture}[scale=1.2]
% Grille
\draw[gray!30, step=1] (0,0) grid (10,10);
% Cadre
\draw[thick] (0,0) rectangle (10,10);
% Zone A (Rouge) - Dispersée
\foreach \point in {(1,8), (2,7), (1,6), (3,8.5), (2.5,6.5), (1.5,9)} {
\fill[region1] \point circle (0.15);
}
% Zone B (Bleu) - Coin supérieur droit
\foreach \point in {(8,8), (9,8.5), (8.5,7.5), (9,9), (8,9.5), (7.5,8)} {
\fill[region2] \point circle (0.15);
}
% Zone C (Vert) - En bas
\foreach \point in {(3,2), (4,1.5), (5,2), (6,1.5), (4,2.5), (5,1)} {
\fill[region3] \point circle (0.15);
}
% Zone D (Violet) - Centre-droit
\foreach \point in {(6,5), (7,5.5), (6.5,4.5), (7.5,5), (6,6), (7,6.5)} {
\fill[region5] \point circle (0.15);
}
% Point à classifier
\node[star,star points=5,star point ratio=2.5,fill=black,draw=black,thick,minimum size=0.6cm] at (5.5,5.5) {};
\end{tikzpicture}
\vspace{0.3cm}
% Légende
\begin{tabular}{ccccccc}
\textcolor{region1}{$\bullet$} Zone A & \quad &
\textcolor{region2}{$\bullet$} Zone B & \quad &
\textcolor{region3}{$\bullet$} Zone C & \quad &
\textcolor{region5}{$\bullet$} Zone D
\end{tabular}
\end{center}
\vspace{0.5cm}
\subsection*{Travail à faire :}
\begin{enumerate}
\item Identifiez les 5 plus proches voisins et tracez les distances sur le graphique
\vspace{0.3cm}
\item Complétez le tableau de votes :
\vspace{0.3cm}
\begin{center}
\begin{tabular}{|c|c|c|c|}
\hline
Zone A & Zone B & Zone C & Zone D \\
\hline
\hspace{1.5cm} & \hspace{1.5cm} & \hspace{1.5cm} & \hspace{1.5cm} \\[0.5cm]
\hline
\end{tabular}
\end{center}
\vspace{0.3cm}
\item Classification finale : Zone \underline{\hspace{4cm}}
\vspace{0.3cm}
\item Cette classification vous semble-t-elle cohérente visuellement ? Pourquoi ?
\vspace{0.8cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\end{enumerate}
% ============= PAGE 4 =============
%\newpage
\section*{Exercice 4 : Création libre}
Créez votre propre situation avec au moins 3 zones différentes.
\vspace{0.5cm}
\begin{center}
\begin{tikzpicture}[scale=1.3]
% Grille
\draw[gray!20, step=1] (0,0) grid (12,12);
% Cadre
\draw[very thick] (0,0) rectangle (12,12);
% Graduations
\foreach \x in {0,2,4,6,8,10,12} {
\node[below] at (\x,-0.2) {\small \x};
}
\foreach \y in {0,2,4,6,8,10,12} {
\node[left] at (-0.2,\y) {\small \y};
}
\end{tikzpicture}
\end{center}
\vspace{0.5cm}
\begin{tcolorbox}[colback=lightblue,colframe=blue!75!black,title=\textbf{Instructions}]
\begin{itemize}
\item Choisissez 3 à 5 zones (utilisez des couleurs différentes)
\item Placez au moins 5 points par zone
\item Placez une étoile noire (point à classifier)
\item Utilisez k = 5 et déterminez la zone du point noir
\end{itemize}
\end{tcolorbox}
\vspace{0.5cm}
\textbf{Vos zones :}
Zone 1 : \underline{\hspace{3cm}} (couleur : \underline{\hspace{2cm}})
Zone 2 : \underline{\hspace{3cm}} (couleur : \underline{\hspace{2cm}})
Zone 3 : \underline{\hspace{3cm}} (couleur : \underline{\hspace{2cm}})
\vspace{0.3cm}
\textbf{Classification avec k = 5 :} Zone \underline{\hspace{4cm}}
\vspace{1cm}
\section*{Pour aller plus loin}
\subsection*{Applications avec plusieurs classes}
L'algorithme k-NN avec plusieurs classes est utilisé pour :
\begin{itemize}
\item \textbf{Reconnaissance de chiffres} : Classifier 0, 1, 2, ..., 9 (10 classes)
\item \textbf{Classification de fleurs} : Différentes espèces (iris, rose, tulipe...)
\item \textbf{Zonage géographique} : Micro-régions, quartiers, zones climatiques
\item \textbf{Diagnostic médical} : Plusieurs types de maladies possibles
\item \textbf{Reconnaissance vocale} : Identifier différents phonèmes ou mots
\end{itemize}
\vspace{0.5cm}
\subsection*{Défis avec plusieurs classes}
\begin{enumerate}
\item \textbf{Égalités plus fréquentes} : Avec 2 classes, égalité rare. Avec 5 classes, beaucoup plus probable !
\item \textbf{Choix de k important} : Si k est trop petit, risque de ne pas capturer la diversité. Si trop grand, perd la précision locale.
\item \textbf{Classes déséquilibrées} : Si une zone a beaucoup plus de points qu'une autre, elle sera sur-représentée.
\item \textbf{Frontières complexes} : Avec plusieurs zones, les frontières peuvent être très irrégulières.
\end{enumerate}
\vspace{0.5cm}
\begin{tcolorbox}[colback=lightyellow,colframe=orange!75!black,title=\textbf{Question finale}]
Pourquoi est-il préférable d'utiliser un \textit{k} impair lorsqu'on a un nombre pair de classes ?
\vspace{1cm}
\underline{\hspace{14cm}}
\vspace{0.4cm}
\underline{\hspace{14cm}}
\end{tcolorbox}
\end{document}

View file

@ -0,0 +1,492 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>k-NN Animation - Micro-régions</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 15px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
font-style: italic;
}
canvas {
border: 2px solid #ddd;
border-radius: 10px;
display: block;
margin: 20px auto;
cursor: crosshair;
background: #fafafa;
}
.controls {
background: #f5f5f5;
padding: 20px;
border-radius: 10px;
margin: 20px 0;
}
.control-group {
margin: 15px 0;
}
label {
font-weight: bold;
color: #555;
display: block;
margin-bottom: 8px;
}
input[type="range"] {
width: 100%;
height: 8px;
border-radius: 5px;
background: #ddd;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
border: none;
}
.value-display {
display: inline-block;
background: #667eea;
color: white;
padding: 5px 15px;
border-radius: 20px;
font-weight: bold;
margin-left: 10px;
}
.legend {
display: flex;
justify-content: center;
gap: 20px;
margin: 20px 0;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 15px;
background: white;
border-radius: 8px;
border: 2px solid #ddd;
}
.legend-circle {
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid #333;
}
.result {
text-align: center;
font-size: 1.5em;
font-weight: bold;
margin: 20px 0;
padding: 20px;
border-radius: 10px;
background: #f0f0f0;
}
.votes {
display: flex;
justify-content: center;
gap: 15px;
margin: 15px 0;
flex-wrap: wrap;
}
.vote-box {
padding: 15px 20px;
border-radius: 10px;
text-align: center;
min-width: 100px;
border: 3px solid transparent;
}
.vote-count {
font-size: 2em;
font-weight: bold;
}
.vote-label {
font-size: 0.9em;
margin-top: 5px;
}
.buttons {
display: flex;
gap: 10px;
justify-content: center;
margin: 20px 0;
flex-wrap: wrap;
}
button {
padding: 12px 24px;
font-size: 16px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.btn-reset {
background: #f44336;
color: white;
}
.btn-random {
background: #4CAF50;
color: white;
}
.instructions {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 15px;
margin: 20px 0;
border-radius: 5px;
}
.instructions h3 {
margin-top: 0;
color: #856404;
}
</style>
</head>
<body>
<div class="container">
<h1>🎯 Animation k-NN : Classification multi-zones</h1>
<p class="subtitle">Algorithme des k plus proches voisins avec plusieurs classes</p>
<div class="instructions">
<h3>📋 Instructions</h3>
<ul>
<li><strong>Cliquez</strong> sur le graphique pour placer un nouveau point</li>
<li><strong>Ajustez le curseur k</strong> pour voir l'impact du nombre de voisins</li>
<li>Observez comment les <strong>votes</strong> se répartissent entre les zones</li>
<li>Les lignes colorées montrent les <strong>k plus proches voisins</strong></li>
</ul>
</div>
<canvas id="canvas" width="800" height="600"></canvas>
<div class="legend" id="legend"></div>
<div class="controls">
<div class="control-group">
<label>
Nombre de voisins (k) :
<span class="value-display" id="kValue">5</span>
</label>
<input type="range" id="kSlider" min="1" max="21" value="5" step="2">
</div>
</div>
<div class="result" id="result">
Cliquez sur le graphique pour classifier un point
</div>
<div class="votes" id="votes"></div>
<div class="buttons">
<button class="btn-random" onclick="placeRandomPoint()">🎲 Point Aléatoire</button>
<button class="btn-reset" onclick="resetPoint()">🔄 Réinitialiser</button>
</div>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const kSlider = document.getElementById('kSlider');
const kValue = document.getElementById('kValue');
const result = document.getElementById('result');
const votesDiv = document.getElementById('votes');
const legendDiv = document.getElementById('legend');
// Définition des zones (micro-régions)
const zones = [
{ name: 'Alta Rocca', color: '#e74c3c', shortName: 'Alta Rocca' },
{ name: 'Balagne', color: '#3498db', shortName: 'Balagne' },
{ name: 'Centre Corse', color: '#2ecc71', shortName: 'Centre' },
{ name: 'Extrême Sud', color: '#f39c12', shortName: 'Sud' },
{ name: 'Cap Corse', color: '#9b59b6', shortName: 'Cap' }
];
// Points d'apprentissage (générés automatiquement par zone)
const trainingPoints = [];
// Zone 1 - Alta Rocca (rouge, bas gauche)
for (let i = 0; i < 15; i++) {
trainingPoints.push({
x: 100 + Math.random() * 150,
y: 400 + Math.random() * 150,
zone: 0
});
}
// Zone 2 - Balagne (bleu, haut gauche)
for (let i = 0; i < 15; i++) {
trainingPoints.push({
x: 100 + Math.random() * 150,
y: 50 + Math.random() * 150,
zone: 1
});
}
// Zone 3 - Centre Corse (vert, centre)
for (let i = 0; i < 15; i++) {
trainingPoints.push({
x: 300 + Math.random() * 200,
y: 200 + Math.random() * 200,
zone: 2
});
}
// Zone 4 - Extrême Sud (jaune, bas droite)
for (let i = 0; i < 15; i++) {
trainingPoints.push({
x: 550 + Math.random() * 150,
y: 400 + Math.random() * 150,
zone: 3
});
}
// Zone 5 - Cap Corse (violet, haut droite)
for (let i = 0; i < 15; i++) {
trainingPoints.push({
x: 550 + Math.random() * 150,
y: 50 + Math.random() * 150,
zone: 4
});
}
let testPoint = null;
let k = 5;
// Créer la légende
function createLegend() {
legendDiv.innerHTML = '';
zones.forEach(zone => {
const item = document.createElement('div');
item.className = 'legend-item';
item.innerHTML = `
<div class="legend-circle" style="background: ${zone.color};"></div>
<span>${zone.name}</span>
`;
legendDiv.appendChild(item);
});
}
function distance(p1, p2) {
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
}
function findKNearest(point, k) {
const distances = trainingPoints.map(p => ({
point: p,
dist: distance(point, p)
}));
distances.sort((a, b) => a.dist - b.dist);
return distances.slice(0, k);
}
function classify(point, k) {
const nearest = findKNearest(point, k);
const votes = {};
zones.forEach((_, idx) => votes[idx] = 0);
nearest.forEach(n => {
votes[n.point.zone]++;
});
// Trouver la zone avec le plus de votes
let maxVotes = -1;
let predictedZone = -1;
for (let zone in votes) {
if (votes[zone] > maxVotes) {
maxVotes = votes[zone];
predictedZone = parseInt(zone);
}
}
return {
zone: predictedZone,
votes: votes,
nearest: nearest
};
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Dessiner les points d'apprentissage
trainingPoints.forEach(p => {
ctx.beginPath();
ctx.arc(p.x, p.y, 6, 0, 2 * Math.PI);
ctx.fillStyle = zones[p.zone].color;
ctx.fill();
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
ctx.stroke();
});
// Si un point test existe
if (testPoint) {
const classification = classify(testPoint, k);
// Dessiner les lignes vers les k plus proches voisins
classification.nearest.forEach((n, index) => {
ctx.beginPath();
ctx.moveTo(testPoint.x, testPoint.y);
ctx.lineTo(n.point.x, n.point.y);
ctx.strokeStyle = zones[n.point.zone].color;
ctx.globalAlpha = 0.3 + 0.7 * (k - index) / k;
ctx.lineWidth = 2;
ctx.stroke();
ctx.globalAlpha = 1;
});
// Dessiner un cercle autour du k-ième plus proche voisin
if (classification.nearest.length > 0) {
const maxDist = classification.nearest[classification.nearest.length - 1].dist;
ctx.beginPath();
ctx.arc(testPoint.x, testPoint.y, maxDist, 0, 2 * Math.PI);
ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]);
ctx.stroke();
ctx.setLineDash([]);
}
// Dessiner le point test
ctx.beginPath();
ctx.arc(testPoint.x, testPoint.y, 12, 0, 2 * Math.PI);
ctx.fillStyle = '#95a5a6';
ctx.fill();
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.stroke();
// Afficher le résultat
displayResults(classification);
}
}
function displayResults(classification) {
const zoneName = zones[classification.zone].name;
const zoneColor = zones[classification.zone].color;
result.innerHTML = `Classification : <span style="color: ${zoneColor};">${zoneName}</span>`;
result.style.background = zoneColor + '22';
// Afficher les votes
votesDiv.innerHTML = '';
zones.forEach((zone, idx) => {
const voteBox = document.createElement('div');
voteBox.className = 'vote-box';
voteBox.style.background = zone.color + '22';
voteBox.style.borderColor = classification.zone === idx ? zone.color : 'transparent';
const voteCount = classification.votes[idx] || 0;
voteBox.innerHTML = `
<div class="vote-count" style="color: ${zone.color};">${voteCount}</div>
<div class="vote-label">${zone.shortName}</div>
`;
votesDiv.appendChild(voteBox);
});
}
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
testPoint = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
draw();
});
kSlider.addEventListener('input', (e) => {
k = parseInt(e.target.value);
kValue.textContent = k;
draw();
});
function placeRandomPoint() {
testPoint = {
x: Math.random() * (canvas.width - 100) + 50,
y: Math.random() * (canvas.height - 100) + 50
};
draw();
}
function resetPoint() {
testPoint = null;
result.innerHTML = 'Cliquez sur le graphique pour classifier un point';
result.style.background = '#f0f0f0';
votesDiv.innerHTML = '';
draw();
}
// Initialisation
createLegend();
draw();
</script>
</body>
</html>

76
menu.html Normal file
View file

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu déroulant</title>
<style>
/* Styles de base pour le menu */
.menu {
list-style: none;
padding: 0;
margin: 0;
background-color: #333;
}
.menu li {
display: inline-block;
position: relative;
}
.menu a {
display: block;
padding: 15px 20px;
color: white;
text-decoration: none;
}
.menu a:hover {
background-color: #555;
}
/* Styles pour le sous-menu */
.sous-menu {
display: none;
position: absolute;
background-color: #444;
min-width: 200px;
list-style: none;
padding: 0;
margin: 0;
top: 100%;
left: 0;
}
/* Afficher le sous-menu au survol */
.menu li:hover .sous-menu {
display: block;
}
.sous-menu a {
padding: 10px 20px;
}
</style>
</head>
<body>
<ul class="menu">
<li><a href="#">Accueil</a></li>
<li>
<a href="#">Produits</a>
<ul class="sous-menu">
<li><a href="#">Produit 1</a></li>
<li><a href="#">Produit 2</a></li>
<li><a href="#">Produit 3</a></li>
</ul>
</li>
<li>
<a href="#">Services</a>
<ul class="sous-menu">
<li><a href="#">Service A</a></li>
<li><a href="#">Service B</a></li>
</ul>
</li>
<li><a href="#">Contact</a></li>
</ul>
</body>
</html>

4
quick-push.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/bash
git add .
git commit -m "${1:-Auto-update: $(date '+%Y-%m-%d %H:%M:%S')}"
git push