title title

Coronavirus - La France se prépare à l'épidémie. Les principales inquiétudes des Français sur les COVID-19 avec les données de Google Trends

L'émergence récente d'un nouveau coronavirus (2019-nCoV) a gagné une large couverture dans les médias publics et les nouvelles mondiales. C' est une brève introduction sur comment Google Trends nous permet de découvrir les préoccupations et les requêtes les plus populaires sur cette nouvelle épidémie en la France.

Source de données

Les données collectées auprès de Google Trends présentent les requêtes les plus populaires des utilisateurs.

L'intérêt plus populaire sur la requête de recherche est exprimé par 100, tandis que le manque d'intérêt ou le nombre insuffisant de données est exprimé par 0. Les requêtes sont collectées à partir de cinq moteurs de recherche spécialisés: Web, Image, News, Google Shopping et Recherche YouTube.

Les données sont récupérées depuis la première mention de cette maladie par Google, en novembre 2019. Les données proviennent de Web Search for France.

Les tendances seront comparées au marché boursier français (CAC 40).

Il sera également analysé la tendance de la date de cette étude, afin de connaître les requêtes les plus fréquentes, la situation géographique et la tendance des requêtes les plus fréquentes

Une mise en garde importante concernant les données de Google Trends: elles ne révèlent pas exactement combien de personnes recherchent un terme donné, elles donnent simplement une idée de la hausse ou de la baisse de popularité de ce terme.

Méthodes et résultats

Configurer les modules et les packages en python

In [1]:
# !pip install pytrends
import numpy as np
import matplotlib.pyplot as plt
from datetime import date, datetime, timedelta
from pytrends.request import TrendReq
import time
import pandas as pd
import matplotlib
import gtrend   
import seaborn as sns
from pandas.io.json import json_normalize
from pandas.plotting import scatter_matrix

plt.style.use('seaborn-darkgrid')
matplotlib.rcParams['font.family'] = ['DejaVu Sans']
def rmax(maxrow: int=50):
    pd.set_option('display.max_rows', maxrow)

def cmax(maxcol: int=50):
    pd.set_option('display.max_columns', maxcol)

Configurer les termes et conditions de la requête

In [2]:
pytrend = TrendReq(hl='fr-FR', tz=60)
keyword = 'coronavirus'
start = '2019-10-01'
end = '2020-04-26'
geo='FR'
cat=0
gprop=''

sont consultées les données de tendance Google quotidiennes pendant plus de 5 mois en concaténant plusieurs requêtes et normaliser (scaling) en fonction de la période de chevauchement (overlapping method)

In [3]:
overlapping = gtrend.get_daily_trend(pytrend, keyword, start, end, geo=geo, cat=cat, gprop=gprop, verbose=True, tz=60)
Fetching 'coronavirus' for period:2019-08-01 2020-04-26
Fetching 'coronavirus' for period:2019-02-13 2019-11-09
Normalize by overlapping period:2019-08-01 2019-11-09
Normalize by overlapping period:2020-04-20 2020-04-24
In [4]:
overlapping.plot(figsize=(15,10))
Out[4]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a0b6aea978>

Acquérir des données de tendance Google quotidiennes pendant plus de 5 mois en concaténant plusieurs requêtes non chevauchantes de 1 mois et normaliser (scaling) par valeur de tendance hebdomadaire de la même période. (pytrends dailydata.py method)

In [5]:
from pytrends import dailydata

start_d = datetime.strptime(start, '%Y-%m-%d')
end_d = datetime.strptime(end, '%Y-%m-%d')
s_year = start_d.year
s_mon = start_d.month
e_year = end_d.year
e_mon = end_d.month

dailydata = dailydata.get_daily_data(word= keyword,
                 start_year= s_year,
                 start_mon= s_mon,
                 stop_year= e_year,
                 stop_mon= e_mon,
                 geo= geo,
                 verbose= False,
                 wait_time = 1.0)
In [6]:
print(dailydata.columns)
dailydata[f'{keyword}'].plot(figsize=(15,10))
Index(['coronavirus_unscaled', 'coronavirus_monthly', 'isPartial', 'scale',
       'coronavirus'],
      dtype='object')
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a0b6aea978>

Les données de tendance hebdomadaire pourraient être une référence pour comparer les méthodes de normalisation ci-dessus. Pour une période de requête comprise 120 jours (~ 4 mois), la tendance google renverra des données weely. Pour avoir une échelle d'axe comparable, les données hebdomadaires sont interpolées pour obtenir des données quotidiennes.

