Pratique de l'analyse de données par Python et pandas (Tokyo COVID-19 data edition)

introduction

Chaque fois que j'ai vu le rapport sur le nombre de nouvelles infections à virus corona, je pensais "Je veux que vous m'en disiez plus sur la répartition par tranche d'âge", mais j'ai appris que Tokyo avait publié des données sur les patients positifs. ..

Ici, nous allons présenter comment analyser et visualiser les données publiées par le gouvernement métropolitain de Tokyo en utilisant Python et pandas, seaborn, Matplotlib.

Le point principal de cet article n'est pas les prédictions et les recommandations selon lesquelles «cela se produira dans le futur» et «ce genre de mesures devrait être prise», mais «cela facilite la visualisation des données, donc tout le monde devrait l'essayer». Si vous l'essayez vous-même, vous approfondirez votre compréhension, alors essayez-le.

Notez que si vous êtes particulier sur les détails tels que la disposition des graphiques et le format des axes, Matplotlib nécessitera un traitement fastidieux, donc je n'entrerai pas dans les détails ici (juste une petite touche à la fin). Plutôt que de créer un beau graphique pour une divulgation généralisée, l'objectif est de visualiser les données et de voir les tendances par vous-même.

Un exemple de code est également disponible sur GitHub. Le bloc-notes Jupyter (.ipynb) est plus facile à lire, veuillez donc vous y référer également.

Aperçu des données

Tokyo

Les données positives des patients pour Tokyo sont publiées ci-dessous.

Vous pouvez y accéder à partir du lien «Obtenir des données ouvertes» du nouveau site de contrôle des infections par le virus corona de Tokyo.

En regardant History, il semble qu'il soit mis à jour de 10 à 15 heures en semaine.

Autres préfectures

Ci-dessous, une liste de sites qui ont bifurqué les sites de contre-mesures à Tokyo.

Certains sites, comme Tokyo, ont des liens vers des données ouvertes. Vous trouverez ci-dessous des exemples des préfectures de Hokkaido et Kanagawa.

Même s'il n'y a pas de lien sur le site, les données elles-mêmes doivent être publiées quelque part, vous pouvez donc les trouver en effectuant une recherche.

L'exemple de code suivant utilise des données de Tokyo. Les données d'autres préfectures peuvent avoir des éléments différents, mais le traitement de base est le même.

Autre informations

En outre, en tant que données liées au nouveau coronavirus, il existe des données agrégées telles que le nombre de tests PCR nationaux effectués, le nombre de positifs, le nombre de personnes hospitalisées et le nombre de décès annoncés par le ministère de la Santé, du Travail et du Bien-être social.

Version de la bibliothèque

Les versions de chaque bibliothèque et de Python lui-même dans l'exemple de code ci-dessous sont les suivantes. Notez que différentes versions peuvent se comporter différemment.

import math
import sys

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

print(pd.__version__)
# 1.0.5

print(mpl.__version__)
# 3.3.0

print(sns.__version__)
# 0.10.1

print(sys.version)
# 3.8.5 (default, Jul 21 2020, 10:48:26) 
# [Clang 11.0.3 (clang-1103.0.32.62)]

Confirmation et prétraitement des données

Spécifiez le chemin vers le fichier CSV téléchargé dans pd.read_csv () et lisez-le comme DataFrame. Les données jusqu'au 31 juillet 2020 sont utilisées à titre d'exemple.

df = pd.read_csv('data/130001_tokyo_covid19_patients_20200731.csv')

Vous pouvez spécifier l'URL directement dans l'argument de pd.read_csv (), mais il est plus sûr de le télécharger localement car il sera accédé plusieurs fois en vain au stade des essais et des erreurs.

# df = pd.read_csv('https://stopcovid19.metro.tokyo.lg.jp/data/130001_tokyo_covid19_patients.csv')

Le nombre de lignes / colonnes et les données au début et à la fin sont les suivants.

print(df.shape)
# (12691, 16)

print(df.head())
#No National Local Public Organization Code Prefecture Name City Ward Town / Village Name Published_Date de début_Date patient_Lieu de résidence Patient_Âge du patient_sexe\
#0 1 130001 Tokyo NaN 2020-01-24 ven NaN Wuhan City, Hubei Province Homme dans la quarantaine
#1 2 130001 Tokyo NaN 2020-01-25 Sat NaN Wuhan City, Province du Hubei Femmes dans la trentaine
#2 3 130001 Tokyo NaN 2020-01-30 Thu NaN Changsha City, Province du Hunan Femmes dans la trentaine
#3 4 130001 Tokyo NaN 2020-02-13 Thu NaN Male dans ses 70 ans à Tokyo
#4 5 130001 Tokyo NaN 2020-02-14 ven NaN Femmes dans la cinquantaine à Tokyo
# 
#patient_Attribut patient_Condition patient_Patient symptôme_Indicateur d'historique de voyage Remarques Drapeau déchargé
# 0    NaN    NaN    NaN           NaN NaN     1.0  
# 1    NaN    NaN    NaN           NaN NaN     1.0  
# 2    NaN    NaN    NaN           NaN NaN     1.0  
# 3    NaN    NaN    NaN           NaN NaN     1.0  
# 4    NaN    NaN    NaN           NaN NaN     1.0  

