visualiser une évolution de tweets

Attention, ce snack est du fast food tendance junk food.

L’ami Stéphane Wharton voulait un coup d’oeuil sur l’analyse de sentiment qu’il a opéré sur les tweets d’un député d’extrême-droite ayant tenu des propos racistes à l’assemblée. Ne faisant pas une veille sur le sujet, les questions qui semblent pertinente sont :

  • quel est la tonalité habituelle des propos du député sur twitter ?
  • est-ce que certaines tonalités ont un fonctionnement différent en terme d’audience ?

Comme on peut le voir, la fréquence de tweets et le nombre total de retweets ne suivent pas vraiment la même tendance. la distribution de retweets entre tweets positifs et négatifs n’est pas vraiment la même non plus.

On peut voir que les tweets du personnage sont perçus négativement par le modéle et que cette négativité engendre plus de réactions depuis mi 2021. Ces réactions peuvent être positives comme négatives mais elles génèrent du bruit et amplifie ainsi la portée de son discours.

la tambouille

Le détail des calculs peut être utile pour voir comment réduire les irrégularités cycliques en aggrégeant les tweets à la semaine et en opérant une moyenne glissante.

import pandas as pd
import matplotlib.pyplot as plt
sentiments = (
    pd
    .read_csv('https://raw.githubusercontent.com/stefw/gdf/main/gdefournasxlm-robertaok_withnature.csv')
    .set_index('id')
)

sentiments
colors = {
    'Negative': '#FF4136',
    'Neutral': '#DDDDDD',
    'Positive': '#7FDBFF'
}
sentiments_evolution = (
    sentiments
    .assign(
        local_time = lambda df: pd.to_datetime(df.local_time),
        date = lambda df: pd.to_datetime(df.local_time).dt.to_period('W')
    )
    .reset_index()
    .groupby(['date', 'sentiment'])
    .agg({
        'id': 'count',
        'retweet_count': ['sum', 'mean'],
        'like_count': ['sum', 'mean']
    })
    .reset_index()
    .pivot_table(
        index='date',
        columns='sentiment',
        fill_value=0
    )
)

sentiments_evolution

graphique d’évolution des tweets

(
    sentiments_evolution
    [('id', 'count')]
    .rolling(50)
    .mean()
    .plot
    .area(
        figsize=(15,10),
        color=colors,
        title='évolution du nombre de tweets par semaine'
    )
)

plt.savefig('graphics/twitter-gdf-count.png')

graphique d’évolution des retweets

(
    sentiments_evolution
    [('retweet_count', 'sum')]
    .rolling(50)
    .mean()
    .plot
    .area(
        figsize=(15,10),
        color=colors,
        title='évolution du nombre de retweets par semaine'
    )
)

plt.savefig('graphics/twitter-gdf-retweets.png')

tableau de synthèse

sentiments_yearly = (
    sentiments
    .assign(
        local_time = lambda df: pd.to_datetime(df.local_time),
        date = lambda df: pd.to_datetime(df.local_time).dt.to_period('Y')
    )
    .reset_index()
    .groupby(['date', 'sentiment'])
    .agg({
        'like_count': ['mean', 'sum'],
        'retweet_count': ['mean', 'sum'] 
    })
    .reset_index()
    .pivot_table(
        index='date',
        columns='sentiment'
    )
)

sentiments_yearly
/tmp/ipykernel_505791/203913093.py:2: PerformanceWarning: dropping on a non-lexsorted multi-index without a level parameter may impact performance.
  sentiments
/tmp/ipykernel_505791/203913093.py:2: PerformanceWarning: dropping on a non-lexsorted multi-index without a level parameter may impact performance.
  sentiments
like_count retweet_count
mean sum mean sum
sentiment Negative Neutral Positive Negative Neutral Positive Negative Neutral Positive Negative Neutral Positive
date
2014 0.277966 0.440860 0.474026 82.0 41.0 73.0 0.816949 1.172043 0.883117 241.0 109.0 136.0
2015 1.693467 1.462185 2.043860 337.0 174.0 233.0 5.065327 3.243697 4.745614 1008.0 386.0 541.0
2016 3.577320 3.760563 3.930481 1388.0 534.0 735.0 5.979381 8.056338 5.673797 2320.0 1144.0 1061.0
2017 3.893750 5.742574 7.697143 1246.0 1160.0 1347.0 5.012500 6.831683 8.622857 1604.0 1380.0 1509.0
2018 6.803828 4.545455 6.405405 1422.0 300.0 474.0 4.956938 2.606061 3.297297 1036.0 172.0 244.0
2019 6.817391 5.645570 7.728571 1568.0 446.0 541.0 5.121739 5.949367 4.300000 1178.0 470.0 301.0
2020 9.156627 13.728972 27.608696 2280.0 1469.0 1905.0 5.449799 7.158879 11.260870 1357.0 766.0 777.0
2021 38.865052 26.384000 23.614286 11232.0 3298.0 1653.0 17.231834 10.648000 7.557143 4980.0 1331.0 529.0
2022 140.068452 15.488889 70.910569 47063.0 2091.0 8722.0 45.199405 4.622222 18.910569 15187.0 624.0 2326.0