In [7]:
tf = start_d.strftime('%Y-%m-%d')+' '+end_d.strftime('%Y-%m-%d')
pytrend.build_payload(kw_list=[keyword], cat=cat, geo=geo, gprop=gprop, timeframe=tf)
week = pytrend.interest_over_time()
week_interp = week.resample('D').mean()
week_interp[f'{keyword}'] = week_interp[f'{keyword}'].interpolate()
In [8]:
week_interp.drop(columns='isPartial', inplace=True)
In [9]:
week_interp.plot(figsize=(15,10))
Out[9]:
<matplotlib.axes._subplots.AxesSubplot at 0x1a0b6b175f8>

Pour une meilleure comparaison visuelle, rassemblons les 3 ensembles de données.

In [10]:
overlapping.loc[:,keyword]
Out[10]:
2019-10-01 01:00:00     0.0
2019-10-02 01:00:00     0.0
2019-10-03 01:00:00     0.0
2019-10-04 01:00:00     0.0
2019-10-05 01:00:00     0.0
                       ... 
2020-04-21 01:00:00    20.0
2020-04-22 01:00:00    21.0
2020-04-23 01:00:00    28.0
2020-04-24 01:00:00    20.0
2020-04-25 01:00:00    20.0
Freq: D, Name: coronavirus, Length: 208, dtype: float64
In [11]:
overlapping.columns
Out[11]:
Index(['coronavirus', 'overlap'], dtype='object')
In [12]:
combined = pd.concat([overlapping, dailydata.loc[:,keyword], week_interp], axis=1)
In [13]:
combined.tail(20)
Out[13]:
coronavirus overlap coronavirus coronavirus
2020-04-15 01:00:00 36.0 NaN NaN NaN
2020-04-16 00:00:00 NaN NaN 24.85 35.0
2020-04-16 01:00:00 34.0 NaN NaN NaN
2020-04-17 00:00:00 NaN NaN 23.46 34.0
2020-04-17 01:00:00 33.0 NaN NaN NaN
2020-04-18 00:00:00 NaN NaN 26.60 35.0
2020-04-18 01:00:00 34.0 NaN NaN NaN
2020-04-19 00:00:00 NaN NaN 23.43 33.0
2020-04-19 01:00:00 32.0 NaN NaN NaN
2020-04-20 00:00:00 NaN NaN 11.27 23.0
2020-04-20 01:00:00 22.0 1.0 NaN NaN
2020-04-21 00:00:00 NaN NaN 9.45 21.0
2020-04-21 01:00:00 20.0 1.0 NaN NaN
2020-04-22 00:00:00 NaN NaN 9.66 21.0
2020-04-22 01:00:00 21.0 1.0 NaN NaN
2020-04-23 00:00:00 NaN NaN 16.80 28.0
2020-04-23 01:00:00 28.0 1.0 NaN NaN
2020-04-24 00:00:00 NaN NaN 9.45 21.0
2020-04-24 01:00:00 20.0 1.0 NaN NaN
2020-04-25 01:00:00 20.0 NaN NaN NaN
In [14]:
combined.columns = ['overlapping method','overlap period', 'dailydata method', 'weekly data']
combined = combined.resample('D').mean()
In [15]:
import matplotlib.dates as mdates
from cycler import cycler
from matplotlib.cm import get_cmap

combined2 = combined.iloc[:, [0,2,3,1]]
combined2.index = [pd.to_datetime(date, format='%Y-%m-%d').date() for date in combined2.index]
# c = ['royalblue', 'darkorange', 'limegreen', 'salmon']
# colors = plt.cm.Paired(np.linspace(0,1,4)) # This returns RGBA; convert:
c = []
for i in range(0,4):
    c.append(matplotlib.colors.rgb2hex(plt.cm.tab10(i)))
ax = combined2.plot(figsize=(15,10), color=c)
# set line colors
# c = plt.cm.hot(np.linspace(0,1,4))
# ax.set_prop_cycle(cycler('color', c))
# ax.set_prop_cycle(color=colors)
# ax.set_prop_cycle('color',plt.cm.Spectral(np.linspace(0,1,30)))
# set monthly locator
ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_minor_locator(mdates.MonthLocator(bymonthday=15))
# set formatter
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
ax.xaxis.set_minor_formatter(mdates.DateFormatter('%b'))

