Ce code Python a été développé dans le but de tirer parti de l’API Twitter pour collecter des données sur les abonnés d’un utilisateur donné, puis construire un réseau de relations entre ces abonnés. Ensuite, il effectue une détection de communauté dans ce réseau et enregistre les résultats pour une analyse ultérieure. Examinons en détail les aspects clés de ce code, son intérêt, ses difficultés et ses applications potentielles.
Intérêt:
L’intérêt majeur de ce code réside dans sa capacité à collecter et à analyser les données liées aux abonnés d’un utilisateur Twitter. Voici quelques-uns des avantages de ce script :
- Collecte de données significatives : En interagissant avec l’API Twitter, le code peut recueillir une quantité importante d’informations sur les abonnés d’un utilisateur, y compris leurs noms, descriptions et nombre de followers. Cela permet de mieux comprendre l’audience d’un compte Twitter.
- Analyse des relations : En créant un graphe des relations entre les abonnés et en identifiant des communautés, le code offre une perspective approfondie des connexions entre les utilisateurs. Cela peut être précieux pour les chercheurs en sciences sociales et les professionnels du marketing.
- Modularité et exportation de données : Le script calcule la modularité du réseau, ce qui permet de mesurer la qualité de la détection de communauté. De plus, il exporte le graphe au format GEXF pour une analyse plus avancée dans des outils comme Gephi.
Difficultés:
Le développement et l’exécution de ce code ne sont pas sans défis :
- Limites de l’API Twitter : L’API Twitter impose des restrictions strictes sur le nombre de requêtes autorisées en un certain laps de temps. Gérer ces limites nécessite une planification minutieuse pour collecter efficacement les données.
- Volume de données : La collecte de données sur un grand nombre d’abonnés peut générer une quantité significative de données. Il est essentiel de disposer de suffisamment d’espace de stockage pour les gérer.
Applications:
Ce code peut trouver des applications dans divers domaines, tels que :
- Analyse d’audience Twitter : Les professionnels du marketing peuvent l’utiliser pour mieux comprendre leur public, identifier les segments clés et adapter leurs stratégies de contenu.
- Recherche en sciences sociales : Les chercheurs peuvent exploiter ce script pour étudier les dynamiques des réseaux sociaux en ligne, en analysant comment les utilisateurs se connectent et interagissent.
- Analyse de sentiment : En identifiant des communautés et des groupes de discussion, le code peut être employé pour surveiller et analyser les discussions sur des sujets spécifiques, notamment la détection de tendances et l’analyse de sentiment.
- Études de réseaux sociaux : Les professionnels de la communication et de la sociologie numérique peuvent l’utiliser pour examiner les réseaux sociaux en ligne, en identifiant les leaders d’opinion et les influenceurs.
Un « graph » (ou graphe en français) est un concept fondamental en théorie des graphes et en science des réseaux. Dans ce contexte, un graphe est une structure mathématique qui représente des relations entre des entités. Dans le cadre des réseaux sociaux comme Twitter, un graphe peut être utilisé pour modéliser les relations entre les utilisateurs.
Un graphe se compose généralement de deux composants principaux :
- Nœuds (ou sommets) : Les nœuds représentent les entités ou les individus du réseau. Dans le cas de Twitter, chaque nœud représenterait un utilisateur Twitter. Par conséquent, chaque nœud dans le graphe est associé à un compte Twitter spécifique.
- Liens (ou arêtes) : Les liens représentent les relations ou les connexions entre les entités. Dans le contexte de Twitter, un lien serait une relation de suivi, c’est-à-dire qu’un utilisateur A suit un utilisateur B. Ainsi, les liens connectent les nœuds correspondants aux utilisateurs qui sont connectés sur la plateforme.
Lorsque ces nœuds et liens sont représentés graphiquement, vous obtenez un schéma visuel qui montre comment les utilisateurs sont connectés les uns aux autres. Cette représentation sous forme de graphe peut être très puissante pour comprendre la structure et les dynamiques d’un réseau social comme Twitter.
Visualisation des Communautés :
Dans un réseau social tel que Twitter, les communautés sont des groupes d’utilisateurs qui sont plus étroitement liés les uns aux autres qu’avec le reste du réseau. Ces communautés peuvent se former autour de centres d’intérêt communs, de sujets spécifiques, d’amis en commun, ou d’autres affinités. La visualisation des communautés dans un graphe Twitter peut révéler plusieurs informations importantes :
- Structure communautaire : Les communautés se manifestent sous forme de groupes de nœuds fortement interconnectés. En utilisant des techniques d’analyse de réseau, il est possible de détecter ces groupes et de les visualiser sous forme de clusters.
- Découverte de groupes d’intérêt : Les communautés peuvent indiquer des groupes d’utilisateurs partageant des intérêts similaires. En visualisant les communautés, il est plus facile de repérer ces groupes et de comprendre quels sujets ou quels thèmes les rassemblent.
- Identification d’influenceurs : En examinant les nœuds centraux au sein de chaque communauté, vous pouvez identifier les utilisateurs influents qui jouent un rôle clé dans ces groupes.
- Analyse de sentiment : En attribuant des couleurs ou des étiquettes aux communautés en fonction des sentiments associés aux discussions, vous pouvez visualiser comment les opinions et les émotions circulent au sein du réseau.
En résumé, un graphe représente les relations entre les utilisateurs d’un réseau social comme Twitter, et la visualisation des communautés dans ce graphe permet de mieux comprendre les dynamiques du réseau, d’identifier des groupes d’intérêt et d’explorer les interactions au sein de la plateforme.
Et voici le code.
import tweepy import pandas as pd import time import os import networkx as nx import community # Twitter API client client = tweepy.Client( bearer_token='YOUR_BEARER_TOKEN_HERE', wait_on_rate_limit=True ) # Replace the user and maximum number of primary and secondary followers User_name = '*********' N_followers_primary = 50 N_followers_secondary = 50 # Initialize time start = time.time() # Initialize request count if N_followers_primary <= 1000: Max_resultsP = N_followers_primary else: Max_resultsP = 1000 if N_followers_secondary <= 1000: Max_resultsS = N_followers_secondary else: Max_resultsS = 1000 # Get user ID and optionally their follower count User_id = client.get_user(username=User_name).data.id # Create dataframes df1 = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower']) # Temporary dataframe for usernames df1_ID = pd.DataFrame(columns=['source_ID', 'target_ID']) # Temporary dataframe for IDs Tableau_followers = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower']) # Followers table Tableau_followers_ID = pd.DataFrame(columns=['source_ID', 'target_ID']) # Follower ID table df2 = pd.DataFrame(columns=['source', 'target', 'description', 'Numb_of_follower']) Token = None # Initialize token # Create a directory and file path directory = User_name parent_dir = "C:/Users/.../twitter" Directory_path = os.path.join(parent_dir, directory) File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_0.csv') Num_de_fichier = 0 try: os.mkdir(Directory_path) except OSError: while True: if input('Resume the request? (y/n) ') == "y": try: Tableau_followers_ID_notdone = pd.read_csv( os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv')) # Retrieve saved progress f = open(os.path.join(Directory_path, 'Num_de_fichier.txt'), 'r') Tableau_followers_ID = Tableau_followers_ID_notdone Num_de_fichier = int(f.read()) Tableau_followers = pd.read_csv( os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) +'.csv')) # Retrieve saved progress Num_de_fichier = Num_de_fichier + 1 File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) +'.csv') break except FileNotFoundError: print('File not found') quit() else: print('Stopping') quit() if Num_de_fichier == 0: # Retrieve primary followers while len(Tableau_followers.index) < N_followers_primary: P_followers = client.get_users_followers(id=User_id, max_results=Max_resultsP, user_fields=['public_metrics', 'description'], pagination_token=Token) Token = P_followers.meta.get('next_token') try: for follower in P_followers.data: if follower.get('public_metrics').get('followers_count') != 0: df1 = pd.DataFrame( [[User_name, follower.username, follower.get('description'), follower.get('public_metrics').get('followers_count')]], columns=['source', 'target', 'description', 'Numb_of_follower']) Tableau_followers = pd.concat([Tableau_followers, df1], ignore_index=True) df1_ID = pd.DataFrame([[User_id, follower.id]], columns=['source_ID', 'target_ID']) Tableau_followers_ID = pd.concat([Tableau_followers_ID, df1_ID], ignore_index=True) except TypeError: pass if not Token: break # DataFrame for pending work Tableau_followers_ID_notdone = Tableau_followers_ID df2 = Tableau_followers # Dataframe manipulation df1 = df1.iloc[0:0] # Initialize error variables and counting nb_errors = 0 server_error = 0 FollowerLimit = 0 Token = None # Reset Token Nb_loops = 0 # Retrieve secondary followers try: for i in Tableau_followers_ID.index: print('Progress:', round(i / len(Tableau_followers_ID.index) * 100, 2), '%') print('Elapsed time:', round((time.time() - start) / 60), 'min') FollowerLimit = 0 with open(os.path.join(Directory_path, 'Num_de_fichier.txt'), 'w') as f: f.write(str(Num_de_fichier)) while FollowerLimit < N_followers_secondary: S_followers = client.get_users_followers(id=Tableau_followers_ID['target_ID'][i], max_results=Max_resultsS, user_fields=['public_metrics', 'description'], pagination_token=Token) Token = S_followers.meta.get('next_token') try: for followers in S_followers.data: df1 = pd.DataFrame( [[Tableau_followers['target'][i], followers.username, followers.get('description'), followers.get('public_metrics').get('followers_count')]], columns=['source', 'target', 'description', 'Numb_of_follower']) df2 = pd.concat([df2, df1], ignore_index=True) FollowerLimit += 1 Nb_loops += 1 except TypeError: nb_errors += 1 if not Token: break Tableau_followers_ID_notdone.loc[i:, :].to_csv( os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv')) # Save remaining follower IDs df2.to_csv(File_path, index=False, escapechar='\\') # Save the dataframe if Nb_loops > 10000: # Limit rows to 10,000 Num_de_fichier += 1 File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(Num_de_fichier) + '.csv') Nb_loops = 0 df2 = df2.iloc[0:0] except tweepy.errors.TwitterServerError: server_error += 1 time.sleep(900) print("User data access issues: ", nb_errors) print("Server access issues:", server_error) df2 = df2.iloc[0:0] Tableau_followers = Tableau_followers.iloc[0:0] for i in range(0, Num_de_fichier): df2 = pd.read_csv(os.path.join(Directory_path, 'networkOF_' + User_name + '_' + str(i) + '.csv')) Tableau_followers = pd.concat([Tableau_followers, df2], ignore_index=True) File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '.csv') Tableau_followers.to_csv(File_path, index=False) # Save the final table def delete_files(Directory_path): # List all files in the directory files = os.listdir(Directory_path) # Iterate through all files in the directory for file in files: # Check if the file is in CSV format and if its name ends with an integer if file.endswith('.csv') and file[-5].isdigit(): # Build the full file path file_path = os.path.join(Directory_path, file) # Delete the file os.remove(file_path) # Call the function to delete files delete_files(Directory_path) os.remove(os.path.join(Directory_path, 'Tableau_followers_ID_notdone.csv')) # Remove the remaining follower IDs file os.remove(os.path.join(Directory_path, 'Num_de_fichier.txt')) # Remove the file location end = time.time() print("Execution time (twitter API):", round((end - start) / 3600), 'h') quit() # Create an undirected graph from connections G = nx.from_pandas_edgelist(Tableau_followers, source='source', target='target', create_using=nx.Graph()) # Exclude nodes with fewer than 5 connections G = G.subgraph([node for node, degree in dict(G.degree()).items() if degree >= 5]) # Perform community detection with the Louvain algorithm partition = community.best_partition(G) # Add "description" and "Numb_of_follower" information to each node for node in G.nodes(): if node in Tableau_followers['target'].values: description = Tableau_followers.loc[Tableau_followers['target'] == node, 'description'].values[0] numb_of_follower = Tableau_followers.loc[Tableau_followers['target'] == node, 'Numb_of_follower'].values[0] if pd.notna(description) and description != "": G.nodes[node]['description'] = description if pd.notna(numb_of_follower): G.nodes[node]['Numb_of_follower'] = numb_of_follower # Calculate modularity for each node modularity = community.modularity(partition, G) # Add the modularity class to each node for node, community_id in partition.items(): G.nodes[node]['modularity_class'] = community_id # Export the graph in GEXF format for Gephi File_path = os.path.join(Directory_path, 'networkOF_' + User_name + '.gexf') nx.write_gexf(G, File_path) end = time.time() print("Execution time (network building):", round((end - start) / 3600), 'h')