print(df.tail())
#No National Local Public Organization Code Prefecture Name City Ward Town / Village Name Published_Date de début_Date patient_Lieu de résidence Patient_Âge\
#12686 12532 130001 Tokyo NaN 2020-07-31 ven NaN NaN 70s
#12687 12558 130001 Tokyo NaN 2020-07-31 ven NaN NaN 70s
#12688 12563 130001 Tokyo NaN 2020-07-31 ven NaN NaN 70s
#12689 12144 130001 Tokyo NaN 2020-07-31 ven NaN NaN 80s
#12690 12517 130001 Tokyo NaN 2020-07-31 ven NaN NaN 80s
# 
#patient_Patient de sexe_Attribut patient_Condition patient_Patient symptôme_Indicateur d'historique de voyage Remarques Drapeau déchargé
#12686 Mâle NaN NaN NaN NaN NaN NaN
#12687 Mâle NaN NaN NaN NaN NaN NaN
#12688 Mâle NaN NaN NaN NaN NaN NaN
#12689 Femelle NaN NaN NaN NaN NaN NaN
#12690 Male NaN NaN NaN NaN NaN NaN

Lorsque des données catégorielles telles que ces données sont les principales, il est facile d'obtenir une vue d'ensemble en utilisant des méthodes telles que count (), nunique (), ʻunique () et value_counts () `.

count () renvoie le nombre d'éléments qui ne sont pas la valeur manquante NaN. On peut constater que des informations détaillées telles que les noms, les symptômes et les attributs des villes / quartiers / villes / villages ne sont pas divulguées (pas de données), probablement en raison de la protection de la vie privée.

print(df.count())
# No              12691
#Code national de l'organisation publique locale 12691
#Nom de la préfecture 12691
#Nom de la ville 0
#Publié_Date 12691
#Vue 12691
#Début_Date 0
#patient_Lieu de résidence 12228
#patient_Âge 12691
#patient_Sexe 12691
#patient_Attribut 0
#patient_État 0
#patient_Symptôme 0
#patient_Indicateur d'historique de voyage 0
#Remarque 0
#Drapeau déchargé 7186
# dtype: int64

nunique () renvoie le nombre de types de données. Puisqu'il s'agit de données de Tokyo, le code du gouvernement local national et les noms de préfecture sont tous les mêmes.

print(df.nunique())
# No              12691
#Code national de l'organisation publique locale 1
#Nom de la préfecture 1
#Nom de la ville 0
#Publié_Date 164
#Jour 7
#Début_Date 0
#patient_Lieu de résidence 8
#patient_13 ans
#patient_Sexe 5
#patient_Attribut 0
#patient_État 0
#patient_Symptôme 0
#patient_Indicateur d'historique de voyage 0
#Remarque 0
#Drapeau déchargé 1
# dtype: int64

Pour chaque colonne (= Series), vous pouvez vérifier les éléments uniques et leur nombre (fréquence d'occurrence) avec ʻunique ()etvalue_counts ()`.

print(df['patient_résidence'].unique())
# ['Ville de Wuhan, province du Hubei' 'Ville de Changsha, province du Hunan' 'À Tokyo' 'Hors de la ville' '―' 'enquêter' '-' "'-" nan]

print(df['patient_résidence'].value_counts(dropna=False))
#Tokyo 11271
#En dehors de Tokyo 531
# NaN         463
# ―           336
#En cours d'enquête 85
#Ville de Wuhan, province du Hubei 2
#Ville de Changsha, province du Hunan 1
# '-            1
# -             1
# Name:patient_résidence, dtype: int64

print(df['patient_sexe'].unique())
# ['Masculin' 'Femme' "'-" '―' 'inconnue']

print(df['patient_sexe'].value_counts())
#Homme 7550
#Femme 5132
# '-       7
#Inconnu 1
# ―        1
# Name:patient_sexe, dtype: int64

Cette fois, nous limiterons la cible d'analyse à la date de publication, à l'âge du patient et à l'indicateur de sortie. Pour plus de commodité, changez le nom de la colonne avec rename ().

df = df[['Publié_Date', 'patient_Âge', 'Drapeau déchargé']].copy()

df.rename(columns={'Publié_Date': 'date_str', 'patient_Âge': 'age_org', 'Drapeau déchargé': 'discharged'},
          inplace=True)

print(df)
#          date_str age_org  discharged
# 0      2020-01-24 années 40 1.0
# 1      2020-01-25 30 secondes 1.0
# 2      2020-01-30 30 s 1.0
# 3      2020-02-13 années 70 1.0
# 4      2020-02-14 50 1.0
# ...           ...     ...         ...
# 12686  2020-07-31 années 70 NaN
# 12687  2020-07-31 années 70 NaN
# 12688  2020-07-31 années 70 NaN
# 12689  2020-07-31 années 80 NaN
# 12690  2020-07-31 années 80 NaN
# 
# [12691 rows x 3 columns]

La raison d'utiliser copy () ici est d'empêcher SettingWithCopyWarning. Dans ce cas, les données ne sont pas mises à jour, il n'y a donc aucun problème si vous les laissez seules.

