53、大数据案例:MongoDB存储推特数据及可视化分析

大数据案例:MongoDB存储推特数据及可视化分析

1. 引言

在大数据时代,如何高效地存储和分析海量数据是一个关键问题。本文将介绍如何使用MongoDB存储推特数据,并通过Folium库将数据可视化展示在地图上。

2. 环境准备

在开始之前,我们需要完成以下准备工作:
1. 配置MongoDB Atlas集群,并获取连接字符串。
2. 准备好Twitter API的认证信息,包括 consumer_key consumer_secret access_token access_token_secret
3. 准备好 senators.csv 文件,该文件包含美国参议员的相关信息。
4. 准备好 state_codes.py 文件,该文件包含美国各州的代码和全称的映射关系。
5. 准备好 keys.py 文件,用于存储各种API的密钥。

3. 数据处理流程

下面是整个数据处理的流程图:

graph LR
    A[获取连接字符串] --> B[认证Twitter API]
    B --> C[加载参议员数据]
    C --> D[配置MongoClient]
    D --> E[设置推特流]
    E --> F[启动推特流]
    F --> G[存储推特数据]
    G --> H[统计每位参议员的推特数量]
    H --> I[获取各州位置信息]
    I --> J[按州分组推特数量]
    J --> K[创建地图]
    K --> L[创建热力图]
    L --> M[创建地图标记]
    M --> N[保存地图]
4. 详细步骤
4.1 认证Twitter API

使用Tweepy库进行Twitter API的认证:

import tweepy, keys
auth = tweepy.OAuthHandler(
    keys.consumer_key, keys.consumer_secret)
auth.set_access_token(keys.access_token, 
    keys.access_token_secret)
api = tweepy.API(auth, wait_on_rate_limit=True, 
                 wait_on_rate_limit_notify=True)
4.2 加载参议员数据

使用pandas库加载 senators.csv 文件,并将 TwitterID 列转换为字符串类型:

import pandas as pd
senators_df = pd.read_csv('senators.csv')
senators_df['TwitterID'] = senators_df['TwitterID'].astype(str)
pd.options.display.max_columns = 6

查看数据的前几行:

senators_df.head()

输出结果如下:
| State | Name | Party | TwitterHandle | TwitterID |
| — | — | — | — | — |
| AL | Richard Shelby | R | SenShelby | 21111098 |
| AL | Doug Jomes | D | SenDougJones | 941080085121175552 |
| AK | Lisa Murkowski | R | lisamurkowski | 18061669 |
| AK | Dan Sullivan | R | SenDanSullivan | 2891210047 |
| AZ | Jon Kyl | R | SenJonKyl | 24905240 |

4.3 配置MongoClient

使用pymongo库连接到MongoDB Atlas集群,并获取 senators 数据库:

from pymongo import MongoClient
atlas_client = MongoClient(keys.mongo_connection_string)
db = atlas_client.senators
4.4 设置推特流

指定要下载的推特数量,并创建 TweetListener 对象:

from tweetlistener import TweetListener
tweet_limit = 10000
twitter_stream = tweepy.Stream(api.auth, 
    TweetListener(api, db, tweet_limit))
4.5 启动推特流

使用 filter 方法启动推特流,跟踪参议员的 TwitterHandle TwitterID

twitter_stream.filter(track=senators_df.TwitterHandle.tolist(),
    follow=senators_df.TwitterID.tolist())
4.6 TweetListener类

TweetListener 类用于处理接收到的推特数据,并将其存储到MongoDB中:

# tweetlistener.py
"""TweetListener downloads tweets and stores them in MongoDB."""
import json
import tweepy

class TweetListener(tweepy.StreamListener):
    """Handles incoming Tweet stream."""

    def __init__(self, api, database, limit=10000):
        """Create instance variables for tracking number of tweets."""
        self.db = database
        self.tweet_count = 0
        self.TWEET_LIMIT = limit  # 10,000 by default
        super().__init__(api)  # call superclass's init

    def on_connect(self):
        """Called when your connection attempt is successful, enabling 
        you to perform appropriate application tasks at that point."""
        print('Successfully connected to Twitter\n')

    def on_data(self, data):
        """Called when Twitter pushes a new tweet to you."""
        self.tweet_count += 1  # track number of tweets processed
        json_data = json.loads(data)  # convert string to JSON
        self.db.tweets.insert_one(json_data)  # store in tweets collection
        print(f'    Screen name: {json_data["user"]["name"]}') 
        print(f'     Created at: {json_data["created_at"]}')         
        print(f'Tweets received: {self.tweet_count}')         

        # if TWEET_LIMIT is reached, return False to terminate streaming
        return self.tweet_count != self.TWEET_LIMIT

    def on_error(self, status):
        print(status)
        return True
4.7 统计每位参议员的推特数量

创建一个文本索引,然后统计包含每位参议员 TwitterHandle 的推特数量:

db.tweets.create_index([('$**', 'text')])
tweet_counts = []
for senator in senators_df.TwitterHandle:
    tweet_counts.append(db.tweets.count_documents(
        {"$text": {"$search": senator}}))
