Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Les UV : des agents mutagènes. Approche épidémiologique avec Pandas GeoPandas et Koala

Les UV : des agents mutagènes. Approche épidémiologique.

Les UV (région du spectre éléctro-magniétique comprise ente 10 nm et 400 nm) sont connus depuis longtemps pour être des agents mutagènes (agents augmentant la fréquence des mutations). Les dimères de thymine induits par les UV provoquent des mésappariements lors de la réplication conduisant ainsi à des mutations. Lorsque ces mutations affectent des mélanocytes du derme ou de l’épiderme, cela peut causer des mélanomes ou cancers de la peau.

Les expérimentations menées notamment chez les levures (exposées à des doses et/ou durées variables d’UV) confirment l’effet mutagène des UV. Ce type d’expériences ne pouvant être mené chez des humains pour des raisons éthiques , une approche épidémiologique s’impose donc pour vérifier l’effet mutagène des UV chez l’humain.

Importez les modules nécessaires.

import pandas as pd 
import geopandas as gp 
import matplotlib.pyplot as plt
import numpy as np

from mpl_toolkits.axes_grid1 import make_axes_locatable

from koala import Koala

Le module koala est disponible sur github

Importez les bases de données.

La base UV est disponible ici au format .xlsx
uvv = pd.read_excel("https://gis.cancer.gov/tools/uv-exposure/uv-county.xlsx")
Les bases "mélanome" sont disponibles ici au format .csv

On utilisera 2 bases: une pour toutes les ethnies et une pour les blancs non hispaniques (les personnes à la peau noire et les hispaniques sont moins touchés par le mélanome ce qui pourrait avoir une incidence sur les résultats en raison du % variable d’afro-américains et d’hispaniques selon les états)

Dans chacune des 2 bases utilisées, la colonne Crude Rate indique le nombre de cas pour 100 000 personnes

Les 2 bases sont également disponibles sur ipfs: melanome.csv , melanome_blanc.csv

all_mela = pd.read_csv("melanome.csv", skiprows=2)

white_mela = pd.read_csv("melanome_blanc.csv", skiprows=2)

On supprime les 2 premières lignes d’informations lors de l’importation sinon ca bug avec pandas

La base geojson des états d'amérique est disponible ici au format .geojson

On l’importe avec GeoPandas:

usa = gp.read_file("usastates.geojson")

On obtient un GeoDataFrame.

Modification de la base UV (DataFrame uvv)

Cette base contient le taux d’UV en Wh/m2 par ville, il faut donc calculer la moyenne par état.

Création d'un DataFrame vide avec colonne state et uvrate

uv = pd.DataFrame({"state":(), "uvrate":()})

Création d'une liste (pd.Series) des états américains

state = uvv.STATENAME
state = state.drop_duplicates()

Pour chaque état on calcule la moyenne des "uvrate" de l'ensemble des villes de l'état, puis on crée une ligne qu'on ajoute au DataFrame uv

for i in state:
    x = uvv[uvv.STATENAME == i]
    m = x.mean()
    r = pd.DataFrame([(i, m[1])], columns = ("state", "uvrate"))
    uv = uv.append(r)	

On ré-indexe:

uv.index = range(49)

Modification des bases mélanome

Pour la base toutes ethnies

On supprime les informations présentes sur les lignes 49 à 53:

cc = all_mela.drop([49,50,51,52,52,53])

On range et on ré-indexe:

cc = cc.sort_values(by=['United States'])

cc.index = range(49)

On élimine les colonnes inutiles, en ne conservant que united states, crude rate, et age-adjusted rate:

cc = cc.loc[:,['United States', 'Crude Rate', 'Age-adjusted Rate']]

On renomme les colonnes:

cc.columns = ['state', 'Crude Rate', 'Age-adjusted Rate']

(La colonne "state" doit être commune à toutes les bases pour permettre d’indexer sur cette colonne lorsqu’on les assemblera)

Pour la base blancs non hispaniques

On fait la même modification sauf qu’il n’y a pas de ligne 53

ccw = white_mela.drop([49,50,51,52])

ccw = ccw.sort_values(by=['United States'])

ccw.index = range(49)

ccw = ccw.loc[:,['United States', 'Crude Rate', 'Age-adjusted Rate']]

ccw.columns = ['state', 'Crude Rate W', 'Age-adjusted Rate W']

Assemblage des 3 bases

On utilise la méthode .join et on indexe les 3 bases sur leur colonne ‘state’

ccuv  = cc.join(uv.set_index('state'), on='state')

ccuv = ccuv.join(ccw.set_index('state'), on='state')

Modification du GeoDataFrame usa states:

On crée une liste de colonnes:

x = list(usa.columns)

On modifie le nom de la colonne 6:

x[6] = 'state'

usa.columns = x

On supprime toutes les colonnes sauf la colonne ‘state’ et la colonne ‘geometry’

x.remove('state')
x.remove('geometry')

usa = usa.drop(columns = x)

On assemble le GeoDataFrame usa avec le DataFrame ccuv obtenu précédemment, en indexant encore sur la colonne ‘state’:

ccuvusa = usa.join(ccuv.set_index('state'), on='state')

On supprime l’Alaska, Puerto Rico et Hawaï (sinon ca "élargie" trop la carte):

ccuvusa = ccuvusa.drop([7,17,34]) 

On supprime les états pour lesquels il manque des données:

ccuvusa = ccuvusa.drop([10,14,46]) 

On sauvegarde le GeoDataFrame au format geojson:

ccuvusa.to_file("baseUV.geojson", driver='GeoJSON')

