Анализ настроений в Твиттере - устранение дублирования ботов - PullRequest
0 голосов
/ 27 апреля 2018

В качестве предисловия, этот код от великого парня из Github / Youtube: https://github.com/the-javapocalypse/

Я сделал несколько небольших настроек для личного использования.

Одна вещь, которая всегда стояла между мной и анализом настроений в твиттере, это то, что существует так много сообщений ботов. Я полагаю, что если я не смогу полностью избежать ботов, возможно, я смогу просто удалить дублирование, чтобы застраховать удар.

Например - "#bitcoin" или "#btc" - учетные записи ботов существуют под многими разными дескрипторами, публикующими один и тот же твит. На нем может быть написано: «Идет на Луну! Купите сейчас #btc или навсегда пожалеете об этом! Купите, купите, купите! Вот ссылка на мой личный сайт [вставьте сюда персональный сайт]»

Это может показаться позитивным настроением. Если 25 аккаунтов публикуют это 2 раза для каждого аккаунта, у нас будет некоторая инфляция, если я только анализирую последние 500 твитов, содержащих "#btc"

Итак, на мой вопрос:

  1. Какой эффективный способ удалить дублирование перед записью в файл csv? Я думал ввести простой оператор if и указать массив, чтобы проверить, существует ли он уже. Есть проблема с этим. Скажем, я ввел 1000 твитов для анализа. Если 500 из них являются дублированием от ботов, мой анализ твитов в 1000 раз стал 501 анализом твитов. Это приводит к моему следующему вопросу
  2. Как можно включить проверку на дублирование и, если есть дублирование, добавлять 1 каждый раз к моему общему запросу на твиты для анализа. Пример - я хочу проанализировать 1000 твитов. Дублирование было найдено один раз, поэтому в анализ необходимо включить 999 уникальных твитов. Я хочу, чтобы скрипт проанализировал еще один, чтобы сделать из него 1000 уникальных твитов (1001 твит, включая 1 дубликат)
  3. Небольшое изменение, но я думаю, что было бы эффективно знать, как удалить все твиты со встроенными гиперссылками. Это сыграло бы роль в цели вопроса 2, компенсируя удаление твитов с гиперссылками. Пример - я хочу проанализировать 1000 твитов. 500 из 1000 имеют встроенные URL. 500 удалены из анализа. Я сейчас до 500 твитов. Я все еще хочу 1000. Скрипт должен продолжать получать не URL, не дубликаты, пока не будет учтено 1000 уникальных твитов без URL.

Смотрите ниже весь сценарий:

import tweepy
import csv
import re
from textblob import TextBlob
import matplotlib.pyplot as plt