tweet_counts_df = senators_df.assign(Tweets=tweet_counts)
tweet_counts_df.sort_values(by='Tweets', 
    ascending=False).head(10)

输出结果如下:
| State | Name | Party | TwitterHandle | TwitterID | Tweets |
| — | — | — | — | — | — |
| SC | Lindsey Graham | R | LindseyGrahamSC | 432895323 | 1405 |
| MA | Elizabeth Warren | D | SenWarren | 970207298 | 1249 |
| CA | Dianne Feinstein | D | SenFeinstein | 476256944 | 1079 |
| HI | Brian Schatz | D | brianschatz | 47747074 | 934 |
| NY | Chuck Schumer | D | SenSchumer | 17494010 | 811 |
| IL | Tammy Duckworth | D | SenDuckworth | 1058520120 | 656 |
| CT | Richard Blumenthal | D | SenBlumenthal | 278124059 | 646 |
| HI | Mazie Hirono | D | maziehirono | 92186819 | 628 |
| UT | Orrin Hatch | R | SenOrrinHatch | 262756641 | 506 |
| RI | Sheldon Whitehouse | D | SenWhitehouse | 242555999 | 350 |

4.8 获取各州位置信息

使用 geopy 库获取各州的经纬度信息:

from geopy import OpenMapQuest
import time
from state_codes import state_codes
geo = OpenMapQuest(api_key=keys.mapquest_key) 
states = tweet_counts_df.State.unique()
states.sort()
locations = []
for state in states:
    processed = False
    delay = .1 
    while not processed:
        try: 
            locations.append(
                geo.geocode(state_codes[state] + ', USA'))
            print(locations[-1])  
            processed = True
        except:  # timed out, so wait before trying again
            print('OpenMapQuest service timed out. Waiting.')
            time.sleep(delay)
            delay += .1
4.9 按州分组推特数量

使用pandas的 groupby 方法按州分组,并计算每个州的推特总数:

tweets_counts_by_state = tweet_counts_df.groupby(
    'State', as_index=False).sum()
tweets_counts_by_state.head()

输出结果如下:
| State | Tweets |
| — | — |
| AK | 27 |
| AL | 2 |
| AR | 47 |
| AZ | 47 |
| CA | 1135 |

4.10 创建地图

使用Folium库创建地图:

import folium
usmap = folium.Map(location=[39.8283, -98.5795], 
                   zoom_start=4, detect_retina=True,
                   tiles='Stamen Toner')
4.11 创建热力图

使用 Choropleth 方法创建热力图,根据每个州的推特数量对地图进行着色:

choropleth = folium.Choropleth(
    geo_data='us-states.json',
    name='choropleth',
    data=tweets_counts_by_state,
    columns=['State', 'Tweets'],
    key_on='feature.id',
    fill_color='YlOrRd',
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name='Tweets by State'
).add_to(usmap)
layer = folium.LayerControl().add_to(usmap)
4.12 创建地图标记

为每个州创建地图标记,并显示该州参议员的信息:

sorted_df = tweet_counts_df.sort_values(
    by='Tweets', ascending=False)
for index, (name, group) in enumerate(sorted_df.groupby('State')):
    strings = [state_codes[name]]  # used to assemble popup text

    for s in group.itertuples():
        strings.append(
            f'{s.Name} ({s.Party}); Tweets: {s.Tweets}')

    text = '<br>'.join(strings)  
    marker = folium.Marker(
        (locations[index].latitude, locations[index].longitude), 
        popup=text)
    marker.add_to(usmap) 
4.13 保存地图

将地图保存为HTML文件:

usmap.save('SenatorsTweets.html')
5. 总结

通过以上步骤,我们成功地将推特数据存储到MongoDB中,并使用Folium库将数据可视化展示在地图上。这种方法可以帮助我们更好地理解和分析数据,发现数据中的规律和趋势。同时,我们还可以进一步扩展这个案例,例如使用情感分析技术对推特数据进行情感分析,以了解公众对参议员的态度。

大数据案例:MongoDB存储推特数据及可视化分析

6. 关键技术点分析
6.1 MongoDB的使用
  • 连接配置 :使用 pymongo 库的 MongoClient 连接到MongoDB Atlas集群,通过传入集群的连接字符串实现连接。代码如下:
from pymongo import MongoClient
atlas_client = MongoClient(keys.mongo_connection_string)
db = atlas_client.senators
  • 数据存储 :将推特的JSON数据作为文档存储在MongoDB的 tweets 集合中。在 TweetListener 类的 on_data 方法中,使用 insert_one 方法将JSON对象插入到集合中。
def on_data(self, data):
    self.tweet_count += 1
    json_data = json.loads(data)
    self.db.tweets.insert_one(json_data)
    # 其他代码...
  • 文本索引与搜索 :为了进行全文搜索,需要为 tweets 集合创建文本索引。使用 create_index 方法创建索引后,使用 count_documents 方法统计包含特定文本的文档数量。
db.tweets.create_index([('$**', 'text')])
tweet_counts = []
for senator in senators_df.TwitterHandle:
    tweet_counts.append(db.tweets.count_documents(
        {"$text": {"$search": senator}}))