ax.tick_params(direction='out', pad=20)
# set font and rotation for date tick labels
# plt.gcf().autofmt_xdate()
ax.xaxis.grid(True, which='minor')

plt.ylabel('Relative Search Trends')
plt.xlabel('Date')
plt.title('Daily Google Trends Value pour \'coronavirus\' depuis '+start+' to '+end)
# plt.set_cmap('Pastel2')

plt.show()

La figure montre que l'intérêt pour le coronavirus en France a commencé à partir de janvier 2020. Il est visible dans la ligne de tendance, que l'intérêt croissant s'accélère avec les premiers cas signalés en France et atteint des valeurs maximales en mars, peut-être en raison de la mesures gouvernementales extrêmes pour protéger l'épidémie par les pays des Union Européenne.

In [16]:
 ax.get_lines()[0].get_color(), ax.get_lines()[1].get_color(), ax.get_lines()[2].get_color(), ax.get_lines()[3].get_color()
Out[16]:
('#1f77b4', '#ff7f0e', '#2ca02c', '#d62728')
In [17]:
combined['overlap period'].fillna(value='0', inplace=True)
combined.tail(20)
Out[17]:
overlapping method overlap period dailydata method weekly data
2020-04-06 41.0 0 36.49 41.0
2020-04-07 40.0 0 35.67 41.0
2020-04-08 40.0 0 34.40 40.0
2020-04-09 37.0 0 30.78 38.0
2020-04-10 37.0 0 28.86 37.0
2020-04-11 31.0 0 20.77 31.0
2020-04-12 29.0 0 17.98 29.0
2020-04-13 39.0 0 31.98 39.0
2020-04-14 35.0 0 26.60 35.0
2020-04-15 36.0 0 28.86 37.0
2020-04-16 34.0 0 24.85 35.0
2020-04-17 33.0 0 23.46 34.0
2020-04-18 34.0 0 26.60 35.0
2020-04-19 32.0 0 23.43 33.0
2020-04-20 22.0 1 11.27 23.0
2020-04-21 20.0 1 9.45 21.0
2020-04-22 21.0 1 9.66 21.0
2020-04-23 28.0 1 16.80 28.0
2020-04-24 20.0 1 9.45 21.0
2020-04-25 20.0 0 NaN NaN

Concentrons-nous sur une période plus courte, comme 2020 janvier à 2020 avril où les données de tendance varient beaucoup et 3 méthodes ont donné des valeurs assez différentes. Dans ce cas, nous pouvons même récupérer les «vraies» données quotidiennes directement à partir de la tendance google (période inférieure à 5 mois) sans faire de mise à l'échelle / traitement pour comparaison.

In [18]:
p_start = '2020-01-20'
p_end = '2020-04-26'
# p_start_d = datetime.strptime(p_start, '%Y-%m-%d')
# p_end_d = datetime.strptime(p_end, '%Y-%m-%d')
tf = p_start+' '+p_end
geo='FR'
pytrend.build_payload(kw_list=[keyword], cat=cat, geo=geo, gprop=gprop, timeframe=tf)
daily_real = pytrend.interest_over_time()
In [19]:
combined_period = combined.loc[p_start:p_end]
combined_period  = pd.concat([combined_period,daily_real], axis=1)
combined_period.drop(columns=['isPartial','overlap period'], inplace=True)
combined_period.columns = ['overlapping method', 'dailydata method', 'weekly data', 'original data']
In [20]:
c = []
for i in range(0,7):
    c.append(matplotlib.colors.rgb2hex(plt.cm.tab10(i)))
c
Out[20]:
['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2']
In [21]:
#combined_period.plot(figsize=(15,10))
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU

combined2 = combined_period.copy()
combined2.index = [pd.to_datetime(date, format='%Y-%m-%d').date() for date in combined2.index]
c = ['#1f77b4', '#ff7f0e', '#2ca02c', '#e377c2']
ax = combined2.plot(figsize=(15,10), color=c)
# set weekday locator
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=TU))
# set formatter
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
# set font and rotation for date tick labels
plt.gcf().autofmt_xdate()

plt.ylabel('Relative Search Trends')
plt.xlabel(None)
plt.title('Daily Google Trends Value pour \'coronavirus\' depuis '+p_start+' to '+p_end)




plt.show()

Les données quotidiennes ont évidemment une différence plus grande que les valeurs réelles et hebdomadaires, mais cette valeur ajustée suit la même tendance que les autres.