class SentimentAnalysis:

    def __init__(self):
        self.tweets = []
        self.tweetText = []

    def DownloadData(self):
        # authenticating
        consumerKey = ''
        consumerSecret = ''
        accessToken = ''
        accessTokenSecret = ''
        auth = tweepy.OAuthHandler(consumerKey, consumerSecret)
        auth.set_access_token(accessToken, accessTokenSecret)
        api = tweepy.API(auth)

        # input for term to be searched and how many tweets to search
        searchTerm = input("Enter Keyword/Tag to search about: ")
        NoOfTerms = int(input("Enter how many tweets to search: "))

        # searching for tweets
        self.tweets = tweepy.Cursor(api.search, q=searchTerm, lang="en").items(NoOfTerms)

        csvFile = open('result.csv', 'a')

        csvWriter = csv.writer(csvFile)

        # creating some variables to store info
        polarity = 0
        positive = 0
        negative = 0
        neutral = 0

        # iterating through tweets fetched
        for tweet in self.tweets:
            # Append to temp so that we can store in csv later. I use encode UTF-8
            self.tweetText.append(self.cleanTweet(tweet.text).encode('utf-8'))
            analysis = TextBlob(tweet.text)
            # print(analysis.sentiment)  # print tweet's polarity
            polarity += analysis.sentiment.polarity  # adding up polarities

            if (analysis.sentiment.polarity == 0):  # adding reaction
                neutral += 1
            elif (analysis.sentiment.polarity > 0.0):
                positive += 1
            else:
                negative += 1

        csvWriter.writerow(self.tweetText)
        csvFile.close()

        # finding average of how people are reacting
        positive = self.percentage(positive, NoOfTerms)
        negative = self.percentage(negative, NoOfTerms)
        neutral = self.percentage(neutral, NoOfTerms)

        # finding average reaction
        polarity = polarity / NoOfTerms

        # printing out data
        print("How people are reacting on " + searchTerm +
              " by analyzing " + str(NoOfTerms) + " tweets.")
        print()
        print("General Report: ")

        if (polarity == 0):
            print("Neutral")
        elif (polarity > 0.0):
            print("Positive")
        else:
            print("Negative")

        print()
        print("Detailed Report: ")
        print(str(positive) + "% positive")
        print(str(negative) + "% negative")
        print(str(neutral) + "% neutral")

        self.plotPieChart(positive, negative, neutral, searchTerm, NoOfTerms)

    def cleanTweet(self, tweet):
        # Remove Links, Special Characters etc from tweet
        return ' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t]) | (\w +:\ / \ / \S +)", " ", tweet).split())

    # function to calculate percentage
    def percentage(self, part, whole):
        temp = 100 * float(part) / float(whole)
        return format(temp, '.2f')

    def plotPieChart(self, positive, negative, neutral, searchTerm, noOfSearchTerms):
        labels = ['Positive [' + str(positive) + '%]', 'Neutral [' + str(neutral) + '%]',
                  'Negative [' + str(negative) + '%]']
        sizes = [positive, neutral, negative]
        colors = ['yellowgreen', 'gold', 'red']
        patches, texts = plt.pie(sizes, colors=colors, startangle=90)
        plt.legend(patches, labels, loc="best")
        plt.title('How people are reacting on ' + searchTerm +
                  ' by analyzing ' + str(noOfSearchTerms) + ' Tweets.')
        plt.axis('equal')
        plt.tight_layout()
        plt.show()


if __name__ == "__main__":
    sa = SentimentAnalysis()
    sa.DownloadData()

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Ответ на свой первый вопрос

Вы можете удалить дубликаты, используя этот вкладыш.

self.tweets = list(set(self.tweets))

Это удалит каждый дублированный твит. На всякий случай, если вы хотите, чтобы это работало, вот простой пример

>>> tweets = ['this is a tweet', 'this is a tweet', 'Yet another Tweet', 'this is a tweet']
>>> print(tweets)
['this is a tweet', 'this is a tweet', 'Yet another Tweet', 'this is a tweet']
>>> tweets = list(set(tweets))
>>> print(tweets)
['this is a tweet', 'Yet another Tweet']

Ответ на второй вопрос

Поскольку теперь вы уже удалили дубликаты, вы можете получить количество удаленных твитов, взяв разницу self.tweets и NoOfTerms

tweets_to_further_scrape = NoOfTerms - self.tweets

Теперь вы можете очистить tweets_to_further_scrape количество твитов и повторять этот процесс, удаляя дубликаты и скребки, пока не найдете нужное количество уникальных твитов.

Ответ на третий вопрос

При переборе списка твитов добавьте эту строку, чтобы удалить внешние ссылки.

tweet.text = ' '.join([i for i in tweet.text.split() if 'http' not in i])

Надеюсь, это поможет вам. Удачного кодирования!

0 голосов
/ 27 апреля 2018

Вы можете просто вести текущий подсчет экземпляров твитов, используя defaultdict. Вы также можете удалить веб-адреса, если они отправляют новые сокращенные URL-адреса.

from collections import defaultdict

def __init__(self):
    ...
    tweet_count = defaultdict(int)

def track_tweet(self, tweet):
    t = self.clean_tweet(tweet)
    self.tweet_count[t] += 1

def clean_tweet(self, tweet):
    t = tweet.lower()
    # any other tweet normalization happens here, such as dropping URLs
    return t

def DownloadData(self):
    ...
    for tweet in self.tweets:
        ...
        # add logic to check for number of repeats in the dictionary.
...