6.2 Tweepy库的使用
  • 认证 :使用Tweepy库进行Twitter API的认证,通过 OAuthHandler set_access_token 方法设置认证信息。
import tweepy, keys
auth = tweepy.OAuthHandler(
    keys.consumer_key, keys.consumer_secret)
auth.set_access_token(keys.access_token, 
    keys.access_token_secret)
api = tweepy.API(auth, wait_on_rate_limit=True, 
                 wait_on_rate_limit_notify=True)
  • 推特流 :使用 Stream 类创建推特流,并通过 filter 方法指定跟踪的关键词和用户ID。
from tweetlistener import TweetListener
tweet_limit = 10000
twitter_stream = tweepy.Stream(api.auth, 
    TweetListener(api, db, tweet_limit))
twitter_stream.filter(track=senators_df.TwitterHandle.tolist(),
    follow=senators_df.TwitterID.tolist())
6.3 Folium库的使用
  • 地图创建 :使用 folium.Map 方法创建地图,并设置初始位置、缩放级别和地图样式。
import folium
usmap = folium.Map(location=[39.8283, -98.5795], 
                   zoom_start=4, detect_retina=True,
                   tiles='Stamen Toner')
  • 热力图创建 :使用 Choropleth 方法创建热力图,根据各州的推特数量对地图进行着色。
choropleth = folium.Choropleth(
    geo_data='us-states.json',
    name='choropleth',
    data=tweets_counts_by_state,
    columns=['State', 'Tweets'],
    key_on='feature.id',
    fill_color='YlOrRd',
    fill_opacity=0.7,
    line_opacity=0.2,
    legend_name='Tweets by State'
).add_to(usmap)
  • 地图标记创建 :为每个州创建地图标记,并显示该州参议员的信息。
sorted_df = tweet_counts_df.sort_values(
    by='Tweets', ascending=False)
for index, (name, group) in enumerate(sorted_df.groupby('State')):
    strings = [state_codes[name]]
    for s in group.itertuples():
        strings.append(
            f'{s.Name} ({s.Party}); Tweets: {s.Tweets}')
    text = '<br>'.join(strings)  
    marker = folium.Marker(
        (locations[index].latitude, locations[index].longitude), 
        popup=text)
    marker.add_to(usmap) 
7. 可能遇到的问题及解决方案
7.1 Twitter API速率限制
  • 问题描述 :Twitter API有速率限制,如果请求过于频繁,会导致请求被拒绝。
  • 解决方案 :在创建 API 对象时,设置 wait_on_rate_limit=True wait_on_rate_limit_notify=True ,让Tweepy在达到速率限制时自动等待,并在等待时发出通知。
api = tweepy.API(auth, wait_on_rate_limit=True, 
                 wait_on_rate_limit_notify=True)
7.2 OpenMapQuest服务超时
  • 问题描述 :在使用 geopy OpenMapQuest 服务获取各州位置信息时,可能会出现服务超时的情况。
  • 解决方案 :使用 try-except 语句捕获异常,并在超时后等待一段时间再重试,每次等待时间逐渐增加。
for state in states:
    processed = False
    delay = .1 
    while not processed:
        try: 
            locations.append(
                geo.geocode(state_codes[state] + ', USA'))
            print(locations[-1])  
            processed = True
        except:  # timed out, so wait before trying again
            print('OpenMapQuest service timed out. Waiting.')
            time.sleep(delay)
            delay += .1
8. 扩展与优化建议
8.1 情感分析

可以使用自然语言处理技术对推特数据进行情感分析,了解公众对参议员的态度是积极、消极还是中立。可以使用如 TextBlob VADER 等库进行情感分析。

8.2 实时更新

可以将整个流程封装成一个定时任务,定期获取新的推特数据,并更新地图和统计信息,实现实时数据展示。

8.3 数据可视化优化

可以进一步优化地图的显示效果,例如添加更多的交互元素,如鼠标悬停显示详细信息、不同的地图样式等。

9. 总结回顾

本文详细介绍了如何使用MongoDB存储推特数据,并通过Folium库将数据可视化展示在地图上。整个流程包括Twitter API认证、数据加载、MongoDB连接与数据存储、推特流监听、数据统计、位置信息获取、地图创建与标记等步骤。同时,分析了关键技术点,讨论了可能遇到的问题及解决方案,并提出了扩展与优化建议。通过这个案例,我们可以更好地理解大数据的存储、处理和可视化技术,为处理其他类似的大数据问题提供参考。

以下是整个流程的另一个mermaid流程图,展示了从数据获取到可视化的完整过程:

graph LR
    A[获取认证信息] --> B[加载参议员数据]
    B --> C[连接MongoDB]
    C --> D[启动推特流监听]
    D --> E[存储推特数据]
    E --> F[统计推特数量]
    F --> G[获取各州位置信息]
    G --> H[按州分组数据]
    H --> I[创建地图]
    I --> J[创建热力图]
    J --> K[创建地图标记]
    K --> L[保存地图]

通过以上的步骤和分析,我们可以完成一个完整的大数据案例,从数据的获取、存储到最终的可视化展示,为数据分析和决策提供有力支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值