baseUV.geojson

Affichage graphique.

Carte UV:
plt.close()

fig, ax = plt.subplots(1, 1)

divider = make_axes_locatable(ax)

cax = divider.append_axes("right", size="5%", pad=0.1)

ccuvusa.plot(column='uvrate', ax=ax, legend=True, cax=cax)

plt.title('UV Wh/m2', fontsize=6)

plt.savefig("uvrate.png")	
Carte mélanome toutes ethnies:
plt.close()

fig, ax = plt.subplots(1, 1)

divider = make_axes_locatable(ax)

cax = divider.append_axes("right", size="5%", pad=0.1)

ccuvusa.plot(column='Crude Rate', ax=ax, legend=True, cax=cax)

plt.title("Melanoma per 100000", fontsize=6) 

plt.savefig("cancer.png")
Carte mélanome blancs non hispaniques:
plt.close()

fig, ax = plt.subplots(1, 1)

divider = make_axes_locatable(ax)

cax = divider.append_axes("right", size="5%", pad=0.1)

ccuvusa.plot(column='Crude Rate W', ax=ax, legend=True, cax=cax)

plt.title("Melanoma per 100000 White", fontsize=5)

plt.savefig("cancerW.png")




Les corrélations mélanomes (toutes ethnies ou population blanche) / taux d´UV ne semblent pas évidentes lorsqu’on compare les cartes visuellement !

Mélanomes toutes ethnies Taux d’UV Mélanomes population blanche
genome_trio comparaison_sequences uv_levure

On va donc mesurer ces corrélations avec Koala.

Régressions avec Koala

Koala permet avec la méthode reg de tester simultanément les régressions linéaire, exponentielle et puissance, tout en affichant les droites de régression et en retournant les équations de ces droites ainsi que les coefficients de corrélation.

On rappelle que le coefficient de corrélations R est compris entre -1 (corrélation négative) et 1 (corrélation positive), et qu’une corrélation est d’autant plus forte que R est proche de 1 ou de -1.

plt.close()

k = Koala(ccuvusa)

rall = k.reg("uvrate", "Crude Rate")

rall.plt.savefig("canceruvall.png")
rwhite = k.reg("uvrate", "Crude Rate W")

rwhite.plt.savefig("canceruvwhite.png")

Dans tous les cas on s’aperçoit que les corrélations sont très mauvaises (proche de 0):

>>> rall.lin.r
-0.40153153897104943

>>> rall.exp.r
-0.42431332286138584

>>> rall.pwr.r
-0.4263730816599278

>>> rwhite.lin.r
0.1530027636233132

>>> rwhite.exp.r
0.14227221269991572

>>> rwhite.pwr.r
0.13763196949543993

Les corrélations sont encore plus mauvaises lorsqu’on utilise les taux de mélanomes ajustés (colonne Age-adjusted Rate).

Le manuel Belin programme 2011 suggère cette corrélation (sans donner le coefficient de corrélation) en combinant sur la même carte index UV et mortalité par mélanome:

Vu de loin , en clignant des yeux et en tournant la tête on peut imaginer une corrélation positive, cependant on ne nous donne pas de coefficient de corrélation pour vérifier cela. Certains états comme le Nouveau Mexique posent un peu problème !

⚠️ Belin utilise la mortalité par mélanome dans la population blanche, alors que les données utilisées ici portent sur l’incidence du mélanome.

On peut obtenir le même type de graphique avec geopandas en superposant les couches graphiques.

Superposition des couches graphiques UV et mélanome white.

On réalise d’abord la carte mélanome par état:

plt.close()

fig, ax = plt.subplots(1, 1)

divider = make_axes_locatable(ax)

cax = divider.append_axes("right", size="5%", pad=0.1)

base = ccuvusa.plot(column='Crude Rate W', ax=ax, legend=True, cax=cax)

plt.title("Melanoma per 100000 White", fontsize=5)

Puis on crée un nouveau GeoDataFrame ayant une colonne geometry contenant non plus des polygones mais des points (points centraux de chaque polygone), et on conserve les colonnes geometry et uvrate:

On copie le GeoDataFrame ccuvusa en l’affectant à une nouvelle variable pt:

pt = ccuvusa

On ajoute une colonne center contenant les coordonnées du point central de chaque état:

pt['center'] = pt.geometry.centroid

On conserve les colonnes center et uvrate:

pt = pt.loc[:, ['center', 'uvrate']]

On renomme la colonne center en geometry:

pt.columns = ['geometry', 'uvrate']

On prend l’exponentielle de l’UVrate/1000 le tout /2 pour "étaler" les valeurs, sinon on ne distinguera pas la différence de diamètre des cercles représentant l’uvrate sur la carte.

ms = np.exp(pt.uvrate / 1000) / 2

On plot en superposant sur la carte mélanome

pt.plot(ax=ax, color='red', marker='o', legend=True,  markersize=ms)

plt.savefig("uvcancerW.png")

Le diamètre de chaque cercle rouge est proportionnel au taux d’UV dans l’etat.

Critiques:

Les données utilisées proviennent de sources fiables: NAACCR (North American Association of Central Cancer Registries) pour les bases "mélanome", et NCI (National Cancer Institute) pour la base UV. Il manque cependant des données pour 3 états; l’échantillon de données et donc relativement petit (48 états) pour mesurer une corrélation significative. Par ailleurs , le fait qu’il n’y ait pas de corrélation linéaire , puissance , ou exponentielle, ne signifie pas qu’il n’y a pas de corrélation (la corrélation pourrait être d’un autre type).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment