Define handles
commodity_sources = ['reuters','wsj','financialtimes', 'bloomberg']
# Query
search_terms = 'spot copper'
# Get twitter data
tweets_df = get_tweets(
commodity_sources,
search_term = search_terms,
top_only = False,
start_date = '2015-01-01',
end_date = '2020-01-01'
).sort_values('date', ascending=False).set_index('date')
tweets_df.head(10)
历史Twitter数据
我们现在需要对这些文本数据进行处理,以便为我们的主题和情感模型提供可解释性。
预处理和探索性数据分析
对于自然语言应用程序,文本数据的预处理需要仔细考虑。从丢失的角度来看,从文本数据组成数字矢量可能具有挑战性,当执行看似基本的任务(例如删除停用词)时,有价值的信息和主题上下文很容易丢失,我们将在后面看到。
首先,让我们以标记和URL的形式删除多余的信息,即:
来自媒体的Tweets通常包含句柄标签、标签和文章链接,所有这些都需要删除
我们定义了几个单行Lambda函数:
https://docs.python.org/3/tutorial/controlflow.html
它们使用Regex:
https://docs.python.org/2/library/re.html
来删除与我们要删除的表达式匹配的字母和字符:
代码语言:javascript复制#@title Strip chars & urls
remove_handles = lambda x: re.sub(‘@[^s] ’,’’, x)
remove_urls = lambda x: re.sub(‘http[^s] ’,’’, x)
remove_hashtags = lambda x: re.sub('#[^s]*','',x)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_handles)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_urls)
tweets_df[‘text’] = tweets_df[‘text’].apply(remove_hashtags)
接下来,我们通过检查tweet的组成来对Twitter数据进行一些基本分析,比如单个tweet的长度(每条tweet的字数)、字符数等。
基本文本EDA —单词和字符的频率分布
停顿词
很明显,每条推文的平均长度相对较短(准确地说是10.3个字)。这些信息表明,如果我们考虑到潜在的信息丢失,以计算复杂性和内存开销为代价,过滤停顿词可能不是一个好主意。
最初,这个实验是用NLTK非常方便的标准停顿词列表从 Tweets中删除所有停顿词:
代码语言:javascript复制# Standard tweet sw
stop_words_nltk = set(stopwords.words('english'))
# custom stop words
stop_words = get_top_ngram(tweets_df['text'], 1)
stop_words_split = [
w[0] for w in stop_words
if w[0] not in [
'price', 'prices',
'china', 'copper',
'spot', 'other_stop_words_etc'
] # Keep SW with hypothesised importance
]
stop_words_all = list(stop_words_nltk) stop_words_split
然而,这一行为导致了许多错误的推文分类(从情绪得分的角度来看),最好避免。
在这一点上,当涉及到处理Twitter数据时,很值得强调NLTK 的优秀库。它提供了一套全面的工具和功能,以帮助解析社会媒体输出,包括表情符号解释!大家可以在这里找到一个非常有用的指南:http://www.nltk.org/howto/twitter.html,帮助你开始使用NLTK。
N-Grams
下一步是考虑词序。当我们将一系列标记向量化为一大堆单词时,我们就失去了这些单词在一条推文中固有的语境和意义。我们可以通过检查最常见的N-Grams来尝试理解在我们的 tweets DataFrame 中词序的重要性。
正如我们在上面的初步分析中所观察到的,一条给定的tweet的平均长度只有10个字。根据这些信息,一条推文中的单词顺序,特别是确保我们保留这种顺序中固有的上下文和意思,对于产生一个准确的情感得分至关重要。我们可以扩展标记的概念,包括多字标记,例如 N-Grams,以便将含义保留在单词的顺序内。
NLTK 有一个非常方便和非常有效的N-Gram标记器: from nltk.util import ngram。N-gram函数返回一个生成器,该生成器生成前n个N-Gram作为元组。我们对探索这些N-Grams实际上是很感兴趣的,所以在第一个实例中,我们会使用Scikit-learn的 CountVectorizer 解析我们的tweet数据:
代码语言:javascript复制def get_ngrams(doc, n=None):
"""
Get matrix of individual token counts for a given text document.
Args:
corpus: String, the text document to be vectorized into its constituent tokens.
n: Int, the number of contiguous words (n-grams) to return.
Returns:
word_counts: A list of word:word frequency tuples.
"""
# Instantiate CountVectorizer class
vectorizer = CountVectorizer(ngram_range=
(n,n)).fit(doc)
bag_of_words = vectorizer.transform(doc)
sum_of_words = bag_of_words.sum(axis=0)
# Get word frequencies
word_counts = [(word, sum_of_words[0, index])
for word, index in vectorizer.vocabulary_.items()
]
word_counts = sorted(word_counts, key=lambda x:x[1], reverse=True)
return word_counts
# Get n-grams
top_bigrams = get_ngrams(tweets_df['text'], 2)[:20]
top_trigrams = get_ngrams(tweets_df['text'], 3)[:20]