Les recherches de "coronavirus" ont été multipliées par sept environ depuis le 25 février, coïncidant avec le premier décès dû à cette maladie https://www.lefigaro.fr/sciences/coronavirus-avec-6-nouveaux-cas-et-1-mort-en-moins-de-48-heures-la-surveillance-se-complique-en-france-20200226

title

Examinons maintenant le comportement de la Bourse française avec l'indice des prix du CAC 40 et les tendances de recherche de Google dans le coronavirus identifiées ci-dessus.

In [24]:
import yfinance as yf

ticker = yf.Ticker("^FCHI")
print(ticker)
ticker.info
frstock = ticker.history(start=start, end=end)
yfinance.Ticker object <^FCHI>
In [25]:
combined_stock = pd.concat([combined, frstock.Close], axis=1)
combined_stock.drop(columns=['dailydata method', 'overlap period'], inplace=True)
In [26]:
combined_stock.columns = ['daily trends', 'weekly trends', 'CAC40 stock price']
In [27]:
combined_stock.head()
Out[27]:
daily trends weekly trends CAC40 stock price
2019-10-01 0.0 0.0 5597.63
2019-10-02 0.0 0.0 5422.77
2019-10-03 0.0 0.0 5438.77
2019-10-04 0.0 0.0 5488.32
2019-10-05 0.0 0.0 NaN
In [28]:
cor_fr = pd.merge(combined2, combined_stock,left_index=True, right_index=True)
In [29]:
fig = plt.figure()
ax = combined2.plot(figsize=(20,10), color=c)
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=TU))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))

ax2 = ax.twinx()
ax2.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=TU))
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
CAC40 = ax2.plot(cor_fr['CAC40 stock price'], color='black')
ax2.legend(['CAC40 stock price'])

l = ax.get_ylim()
l2 = ax2.get_ylim()
f = lambda x : l2[0]+(x-l[0])/(l[1]-l[0])*(l2[1]-l2[0])
ticks = f(ax.get_yticks())
ax2.yaxis.set_major_locator(matplotlib.ticker.FixedLocator(ticks))

plt.gcf().autofmt_xdate()

ax.set_ylabel('Tendances relatives de la recherche Google %')
ax2.set_ylabel('CAC40 stock price € ')
plt.title('Daily Google Trends Value pour \'coronavirus\' depuis '+p_start+' to '+p_end)

plt.show()
<Figure size 432x288 with 0 Axes>

Ce graphique montre comment le scepticisme des investisseurs sur les mesures de soutien économique, la guerre des prix sur le marché du pétrole et le reclassement de l'épidémie de Covid-19 en "pandémie" n'a pas favorisé la Bourse de Paris.

title

Analyser les termes de recherche et les domaines les plus intéressants pour France

In [30]:
pytrend.build_payload(kw_list=['coronavirus'], geo = 'FR', timeframe = 'now 1-d')
interest_over_time_df = pytrend.interest_over_time()
In [31]:
print(interest_over_time_df.tail())
                     coronavirus isPartial
date                                      
2020-04-26 16:56:00           66     False
2020-04-26 17:04:00           72     False
2020-04-26 17:12:00           73     False
2020-04-26 17:20:00           75     False
2020-04-26 17:28:00           70      True
In [32]:
interest_by_region_df = pytrend.interest_by_region()
In [33]:
interest_by_region_df.sort_values(by = 'coronavirus', ascending = True).plot.barh()
plt.title('Daily Google Trends Value par Coronavirus par Région Française')
Out[33]:
Text(0.5, 1.0, 'Daily Google Trends Value par Coronavirus par Région Française')

Il s'agit d'une répartition de la popularité par zone géographique des recherches google associées au coronavirus en la France

In [34]:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(color_codes= False)
dx = interest_over_time_df.plot.line(figsize = (12,9),title = "Tendance horaire relatives de la recherche Google en France")
dx.set_xlabel('GMT +1 Time', fontsize = 15)
dx.set_ylabel('search',fontsize = 15)
dx.tick_params(axis='both', which='major', labelsize=13)

Nous voyons en détail les consultations d'aujourd'hui 11 mars et comment la fréquence se concentre sur les heures du matin, du midi et de la nuit en dehors des heures de travail

In [38]:
kw_list= ['coronavirus']