En regardant la colonne de l'ère, elle contient des données telles que ʻinconnu et'-`.

print(df['age_org'].unique())
# ['Quarante' '30 s' 'Années 70' 'Années 50' 'Années 60' 'Années 80' '20 ans' 'Moins de 10 ans' 'Années 90' '10 ans' '100 ans et plus'
#  'inconnue' "'-"]

print(df['age_org'].value_counts())
#Années 20 4166
#30 ans 2714
#Années 40 1741
#50 ans 1362
#Années 60 832
#Années 70 713
#Années 80 455
#Jeune 281
#Années 90 214
#Moins de 10 ans 200
#Inconnu 6
#100 ans et plus de 5
# '-           2
# Name: age_org, dtype: int64

Comme le nombre est petit, je vais l'exclure ici.

df = df[~df['age_org'].isin(['inconnue', "'-"])]

print(df)
#          date_str age_org  discharged
# 0      2020-01-24 années 40 1.0
# 1      2020-01-25 30 secondes 1.0
# 2      2020-01-30 30 s 1.0
# 3      2020-02-13 années 70 1.0
# 4      2020-02-14 50 1.0
# ...           ...     ...         ...
# 12686  2020-07-31 années 70 NaN
# 12687  2020-07-31 années 70 NaN
# 12688  2020-07-31 années 70 NaN
# 12689  2020-07-31 années 80 NaN
# 12690  2020-07-31 années 80 NaN
# 
# [12683 rows x 3 columns]

print(df['age_org'].unique())
# ['Quarante' '30 s' 'Années 70' 'Années 50' 'Années 60' 'Années 80' '20 ans' 'Moins de 10 ans' 'Années 90' '10 ans' '100 ans et plus']

Puisque la division d'âge est bonne, rendez-la un peu plus rugueuse. Tout le côté droit est entre parenthèses () car il se brise au milieu.

df['age'] = (
    df['age_org'].replace(['Moins de 10 ans', '10 ans'], '0-19')
    .replace(['20 ans', '30 s'], '20-39')
    .replace(['Quarante', 'Années 50'], '40-59')
    .replace(['Années 60', 'Années 70', 'Années 80', 'Années 90', '100 ans et plus'], '60-')
)

print(df['age'].unique())
# ['40-59' '20-39' '60-' '0-19']

print(df['age'].value_counts())
# 20-39    6880
# 40-59    3103
# 60-      2219
# 0-19      481
# Name: age, dtype: int64

La colonne de date et d'heure (date de publication) date_str est une chaîne de caractères. Pour un traitement ultérieur, ajoutez la colonne «date» convertie en type «datetime64 [ns]».

df['date'] = pd.to_datetime(df['date_str'])

print(df.dtypes)
# date_str              object
# age_org               object
# discharged           float64
# age                   object
# date          datetime64[ns]
# dtype: object

C'est la fin du prétraitement. De là, un exemple d'analyse et de visualisation des données est montré.

Évolution du nombre de nouveaux patients positifs par groupe d'âge

Ici, nous examinons l'évolution du nombre de nouveaux patients positifs par groupe d'âge. Le nombre total de nouveaux patients positifs sera décrit à la fin à titre d'exemple de traitement avec Matplotlib.

Graphique à barres empilées

Utilisez pd.crosstab () pour croiser la date et l'heure (date de publication) et l'âge.

df_ct = pd.crosstab(df['date'], df['age'])

print(df_ct)
# age         0-19  20-39  40-59  60-
# date                               
# 2020-01-24     0      0      1    0
# 2020-01-25     0      1      0    0
# 2020-01-30     0      1      0    0
# 2020-02-13     0      0      0    1
# 2020-02-14     0      0      1    1
# ...          ...    ...    ...  ...
# 2020-07-27     5     79     34   13
# 2020-07-28    13    168     65   20
# 2020-07-29     9    160     56   25
# 2020-07-30    11    236     83   37
# 2020-07-31    10    332     82   39
# 
# [164 rows x 4 columns]

print(type(df_ct.index))
# <class 'pandas.core.indexes.datetimes.DatetimeIndex'>

La colonne convertie au type datetime64 [ns] devient un nouvel index et est traitée comme DatetimeIndex. Notez que même si la sortie est la même, si vous spécifiez une date et une heure de type chaîne, ce ne sera pas DatetimeIndex.

Agréger chaque semaine avec resample (). resample () ne peut être exécuté qu'avec DatetimeIndex.

df_ct_week = df_ct.resample('W', label='left').sum()

print(df_ct_week)
# age         0-19  20-39  40-59  60-
# date                               
# 2020-01-19     0      1      1    0
# 2020-01-26     0      1      0    0
# 2020-02-02     0      0      0    0
# 2020-02-09     0      2      5    9
# 2020-02-16     0      1      3    6
# 2020-02-23     0      2      3    5
# 2020-03-01     2      5      9    9
# 2020-03-08     0      5     10   11
# 2020-03-15     0     10     27   12
# 2020-03-22     7    100     88  102
# 2020-03-29    16    244    198  148
# 2020-04-05    21    421    369  271
# 2020-04-12    30    350    375  280
# 2020-04-19    32    286    267  264
# 2020-04-26    29    216    165  260
# 2020-05-03     7    105     69  120
# 2020-05-10     2     46     16   46
# 2020-05-17     3     22     10   15
# 2020-05-24     4     43     16   21
# 2020-05-31     2     89     34   22
# 2020-06-07     5    113     17   26
# 2020-06-14     6    177     29   28
# 2020-06-21    10    236     65   23
# 2020-06-28    34    460    107   51
# 2020-07-05    79    824    191   68
# 2020-07-12    66   1006    295  117
# 2020-07-19    78   1140    414  171
# 2020-07-26    48    975    320  134

Visualisé avec plot (). Vous pouvez facilement créer un graphique à barres empilées.

df_ct_week[:-1].plot.bar(stacked=True)

bar_ct_week.png

Les données de la dernière ligne (la semaine dernière) sont exclues par «[: -1]». Ces données excluent la semaine dernière car elles n'incluent pas le samedi (1er août 2020) et ne sont pas appropriées pour être comparées aux autres semaines.

Le bloc-notes Jupyter affiche le graphique dans la cellule de sortie. Si vous voulez l'enregistrer en tant que fichier image, utilisez plt.savefig (). Vous pouvez également cliquer avec le bouton droit pour enregistrer la sortie du bloc-notes Jupyter.

plt.figure()
df_ct_week[:-1].plot.bar(stacked=True)
plt.savefig('image/bar_chart.png', bbox_inches='tight')
plt.close('all')

La condition d'occurrence est inconnue, mais il y a eu un problème lié à la coupure de l'étiquette de l'axe X lors de l'enregistrement. Reportez-vous à ce qui suit et définissez bbox_inches = 'tight' pour résoudre le problème.

Si vous créez un graphique à barres tel qu'il est comme dans l'exemple ci-dessus, l'heure sera affichée sur l'étiquette de l'axe X. La solution la plus simple consiste à convertir l'index en une chaîne dans n'importe quel format.

df_ct_week_str = df_ct_week.copy()
df_ct_week_str.index = df_ct_week_str.index.strftime('%Y-%m-%d')

df_ct_week_str[:-1].plot.bar(stacked=True, figsize=(8, 4))

bar_ct_week_str.png

Normaliser l'ensemble et voir la transition du ratio d'âge. «T» est la translocation (permuter les lignes et les colonnes). Il peut être normalisé en le transposant, en le divisant par la valeur totale, en le transloquant à nouveau et en le ramenant à la valeur d'origine.

La plupart des jeunes (20-30 ans) ont fermé depuis juin, mais récemment, le pourcentage de personnes d'âge moyen (40 ans et plus) augmente.

df_ct_week_str_norm = (df_ct_week_str.T / df_ct_week_str.sum(axis=1)).T

bar_ct_week_str_norm.png

Les changements entre les jeunes (20-30 ans) et les personnes âgées (60 ans et plus) sont les suivants. Le nombre absolu de personnes âgées a également augmenté pour atteindre le niveau de fin mars.

df_ct_week_str[:-1][['20-39', '60-']].plot.bar(figsize=(8, 4))

bar_ct_week_str_young_old.png

Graphique en ligne brisée (par rapport à la semaine précédente)

Pour voir l'élan de la propagation de l'infection, calculez le changement par rapport à la semaine précédente.

Les données peuvent être décalées et divisées par shift ().

df_week_ratio = df_ct_week / df_ct_week.shift()

print(df_week_ratio)
# age             0-19      20-39     40-59       60-
# date                                               
# 2020-01-19       NaN        NaN       NaN       NaN
# 2020-01-26       NaN   1.000000  0.000000       NaN
# 2020-02-02       NaN   0.000000       NaN       NaN
# 2020-02-09       NaN        inf       inf       inf
# 2020-02-16       NaN   0.500000  0.600000  0.666667
# 2020-02-23       NaN   2.000000  1.000000  0.833333
# 2020-03-01       inf   2.500000  3.000000  1.800000
# 2020-03-08  0.000000   1.000000  1.111111  1.222222
# 2020-03-15       NaN   2.000000  2.700000  1.090909
# 2020-03-22       inf  10.000000  3.259259  8.500000
# 2020-03-29  2.285714   2.440000  2.250000  1.450980
# 2020-04-05  1.312500   1.725410  1.863636  1.831081
# 2020-04-12  1.428571   0.831354  1.016260  1.033210
# 2020-04-19  1.066667   0.817143  0.712000  0.942857
# 2020-04-26  0.906250   0.755245  0.617978  0.984848
# 2020-05-03  0.241379   0.486111  0.418182  0.461538
# 2020-05-10  0.285714   0.438095  0.231884  0.383333
# 2020-05-17  1.500000   0.478261  0.625000  0.326087
# 2020-05-24  1.333333   1.954545  1.600000  1.400000
# 2020-05-31  0.500000   2.069767  2.125000  1.047619
# 2020-06-07  2.500000   1.269663  0.500000  1.181818
# 2020-06-14  1.200000   1.566372  1.705882  1.076923
# 2020-06-21  1.666667   1.333333  2.241379  0.821429
# 2020-06-28  3.400000   1.949153  1.646154  2.217391
# 2020-07-05  2.323529   1.791304  1.785047  1.333333
# 2020-07-12  0.835443   1.220874  1.544503  1.720588
# 2020-07-19  1.181818   1.133201  1.403390  1.461538
# 2020-07-26  0.615385   0.855263  0.772947  0.783626

df_week_ratio['2020-05-03':'2020-07-25'].plot(grid=True)

line_week_ratio.png

En juillet, le taux hebdomadaire a diminué dans chaque groupe d'âge.

De plus, contrairement au graphique à barres, lors de la création d'un graphique linéaire avec plot () (ou plot.line ()), les données de date et d'heure sur l'axe X sont formatées de manière appropriée comme dans l'exemple ci-dessus. Notez qu'il peut ne pas être formaté en fonction du contenu des données de date et d'heure comme décrit plus loin.

Carte de chaleur

Créer une carte thermique comme autre approche pour saisir la transition du nombre de nouveaux patients positifs par groupe d'âge.

Ici, le groupe d'âge détaillé est utilisé tel quel. Tableau croisé avec pd.crosstab () comme dans l'exemple du graphique à barres empilées. Puisque resample () n'est pas utilisé, la date et l'heure date_str du type chaîne de caractères sont spécifiées. L'axe horizontal est transposé avec «T» pour régler la date et l'heure, et le côté inférieur de l'axe vertical est transposé avec «[:: -1]» pour inverser la disposition des lignes après translocation.

df['age_detail'] = df['age_org'].replace(
    {'Moins de 10 ans': '0-9', '10 ans': '10-19', '20 ans': '20-29', '30 s': '30-39', 'Quarante': '40-49', 'Années 50': '50-59',
     'Années 60': '60-69', 'Années 70': '70-79', 'Années 80': '80-89', 'Années 90': '90-', '100 ans et plus': '90-'}
)

df_ct_hm = pd.crosstab(df['date_str'], df['age_detail']).T[::-1]

La fonction seaborn heatmap () est utile pour créer des heatmaps.

plt.figure(figsize=(15, 5))
sns.heatmap(df_ct_hm, cmap='hot')

heatmap.png

On peut confirmer que l'infection s'est progressivement propagée aux personnes âgées depuis juin.

Voir ci-dessous pour les cartes thermiques à l'échelle logarithmique. J'ai reçu un avertissement, mais cela a fonctionné pour le moment.

Notez que s'il y a «0» dans les données, une erreur se produira, donc le processus approximatif de remplacement de «0» par «0,1» est effectué.

df_ct_hm_re = df_ct_hm.replace({0: 0.1})

min_value = df_ct_hm_re.values.min()
max_value = df_ct_hm_re.values.max()

log_norm = mpl.colors.LogNorm(vmin=min_value, vmax=max_value)
cbar_ticks = [math.pow(10, i) for i in range(math.floor(math.log10(min_value)),
                                             1 + math.ceil(math.log10(max_value)))]

plt.figure(figsize=(15, 5))
sns.heatmap(df_ct_hm_re, norm=log_norm, cbar_kws={"ticks": cbar_ticks})

heatmap_log.png

Au fait, j'ai appris l'idée de visualiser avec une carte thermique en regardant l'exemple de la Floride dans l'article suivant.

@Zorinaq, qui a créé le graphique de Floride, a publié le code pour créer divers graphiques tels que les prévisions futures en plus de la carte thermique. Cela semble difficile sans une certaine connaissance de Python, mais si vous êtes intéressé, vous voudrez peut-être jeter un coup d'œil.

Drapeau déchargé

point important

Comme le montre le résultat de count () ci-dessus, il y a 7186 cas où l'indicateur déchargé est "1" dans les données publiques, mais [Nouveau site de contrôle des maladies infectieuses du coronavirus à Tokyo](https: / /stopcovid19.metro.tokyo.lg.jp/) "Décharge, etc. (y compris la fin de la période de traitement médical)" est 9615 (mise à jour à 20h30 le 31 juillet 2020).

tokyo_stopcovid.png

Je ne sais pas si la réflexion des données est simplement retardée ou pour une raison quelconque, mais veuillez noter que le drapeau déchargé des données publiques peut être différent de la situation actuelle.

Graphique à barres empilées

Similaire à l'exemple de la transition du nombre de personnes positives par tranche d'âge, la transition du drapeau déchargé est visualisée dans un graphique à barres empilées. La valeur manquante «NaN» est remplacée par «0» en tant que prétraitement.

print(df['discharged'].unique())
# [ 1. nan]

df['discharged'] = df['discharged'].fillna(0).astype('int')

print(df['discharged'].unique())
# [1 0]

print(pd.crosstab(df['date'], df['discharged']).resample('W', label='left').sum()[:-1].plot.bar(stacked=True))

bar_discharged_all.png

Si vous êtes préoccupé par l'heure affichée sur l'axe X, vous pouvez convertir la date et l'heure de l'index en une chaîne de caractères, comme dans l'exemple des changements du nombre de positifs par tranche d'âge. Je le laisse ici. Il en va de même pour les exemples suivants.

Ce graphique montre le pourcentage de drapeaux déchargés par date de publication. Bien sûr, la plupart des personnes qui ont été confirmées positives pendant une longue période (= la date de publication est ancienne) ont été libérées (= le drapeau déchargé est «1»).

Vérifiez par tranche d'âge. Dans pd.crosstab (), si vous spécifiez plusieurs colonnes dans la liste, le résultat sera obtenu sous la forme d'un multi-index.

df_dc = pd.crosstab(df['date'], [df['age'], df['discharged']]).resample('W', label='left').sum()

print(df_dc)
# age        0-19     20-39      40-59       60-     
# discharged    0   1     0    1     0    1    0    1
# date                                               
# 2020-01-19    0   0     0    1     0    1    0    0
# 2020-01-26    0   0     0    1     0    0    0    0
# 2020-02-02    0   0     0    0     0    0    0    0
# 2020-02-09    0   0     0    2     0    5    0    9
# 2020-02-16    0   0     0    1     0    3    0    6
# 2020-02-23    0   0     0    2     0    3    0    5
# 2020-03-01    0   2     0    5     0    9    0    9
# 2020-03-08    0   0     0    5     0   10    1   10
# 2020-03-15    0   0     0   10     0   27    0   12
# 2020-03-22    0   7     0  100     0   88    2  100
# 2020-03-29    0  16     1  243     4  194    9  139
# 2020-04-05    0  21     5  416     1  368   11  260
# 2020-04-12    1  29     0  350     6  369   10  270
# 2020-04-19    2  30     3  283     6  261   17  247
# 2020-04-26    1  28     8  208     4  161   33  227
# 2020-05-03    1   6     6   99     5   64   23   97
# 2020-05-10    0   2     7   39     3   13    8   38
# 2020-05-17    2   1    10   12     2    8    9    6
# 2020-05-24    3   1    18   25     8    8    5   16
# 2020-05-31    0   2    13   76     8   26    9   13
# 2020-06-07    1   4    17   96     7   10   12   14
# 2020-06-14    3   3    84   93    13   16   17   11
# 2020-06-21    4   6    75  161    18   47    8   15
# 2020-06-28    4  30    37  423    19   88   20   31
# 2020-07-05   44  35   211  613    92   99   46   22
# 2020-07-12   62   4   803  203   250   45  113    4
# 2020-07-19   78   0  1140    0   414    0  171    0
# 2020-07-26   48   0   975    0   320    0  134    0

Les graphiques des jeunes et des personnes âgées sont les suivants.

df_dc[:-1]['20-39'].plot.bar(stacked=True)

bar_discharged_young.png

df_dc[:-1]['60-'].plot.bar(stacked=True)

bar_discharged_old.png

Comme vous pouvez l'imaginer, le pourcentage de personnes âgées dont la date de sortie n'est pas fixée à «1» est plus élevé même si la date de publication est plus ancienne, et il semble que l'hospitalisation soit plus susceptible d'être prolongée.

Standardisez pour rendre le rapport plus facile à voir.

x_young = df_dc[9:-1]['20-39']
x_young_norm = (x_young.T / x_young.sum(axis=1)).T

print(x_young_norm)
# discharged         0         1
# date                          
# 2020-03-22  0.000000  1.000000
# 2020-03-29  0.004098  0.995902
# 2020-04-05  0.011876  0.988124
# 2020-04-12  0.000000  1.000000
# 2020-04-19  0.010490  0.989510
# 2020-04-26  0.037037  0.962963
# 2020-05-03  0.057143  0.942857
# 2020-05-10  0.152174  0.847826
# 2020-05-17  0.454545  0.545455
# 2020-05-24  0.418605  0.581395
# 2020-05-31  0.146067  0.853933
# 2020-06-07  0.150442  0.849558
# 2020-06-14  0.474576  0.525424
# 2020-06-21  0.317797  0.682203
# 2020-06-28  0.080435  0.919565
# 2020-07-05  0.256068  0.743932
# 2020-07-12  0.798211  0.201789
# 2020-07-19  1.000000  0.000000

x_young_norm.plot.bar(stacked=True)

bar_discharged_young_norm.png

x_old = df_dc[9:-1]['60-']
x_old_norm = (x_old.T / x_old.sum(axis=1)).T

print(x_old_norm)
# discharged         0         1
# date                          
# 2020-03-22  0.019608  0.980392
# 2020-03-29  0.060811  0.939189
# 2020-04-05  0.040590  0.959410
# 2020-04-12  0.035714  0.964286
# 2020-04-19  0.064394  0.935606
# 2020-04-26  0.126923  0.873077
# 2020-05-03  0.191667  0.808333
# 2020-05-10  0.173913  0.826087
# 2020-05-17  0.600000  0.400000
# 2020-05-24  0.238095  0.761905
# 2020-05-31  0.409091  0.590909
# 2020-06-07  0.461538  0.538462
# 2020-06-14  0.607143  0.392857
# 2020-06-21  0.347826  0.652174
# 2020-06-28  0.392157  0.607843
# 2020-07-05  0.676471  0.323529
# 2020-07-12  0.965812  0.034188
# 2020-07-19  1.000000  0.000000

x_old_norm.plot.bar(stacked=True)

bar_discharged_old_norm.png

Les pourcentages de jeunes et de personnes âgées dont les drapeaux déchargés ne sont pas réglés sur «1» sont indiqués ci-dessous. Après tout, les personnes âgées ont tendance à rester à l'hôpital plus longtemps.

pd.DataFrame({'20-39': x_young_norm[0], '60-': x_old_norm[0]}).plot.bar()

bar_discharged_young_old_norm.png

Traité par Matplotlib

Les exemples jusqu'à présent ont été relativement faciles à gérer en utilisant le plot () de DataFrame et la fonction seaborn, mais dans certains cas, ils doivent être gérés par Matplotlib.

Prenons l'exemple de la transition du nombre total de nouveaux positifs.

Ici, value_counts () est utilisé pour compter les colonnes de date et d'heure et calculer le nombre total de nouveaux positifs pour chaque date de publication. Notez que si vous ne triez pas par sort_index (), ils seront classés par ordre décroissant.

s_total = df['date'].value_counts().sort_index()

print(s_total)
# 2020-01-24      1
# 2020-01-25      1
# 2020-01-30      1
# 2020-02-13      1
# 2020-02-14      2
#              ... 
# 2020-07-27    131
# 2020-07-28    266
# 2020-07-29    250
# 2020-07-30    367
# 2020-07-31    463
# Name: date, Length: 164, dtype: int64

print(type(s_total))
# <class 'pandas.core.series.Series'>

print(type(s_total.index))
# <class 'pandas.core.indexes.datetimes.DatetimeIndex'>

Contrairement aux exemples précédents, il s'agit de «Series» au lieu de «DataFrame», mais l'idée est la même dans les deux cas.

Lorsqu'un graphique à barres est généré avec plot.bar (), les axes X se chevauchent comme indiqué ci-dessous.

s_total.plot.bar()

bar_total_ng.png

Dans l'exemple de la semaine précédente, j'ai écrit que si vous utilisez plot () pour générer un graphique linéaire, cela formatera la date et l'heure de manière appropriée, mais cela ne fonctionnera pas.

s_total.plot()

line_total_ng.png

Il semble que la raison pour laquelle plot () ne fonctionne pas est que les données de date et d'heure dans l'index ne sont pas périodiques (je suis désolé si c'est différent car je ne l'ai pas étudié en détail).

Dans l'exemple par rapport à la semaine précédente, les données hebdomadaires existaient sans omission, mais dans cet exemple, les données sont disponibles à la date et à l'heure où le nombre de personnes positives telles que «2020-01-26» et «2020-01-27» est «0». N'existe pas.

En utilisant reindex () et pd.date_range (), ajoutez des données avec la valeur "0" même à la date et à l'heure où le nombre de positifs est "0".

s_total_re = s_total.reindex(
    index=pd.date_range(s_total.index[0], s_total.index[-1]),
    fill_value=0
)

print(s_total_re)
# 2020-01-24      1
# 2020-01-25      1
# 2020-01-26      0
# 2020-01-27      0
# 2020-01-28      0
#              ... 
# 2020-07-27    131
# 2020-07-28    266
# 2020-07-29    250
# 2020-07-30    367
# 2020-07-31    463
# Freq: D, Name: date, Length: 190, dtype: int64

Cela formatera la date et l'heure de manière appropriée avec plot (). Au fait, si vous souhaitez utiliser l'échelle logarithmique, logy = True.

s_total_re.plot()

line_total_ok.png

s_total_re.plot(logy=True)

line_total_ok_log.png

Même dans ce cas, plot.bar () est inutile.

s_total_re.plot.bar()

bar_total_ng_2.png

Pour les types autres que les graphiques linéaires, Matplotlib doit les gérer.

Définissez Formatter et Locator, et générez un graphique avec bar () de Matplotlib.

fig, ax = plt.subplots(figsize=(12, 4))

ax.xaxis.set_major_locator(mpl.dates.AutoDateLocator())
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%Y-%m-%d'))

ax.xaxis.set_tick_params(rotation=90)

ax.bar(s_total.index, s_total)

bar_total_ok.png

Set_yscale ('log') si vous voulez une échelle log.

fig, ax = plt.subplots(figsize=(12, 4))

ax.xaxis.set_major_locator(mpl.dates.AutoDateLocator())
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%Y-%m-%d'))

ax.xaxis.set_tick_params(rotation=90)

ax.set_yscale('log')

ax.bar(s_total.index, s_total)

bar_total_ok_log.png

Si vous voulez ajouter une ligne moyenne mobile, utilisez rolling ().

print(s_total.rolling(7).mean())
# 2020-01-24           NaN
# 2020-01-25           NaN
# 2020-01-30           NaN
# 2020-02-13           NaN
# 2020-02-14           NaN
#                  ...    
# 2020-07-27    252.285714
# 2020-07-28    256.428571
# 2020-07-29    258.142857
# 2020-07-30    258.285714
# 2020-07-31    287.285714
# Name: date, Length: 164, dtype: float64

fig, ax = plt.subplots(figsize=(12, 4))

ax.xaxis.set_major_locator(mpl.dates.AutoDateLocator())
ax.xaxis.set_minor_locator(mpl.dates.DayLocator())
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%Y-%m-%d'))

ax.xaxis.set_tick_params(labelsize=12)
ax.yaxis.set_tick_params(labelsize=12)

ax.grid(linestyle='--')
ax.margins(x=0)

ax.bar(s_total.index, s_total, width=1, color='#c0e0c0', edgecolor='black')
ax.plot(s_total.index, s_total.rolling(7).mean(), color='red')

bar_total_with_ma.png

Dans l'exemple ci-dessus, certains paramètres ont été ajoutés pour référence. margins (x = 0) est la troncature des marges gauche et droite. Vous pouvez spécifier la couleur par nom ou code couleur.

à la fin

Les données ouvertes au public sont limitées, mais je pense que vous pouvez approfondir votre compréhension en jouant avec vous-même. Veuillez l'essayer.

Recommended Posts

Pratique de l'analyse de données par Python et pandas (Tokyo COVID-19 data edition)
Analyse des données financières par pandas et leur visualisation (2)
Analyse de données à l'aide de pandas python
Essayez de gratter les données COVID-19 Tokyo avec Python
Créez un arbre de décision à partir de zéro avec Python et comprenez-le (3. Bibliothèque d'analyse de données édition Pandas)
Livres et sources recommandés de programmation d'analyse de données (Python ou R)
Exercice pratique d'analyse de données avec Python ~ 2016 New Coder Survey Edition ~
Acquisition automatique des données de niveau d'expression génique par python et R
Exemple d'analyse de squelette tridimensionnelle par Python
Pandas du débutant, par le débutant, pour le débutant [Python]
Analyse d'image de microtomographie à rayons X par Python
Analyse de données python
[CovsirPhy] Package Python COVID-19 pour l'analyse des données: chargement des données
[Python] Analyse de données, pratique du machine learning (Kaggle) -Prétraitement des données-
Calcul des indicateurs techniques par TA-Lib et pandas
Analyse émotionnelle des données de tweet à grande échelle par NLTK
Environnement enregistré pour l'analyse des données avec Python
Fonctionnement de base de Python Pandas Series et Dataframe (1)
Analyse des données de pratique Python Résumé de l'apprentissage que j'ai atteint environ 10 avec 100 coups
[Python] De l'analyse morphologique des données CSV à la sortie CSV et à l'affichage graphique [GiNZA]
[Python] Comparaison de la théorie de l'analyse des composants principaux et de l'implémentation par Python (PCA, Kernel PCA, 2DPCA)
Pratique de création d'une plateforme d'analyse de données avec BigQuery et Cloud DataFlow (traitement de données)
Analyse de données avec python 2
Obtenez une grande quantité de données Twitter de Starba avec python et essayez l'analyse de données Partie 1
[Python] [Word] [python-docx] Analyse simple des données de diff en utilisant python
Liste des bibliothèques Python pour les data scientists et les data ingénieurs
Présentation de l'analyse de données python
Construction d'un environnement d'analyse de données avec Python (notebook IPython + Pandas)
Défiez l'analyse des composants principaux des données textuelles avec Python
Récapitulatif des méthodes Pandas utilisées lors de l'extraction de données [Python]
Histoire de l'analyse d'image du fichier PDF et de l'extraction de données
Liste du code Python utilisé dans l'analyse de Big Data
[CovsirPhy] Package Python COVID-19 pour l'analyse de données: modèle SIR-F
[CovsirPhy] Package Python COVID-19 pour l'analyse des données: analyse des tendances S-R
Modèle d'analyse de données Python
[CovsirPhy] Package Python COVID-19 pour l'analyse des données: modèle SIR
Analyse des données de mesure (2) -Hydrobacter et raccord, recommandation lmfit-
[CovsirPhy] Package Python COVID-19 pour l'analyse des données: estimation des paramètres
Comment visualiser les données par variable explicative et variable objective
[Mémo du débutant Python] Importance et méthode de confirmation de la valeur manquante NaN avant l'analyse des données
Analyse de données avec Python
[CovsirPhy] Package Python COVID-19 pour l'analyse de données: analyse de scénario (comparaison de paramètres)
Effectuer une analyse isocurrent des canaux en eau libre avec Python et matplotlib
■ Kaggle Practice pour les débutants - Introduction de Python - par Google Colaboratory
Application de Python: Nettoyage des données Partie 3: Utilisation d'OpenCV et prétraitement des données d'image
20200329_Introduction à l'analyse de données avec Python 2nd Edition Personal Summary
Débarrassez-vous des données sales avec Python et les expressions régulières
Analyse des données basée sur les résultats des élections du gouverneur de Tokyo (2020)
Récupérer les données souhaitées du site Web en liant Python et Excel
[Introduction to Data Scientists] Bases de Python ♬ Fonctions et classes
Graphique des données de séries chronologiques en Python à l'aide de pandas et matplotlib
Comparaison de la gestion des trames de données en Python (pandas), R, Pig
[Python] Extraction / combinaison de données aléatoires à partir de DataFrame en utilisant random et pandas
Mon conteneur d'analyse de données python
Série Python 2 et série 3 (édition Anaconda)
Python pour l'analyse des données Chapitre 4
Analyse statique des programmes Python
Visualisation des données par préfecture
Notes d'apprentissage sur l'analyse des données Python
Python pour l'analyse des données Chapitre 2
Installation source et installation de Python