pytrend.build_payload(kw_list=kw_list, geo = 'FR', timeframe = '2019-10-01 2020-04-26')
related_queries= pytrend.related_queries()
print(related_queries)
{'coronavirus': {'top':                                                 query  value
0                                  france coronavirus    100
1                                      le coronavirus     58
2                                     cas coronavirus     21
3   merci à tous ceux qui aident à combattre le co...     20
4                                              italie     19
5                                  coronavirus italie     19
6                               coronavirus en france     17
7                                coronavirus conseils     14
8                                   coronavirus carte     12
9                                    coronavirus mort     11
10                               coronavirus symptome     11
11                            coronavirus attestation     10
12                                  coronavirus chine     10
13                                  chine coronavirus     10
14                                  coronavirus monde     10
15                             coronavirus france cas      9
16                            confinement coronavirus      8
17                                             corona      8
18                                  coronavirus bilan      8
19                          coronavirus nombre de cas      7
20                                 direct coronavirus      6
21                                  coronavirus paris      6
22                                   info coronavirus      6
23                                  morts coronavirus      6
24                                  deces coronavirus      5, 'rising':                                                 query    value
0                                  france coronavirus  1828600
1                                      le coronavirus  1066800
2                                     cas coronavirus   380600
3   merci à tous ceux qui aident à combattre le co...   370250
4                                              italie   352500
5                                  coronavirus italie   342200
6                               coronavirus en france   303900
7                                coronavirus conseils   260100
8                                   coronavirus carte   216550
9                                    coronavirus mort   204250
10                               coronavirus symptome   200500
11                            coronavirus attestation   184850
12                                  coronavirus chine   183850
13                                  chine coronavirus   183000
14                                  coronavirus monde   174000
15                             coronavirus france cas   160300
16                            confinement coronavirus   153800
17                                             corona   147450
18                                  coronavirus bilan   140200
19                          coronavirus nombre de cas   118900
20                                 direct coronavirus   117450
21                                  coronavirus paris   113600
22                                   info coronavirus   102100
23                                  morts coronavirus   101150
24                                  deces coronavirus    92800}}
In [39]:
type(related_queries)
Out[39]:
dict
In [40]:
related = related_queries['coronavirus']['top']
related
Out[40]:
query value
0 france coronavirus 100
1 le coronavirus 58
2 cas coronavirus 21
3 merci à tous ceux qui aident à combattre le co... 20
4 italie 19
5 coronavirus italie 19
6 coronavirus en france 17
7 coronavirus conseils 14
8 coronavirus carte 12
9 coronavirus mort 11
10 coronavirus symptome 11
11 coronavirus attestation 10
12 coronavirus chine 10
13 chine coronavirus 10
14 coronavirus monde 10
15 coronavirus france cas 9
16 confinement coronavirus 8
17 corona 8
18 coronavirus bilan 8
19 coronavirus nombre de cas 7
20 direct coronavirus 6
21 coronavirus paris 6
22 info coronavirus 6
23 morts coronavirus 6
24 deces coronavirus 5
In [41]:
grows = related_queries['coronavirus']['rising']
grows
Out[41]:
query value
0 france coronavirus 1828600
1 le coronavirus 1066800
2 cas coronavirus 380600
3 merci à tous ceux qui aident à combattre le co... 370250
4 italie 352500
5 coronavirus italie 342200
6 coronavirus en france 303900
7 coronavirus conseils 260100
8 coronavirus carte 216550
9 coronavirus mort 204250
10 coronavirus symptome 200500
11 coronavirus attestation 184850
12 coronavirus chine 183850
13 chine coronavirus 183000
14 coronavirus monde 174000
15 coronavirus france cas 160300
16 confinement coronavirus 153800
17 corona 147450
18 coronavirus bilan 140200
19 coronavirus nombre de cas 118900
20 direct coronavirus 117450
21 coronavirus paris 113600
22 info coronavirus 102100
23 morts coronavirus 101150
24 deces coronavirus 92800
In [47]:
pytrend = TrendReq()
pytrend.build_payload(kw_list=['cas coronavirus', 'coronavirus en france', 'chine coronavirus', 'italie','coronavirus symptome'], geo = 'FR', timeframe = 'today 3-m')
interest_over_time_df = pytrend.interest_over_time()
plt.show()
In [46]:
sns.set(color_codes= False)
dx2 = interest_over_time_df.plot.line(figsize = (15,9),title = "Principales tendances relatives de la recherche Google en France")
dx2.set_xlabel('Time GMT +1', fontsize = 12)
dx2.set_ylabel('Relative Google Search Trends',fontsize = 12)
dx2.tick_params(axis='both', which='major', labelsize=12)
plt.show()