用 NLP 分析迪士尼乐园评论
情感分析、情感检测、搭配和主题建模
与刘培、路畅、帕萨·塔玛塞比和马英凯(加州大学欧文分校 MSBA 分校 21 年级)合作
项目目标:使用情感分析、情感检测和 n-gram 联想,比较顾客对三个迪士尼乐园地点(阿纳海姆、巴黎和香港)景点的情感。使用主题建模识别关键词,帮助迪士尼确定游客痛点并改善公园体验。要查看我们的代码,请参考 GitHub 库这里。
**数据集:**我们使用了在 Kaggle 中找到的数据集,该数据集包含来自猫途鹰的 42,000 条关于三个迪士尼乐园分店的评论:加州、巴黎和香港。我们决定按分支位置分割数据,以便在计算上更容易分析较小的样本。关于阿纳海姆的评论有 19406 条,关于巴黎的有 13630 条,关于香港的有 9620 条。数据变量包括评论 ID、评级、年月、评论者位置、评论文本和迪士尼乐园分支。
**探索性数据分析:**首先,我们进行了探索性数据分析(EDA ),以了解所有地点的平均评分,我们的访问者来自哪里,以及评分如何随时间变化。
上图显示了公园所在地每年的平均评分。下图显示了每年针对每个地点撰写的评论数量。
显示了前 10 个国家的游客来自的频率。加州、巴黎和香港(从左至右)
一段时间内的评级频率。2019 年的下降可能是因为没有全年的数据。有些评论没有日期。
我们找到了每个公园的平均评分(满分 5 颗星):加州 4.41,巴黎 3.96,香港 4.20。游客的国籍取决于地理位置——例如,许多香港游客来自邻近国家(如澳大利亚、印度、菲律宾),大多数巴黎游客来自英国,许多加州游客来自美国。
**单词云:**我们生成了单词云,以便对游客在回顾他们的迪士尼乐园体验时谈论的内容有一个大致的了解。在我们的分析中,我们只对用英语写的评论感兴趣,并删除重复的评论。
为了创建单词云,我们对评论中的单词进行了标记,并删除了停用词。有许多方法可以自定义文字云的字体、背景颜色和轮廓。你可以参考这个网站来寻找 HTML 颜色或者这个来获得更多可以用来增强你的图表的颜色图选项。
tokenizer = RegexpTokenizer(r'\w+')
text = text.lower()
cleaned_text = re.sub('\W', ' ', text)
stopword = stopwords.words("english")
snowball_stemmer = SnowballStemmer("english")
word_tokens = nltk.word_tokenize(cleaned_text)
stemmed_word = [snowball_stemmer.stem(word) for word in word_tokens]
processed_text = [word for word in stemmed_word if word not in stopword]
text_string=(" ").join(processed_text)#make word cloud
mask = np.array(Image.open("m2.jpg"))
wordcloud = WordCloud(background_color="white", font_path='arial', mask = mask).generate(text_string)#applies colors from your image mask into your word cloud
image_colors = ImageColorGenerator(mask)
plt.figure(figsize=(15,8))
plt.imshow(wordcloud.recolor(color_func=image_colors), cmap=plt.cm.gray, interpolation="bilinear")
plt.axis("off")
plt.show()
生成关于所有公园位置的文字云。
从左至右:加州、巴黎、香港
总的来说,这三个地方的评论都提到了快速通道、排队、游客统计、乘车和景点。
**情感分析:**我们想更深入地了解评论揭示了访问者的情感。对于这一步,我们使用了三种方法来获得使用 TextBlob 和 Vader 的情感。
- 这种方法使用复合分数来分配情绪“积极”或“消极”。
#assign sentiment based on compound score
df['sentiment'] = np.where(df['vader_comp'] >= 0.05, 'positive', 'negative')
2.我们还尝试了其他方法来附加情感,通过使用不同的复合得分阈值来分类“正面”、“中性”和“负面”:
df['nltk_sentiment_type'] = ''
df.loc[df.nltk_compound > 0, 'nltk_sentiment_type'] = 'POSITIVE'
df.loc[df.nltk_compound == 0, 'nltk_sentiment_type'] = 'NEUTRAL'
df.loc[df.nltk_compound < 0, 'nltk_sentiment_type'] = 'NEGATIVE'
每个公园位置的情感频率。
3.另一种方法是基于评级来分配情感:
# assigning sentiment using rating
rating = df['Rating']
def label_func(rating):
if rating >= 4:
return "Positive"
elif rating == 3:
return "Neutral"
else:
return "Negative"
df['Sentiment'] = df['Rating'].apply(lambda x: label_func(x))
我们想知道情绪的两极性和主观性在多大程度上影响了游客对迪士尼乐园体验的评价。下面是一个例子,说明我们如何衡量使用“最幸福的地方”和“地球上最幸福的地方”这两个短语的关于香港的评论的极性和主观性
从上面的图表中,我们可以推断出,情绪积极、极性得分高的评论对他们的公园体验非常满意。主观正面评价比主观负面评价多。主观性衡量一篇评论有多固执己见,因此我们可以推断,那些持负面观点的人给出了更严厉的评论,因为他们的期望在访问期间没有得到满足。
**情绪检测:**我们使用 NRCLex 来分配情绪,NRC lex 基于文本来测量情绪影响。情绪影响包括:积极、消极、期待、信任、恐惧、惊讶、愤怒、悲伤、喜悦和厌恶。我们还尝试使用软件包 text2emotion ,它将情绪分为快乐、愤怒、悲伤、惊讶和恐惧。然而,text2emotion 的问题是它会给“恐惧”打高分(这对地球上最快乐的地方来说没有意义),所以我们选择使用 NRCLex 进行分析。
from nrclex import NRCLex#nrclex outputs a score for all 9 emotions, but we only want the emotion with the highest score (usually the first output)emotion = []
for i in range(len(df)):
emotions = NRCLex(df['Review_Text'][i])
emotion.append(emotions.top_emotions[0][0])
df['emotion'] = emotion
检测情绪后,我们为每个位置创建了可视化效果,以显示每种情绪的频率:
graph = sns.countplot(y = "emotion", data = df, palette = "flare")
graph.set(xlabel = 'Frequency', ylabel = 'Emotion', title = 'Emotion from reviews about Disneyland (CA)')
figure = graph.get_figure()
在这三个地方中,香港是唯一一个没有感到“厌恶”的地方。
总的来说,这三个公园都有高频率的“积极”情绪。然而,我们必须仔细看看与负面情绪(愤怒、恐惧、消极、厌恶、悲伤)相关的评论,这样我们才能了解为什么有些游客有不愉快的公园经历。
我们发现了一些有趣的评论,其中情绪被分为“厌恶”或“负面”:
- 巴黎的顾客服务: “不要在欧洲迪斯尼浪费你的时间……那里的工作人员不友好,粗鲁,对顾客一点也不感兴趣!如果你不说法语,你就被忽视了!”
- 加州物价: “这无疑是一个传奇的地方,但我认为不值得为过度拥挤和过高的价格而花钱。迪士尼继续提高门票价格,每天的人潮都很荒谬。”
- 加州客服: “去过佛罗里达的迪士尼世界,加州迪士尼乐园让人大失所望。洗手间很脏。送餐员会转过身来挖鼻孔。”
- 酒店住宿,客户服务,公园可及性,香港的线路: “圣诞节假期去过。整个旅程都被令人恶心的服务和糟糕的经历所破坏…甚至对我的孩子来说也没有魔力。那里的员工大多在生闷气(可能是因为他们需要在假期工作)。回复主要是照着剧本念的,听起来像是破了的单调唱片。有两个亮点,我希望我会忘记…为我的小宝贝租了一辆婴儿车。一位皱着眉头的工作人员接待了她,递给她一张 HKD 1000 美元的钞票,但找错了零钱(HKD 少了 500 美元)问她,她尖叫了一声!!然后她用广东话咒骂,坚持说她身上没有 HKD 1000 元的钞票,我真笨,给了一张 HKD 500 元的钞票。第二个亮点是当我们排队观看 3D 表演时,一群印度人插队到了队伍的前面。告知工作人员,他们坚决告知,没有排队的规定,并继续聊天。插队者反驳说他们是贵族,排在队伍前面是他们的权利。工作人员笑着点点头,继续他们之间的闲聊。史上最可怕的噩梦…永远不要去那里…最好还是坚持东京或者我们。”
将情绪和情感结合起来使用可以帮助迪士尼找到客户不满意的地方以及他们不满意的原因。然后,这些信息可用于进行必要的适当更改,以增强游客体验。
**搭配:**我们希望找到评论中的常用短语,这样我们就可以识别访问者经常讨论的关键词或主题。通过这样做,迪士尼可以识别评论的上下文,而不必单独阅读每一篇评论。我们采取措施寻找搭配——由一个以上的单词组成的短语,通过 n 元语法关联共同出现。
二元联想 —识别两个频繁出现的词,以获得关于评论上下文的更多洞察。我们发现,只过滤形容词和名词更有意义:
def rightTypes(ngram):
if '-pron-' in ngram or '' in ngram or ' 'in ngram or 't' in ngram:
return False
for word in ngram:
if word in stop_words:
return False
acceptable_types = ('JJ', 'JJR', 'JJS', 'NN', 'NNS', 'NNP', 'NNPS')
second_type = ('NN', 'NNS', 'NNP', 'NNPS')
tags = nltk.pos_tag(ngram)
if tags[0][1] in acceptable_types and tags[1][1] in second_type:
return True
else:
return False
以下是每个公园位置的顶级二元模型:
从左至右:加州、巴黎、香港
最常见的二元模型包括热门景点、使用的门票类型(一日通票、公园票)、员工(演职人员)和等待时间。
三元组关联 —识别三个频繁出现的词,以获得对评论上下文的更多洞察。三元模型可以给我们更多关于游客在主题公园做什么的信息。我们也将只考虑形容词和名词给我们有意义的上下文。
从左至右:加州、巴黎、香港
似乎去加州的游客会鼓励其他人“使用快速通道”来缩短等待时间。这些评论还谈到加州冒险,比较他们的经验,佛罗里达州的华特·迪士尼世界,使用公园跳跃者,和受欢迎的公园景点。巴黎评论家还提到使用快速通道,受欢迎的景点,并与其他公园进行比较。关于香港的评论提到了热门景点和乘车等待时间。
我们可以使用通过搭配识别获得的结果,进一步分析游客对景点的情感。为此,我们将查找提到“太空山”或“超空间山”的评论,并比较这三个地方对该旅程的总体看法。我们只对游客使用的与游乐设施相关的词汇感兴趣,所以我们只考虑形容词。
从左到右:与太空山加州、巴黎和香港相关的前 100 个单词
总的来说,当我们可视化与太空山相关的评论时,来自所有三个地方的评论者使用相似的形容词。
**主题建模:**我们希望使用主题建模来提取评论中使用的关键词,以帮助迪士尼确定公园游客关注的具体问题。我们可以建立一个字典,并使用无监督学习算法 ld a(潜在狄利克雷分配)来训练我们的主题模型,以发现文本中的隐藏模式。这也将产生主题出现在我们的模型中的概率。在构建这个模型之前,我们删除了标点符号、停用词,并对文本进行了词条化。然后,我们找到了 k(主题数量)的最佳值,将其与 coherence score 进行对比。我们选择了一致性分数最大的理想 k 值。我们使用 gensim 包来完成这项任务。
def compute_coherence_values(dictionary, corpus, texts, start, stop):
"""
Compute c_v coherence for various number of topics
"""
coherence_values = []
model_list = []
for num_topics in range(start, stop):
model = gensim.models.ldamodel.LdaModel(corpus=corpus,
num_topics=num_topics,
id2word=id2word,
random_state=90,
alpha='auto',
eta='auto',
per_word_topics=True)
model_list.append(model)
coherencemodel = CoherenceModel(model=model, texts=texts,
dictionary=dictionary, coherence='c_v')
coherence_values.append(coherencemodel.get_coherence())
return model_list, coherence_values
start=4
stop=11
model_list, coherence_values = compute_coherence_values(dictionary=id2word,
corpus=corpus,
texts=data_lemmatized,
start=start, stop=stop)x = range(start, stop)
plt.figure(figsize=(10,7))
plt.style.use('ggplot')
plt.plot(x, coherence_values, color = "blue",marker=".")
plt.xlabel("Num Topics", size=14)
plt.ylabel("Coherence score", size=14)
plt.title('Number of Topics Based on The Coherence Score',size=18)
#plt.savefig("output/k_topic.jpg", bbox_inches='tight', dpi = 300)
plt.show()
对于加利福尼亚的位置,理想的主题数是 7。这给出了 0.35 的一致性分数和-6.94 的困惑分数。应用这个 k 值,我们获得每个主题中的热门单词:
[(0,
'0.089*"year" + 0.078*"kid" + 0.052*"old" + 0.033*"child" + 0.032*"come" + '
'0.031*"little" + 0.029*"character" + 0.018*"young" + 0.018*"daughter" + '
'0.015*"adult"'),
(1,
'0.079*"wait" + 0.076*"line" + 0.066*"pass" + 0.050*"fast" + 0.043*"long" + '
'0.038*"people" + 0.037*"hour" + 0.026*"minute" + 0.023*"ticket" + '
'0.019*"get"'),
(2,
'0.051*"ride" + 0.049*"go" + 0.040*"time" + 0.040*"day" + 0.037*"park" + '
'0.030*"get" + 0.018*"do" + 0.016*"good" + 0.014*"food" + 0.014*"take"'),
(3,
'0.087*"mountain" + 0.080*"space" + 0.041*"pirate" + 0.033*"detail" + '
'0.028*"disneyworld" + 0.022*"haunted_mansion" + 0.022*"walt" + '
'0.020*"matterhorn" + 0.019*"caribbean" + 0.018*"indiana_jone"'),
(4,
'0.020*"area" + 0.018*"tell" + 0.013*"give" + 0.013*"put" + 0.012*"re" + '
'0.012*"parking" + 0.011*"patience" + 0.011*"gate" + 0.011*"leave" + '
'0.010*"truely"'),
(5,
'0.078*"disneyland" + 0.051*"disney" + 0.038*"place" + 0.030*"great" + '
'0.029*"love" + 0.027*"visit" + 0.025*"park" + 0.020*"world" + 0.019*"fun" + '
'0.017*"well"'),
(6,
'0.034*"overprice" + 0.032*"halloween" + 0.030*"effort" + 0.022*"party" + '
'0.021*"event" + 0.013*"group" + 0.013*"weekday" + 0.013*"local" + '
'0.011*"trick" + 0.010*"sandwich"')]
为了在二维空间中可视化主题,我们将使用 gensim 的 pyLDAvis 并创建一个我们模型的交互式可视化。
从我们的主题模型中,我们能够获得每个主题的热门关键词:
- 42.5%的代币是关于乘车、表演和食物的。
- 24.4%的人认为家庭公园体验是积极有趣的。
- 12%的代币关于排队等候和使用快速通行证。
- 7.8%的游客与谁一起参观主题公园。
- 7.2%的代币关于停车和入口。
- 3.5%的热门游乐设施代币(太空山、加勒比海盗、鬼屋、马特宏峰、印第安纳琼斯、大雷山)。
- 2.5%的代币关于节假日(万圣节和圣诞节)。
我们应用同样的技术提取关于巴黎和香港的主题,发现了以下结果:
- 对于巴黎迪士尼乐园,我们发现了 6 个主题:公园体验、景点、排队和快速通道、酒店住宿、天气和公园可达性。
- 对于香港迪士尼乐园,我们提取了 7 个主题,涉及:公园体验、家庭娱乐、酒店和餐厅住宿、客户服务、假期和庆祝活动(万圣节、冬季、生日)、积极体验和游客建议。
通过寻找关键主题,迪士尼可以确定他们可以改善的具体领域,以提高游客体验。同样的技术可以用于分析情绪消极的评论,以便发现主题公园中出现的问题。
我们用这种方法分析了关于香港的负面评论,并找出了与负面情绪相关的话题:排队、价格、插队和餐馆。在谷歌上快速搜索一下,就会发现插队在香港已经存在多年了。香港迪士尼乐园还在他们的公园条例中增加了一条,游客应该“……在参观期间尊重公园的其他游客,注意不要撞到、推搡或超过其他排队的游客。”(参见本猫途鹰论坛上的问题)。
我们对巴黎的评论应用了同样的方法,发现这些话题与负面情绪有关:长队和人群、客户服务、预订和住宿、吸烟、游览时间和糟糕的公园体验。吸烟在法国很普遍;巴黎迪士尼乐园甚至在园区内有指定的吸烟区。一些评论抱怨这个问题,并声称它已经“摧毁了魔法。”(这里是一个关于这个问题的猫途鹰论坛)。游客们表示,他们的孩子呆在空气中飘散的烟雾周围是不安全的。
我们发现在加州常见的问题是:长队和人群,家庭体验,食物,可达性和婴儿车。这个地方的一个独特问题是婴儿车拥挤、出租、停车和盗窃。评论者提到,如果婴儿车挡住了道路,演职人员有时会移动婴儿车,或者在必要时切断他们的锁。这个动作会让公园的游客感到困惑,特别是如果他们不知道他们的婴儿车被移动到了哪里。(这里是一个关于这个问题的有趣论坛。这里的是一篇关于一个公园游客建议迪士尼应该解决这个问题的文章——根据婴儿车的尺寸向游客收费。)
分类建模:我们希望使用多种方法构建一个健壮的分类器,以便对未来数据进行分类。我们分别实现了随机森林和逻辑回归,并在 unigrams 上使用单词包和 TF-IDF 作为集合模型。我们用于评估每个模型的指标是 F1 分数*。我们还使用了微平均方法用于集成分类器。
** F1-得分是精确度和召回率指标的加权平均值,您可以使用混淆矩阵计算每个指标。*
我们的分析结果如下:
- 袋字
香港
加州
巴黎
2。TF-IDF
香港
巴黎
加利福尼亚
**进一步分析:**通过按月对比评论,我们可以更深入地了解何时发生常见公园问题。我们还可以分析不同年份的评论,以告知我们每个分支机构是否试图做出改变来改善游客体验。
**推荐:**很多游客痛点源于排队和人潮的挫败感。大量时间花在排队上,这会激怒人们,并导致更负面的体验。另一个导致排长队问题的常见痛点是公园容量——更多的游客意味着等待景点和食物的时间更长。迪士尼应考虑以下一些建议,采取措施缓解负面公园体验的症状:
- 迪士尼应该想办法优化他们的快速通行证系统。全天提供免费移动快速通行证。
- 在旺季,尤其是夏天,设置最大的公园容量,这样就不会有太多的人排队。炎热的天气只会加剧游客的挫败感。
- 让等待的队伍互动,或者在队伍附近设立小吃摊。让更多的角色在受欢迎的游乐设施周围走动——让该游乐设施中的一些角色与排队的游客互动,并与他们合影。
- 鼓励演职人员执行公园规则,以便游客只在指定区域吸烟(巴黎),不插队(香港),并遵守推车政策(加州)。然而,我们意识到这些都是很难解决的问题,因为有些游客试图打破规则,如果他们没有任何后果的话。
- 迪士尼应该在受欢迎的景点附近指定区域来停放或存放婴儿车。这可以减少人行道上的拥挤和盗窃/财产损失。
参考文献:
NRCLex:https://pypi.org/project/NRCLex/
https://pypi.org/project/vaderSentiment/
text blob:https://pypi.org/project/textblob/
基于复合得分的情感赋值:https://www . analyticsvidhya . com/blog/2021/01/opinion-analysis-Vader-or-text blob/
航空公司推特:https://medium . com/analytics-vid hya/airlines-on-Twitter-理解-客户-投诉-with-NLP-81278 F2 b 68 DC
分析德克萨斯海湾沿岸的能源消耗习惯
RStudio 中的多元回归、自举和方差分析
弗拉德·布苏约克在 Unsplash 上拍摄的照片
摘要
这项分析旨在综合 2010 年至 2016 年期间每年 6 月至 8 月三个月的夏季德克萨斯州墨西哥湾沿岸电力消耗数据。所用数据直接来自 ERCOT,该公司管理着该州约 90%的电力负荷,代表着超过 2600 万德州客户。所有计算均使用 R 和 RStudio 进行。
通过这一分析,我将试图回答两个主要问题:
1.在夏季,工作日与周末相比,白天的耗电量高或低多少?
2.平均而言,功耗如何随温度增加?这种关系在周末和工作日之间似乎有所不同吗?
关于数据
用于此分析的数据集包含 5,820 个关于德克萨斯州墨西哥湾沿岸地区功耗的单独条目。这包括休斯顿周围的地区,并延伸到马塔哥达湾以南。如果你想直观地了解这个地区,你可以在这里查看地图。该数据集中的列如下:
时间:每个数据点的日期和时间戳。每个点覆盖上午 9 点到下午 7 点之间的一个小时间隔,并从列出的时间戳开始。
COAST:指定时间内德克萨斯州整个沿海地区的峰值需求(以兆瓦为单位)。请参见上面的链接地图,进一步了解这一点。
Temp:休斯顿威廉·p·霍比国际机场气象站记录的所列一小时间隔内的平均温度。所有单位都是摄氏度。
Weekday:一个二元指示器,表示所讨论的那一天是否是工作日。在本分析中,1 =工作日,0 =周末。
接近
在直接处理任何问题之前,让我们先构建手头数据的可视化。通过执行以下代码块,创建一个简单的日间能耗散点图,作为温度的函数,并按日分类分面,可以很容易地做到这一点:
ggplot(data=load_summer, mapping=aes(x=temp, y=COAST)) +
geom_jitter(width=0.5, alpha=0.2) +
geom_smooth(se=F, method=lm) +
facet_wrap(~weekdaytf) +
labs(
title = "Energy Consumption By Weekday/Weekend on Texas Gulf Coast",
caption = "Data sourced from ERCOT",
x = "Weekday vs. Weekend",
y = "Peak Energy Demand (MW)"
)
这产生了下面的图:
图片由作者使用 RStudio 制作
毫不奇怪,在峰值能源需求和测量温度之间可以看到一个积极的趋势。我们稍后将进一步研究这种关系。不过,现在让我们来解决第一个问题。
要回答工作日和周末之间的日间功耗变化程度,拟合一个简单的多元回归模型会很有用。这可以用 R 来构造,如下所示:
lm1 = lm(COAST ~ temp + weekday + temp:weekday, data=load_summer)
coef(lm1) %>%
round(3)
正如您在这里看到的,我在这个模型中包含了三个主要的预测项:
- 温度的主要影响
- 日分类的主要作用
- 两种主要效应之间的相互作用项
在执行时,给出以下结果:
(Intercept) temp weekday temp:weekday
-569.919 512.214 962.098 0.461
这允许我们通过以下线性方程来表达这些变量之间的关系:
能量需求 = -569.919 + 512.214* 温度 + 962.098* 工作日 + 0.461* 温度:工作日
虽然这个模型对于简单的估计来说很好,但是它很容易产生很大的误差。为了克服这个问题,我使用了一个简单的 bootstrap 和重新采样的 load_summer 数据,并根据这些结果计算了每个参数的置信区间:
lm1_boot = do(10000)*lm(COAST ~ temp + weekday + temp:weekday, data=resample(load_summer))confint(lm1_boot) %>%
mutate_if(is.numeric, round, 3)
*注意:当试图引导一个多元回归模型时,R 有时会很挑剔。如果在运行这段代码时收到奇怪的错误消息,可以直接在原始线性模型上运行 confint()函数。你的置信区间会宽一点,但是在同一个邻域内。
运行此命令后,我们可以在控制台中查看每个模型参数的 95%置信区间:
name lower upper level method estimate
1 Intercept -1013.626 -116.096 0.95 percentile -569.919
2 temp 496.896 527.219 0.95 percentile 512.214
3 weekday 422.334 1487.091 0.95 percentile 962.098
4 temp.weekday -17.385 18.722 0.95 percentile 0.461
5 sigma 1136.468 1177.841 0.95 percentile 1157.655
6 r.squared 0.691 0.713 0.95 percentile 0.702
7 F 4333.136 4823.466 0.95 percentile 4571.931
如果您直接在非自举线性模型上运行 R 的 confint()函数,下面是输出。如前所述,这个简化方法的上限和下限会稍微偏离自举模型提供的估计值。然而,出于本分析的目的,这两种方法都适用:
2.5 % 97.5 %
(Intercept) -1043.794 -96.044
temp 495.783 528.646
weekday 398.141 1526.056
temp:weekday -19.075 19.998
仅从这些结果来看,我们可以说,在工作日与周末相比,白天的功耗预计会从422 MW 增加到1487 MW——保持所有其他变量不变。鉴于该地区的地理位置和一年中的时间,这是有道理的。当这个国家的其他地区可能会在周末看到更高的能源需求,因为个人花更多的时间在家里,休斯顿是热的。办公室和家庭每个月都不得不在空调上花费大量金钱,因此,当全市的办公室试图为员工提供一些夏日阳光时,能源消耗会更高是有道理的。
但是,观测到的温度和能量消耗之间是否也有关联呢?如果是的话,这种关系在周末和工作日之间也有所不同吗?让我们把焦点转移到第二个问题上来,把这个问题搞清楚。
如果你看一下本分析开头的可视化,这两个变量之间的正相关是相当明显的。同样,这也是合乎逻辑的——由于室内气候控制系统的更多使用,能源消耗必然会随着温度的升高而增加。在再次查看了我们的自举置信区间的输出后,看起来平均而言,对于温度上升一度,峰值需求有望从 ~496.896 MW 增加到 527.219 MW。
评估这种关系在周末和工作日之间是否不同的最简单方法是进行简单的方差分析(ANOVA)。这可以在 R 中通过将 simple_anova()函数应用于我们的原始模型来完成:
simple_anova(lm1) %>%
round(3)
执行此代码块将产生以下结果:
Df R2 R2_improve sd sd_improve pval
Intercept 1 0.000 2120.9
temp 1 0.659 0.659 1238.4 882.52 0.000
weekday 1 0.702 0.043 1157.6 80.86 0.000
temp:weekday 1 0.702 0.000 1157.7 -0.10 0.963
Residuals 5816
注:方差分析表本身受制于其中变量的排序,也应如此解读。上面的方差分析表不是这个模型的方差分析表,而是它的一个单一版本。幸运的是,我们感兴趣的联合效应不会因为任何排序的变化而受到影响。然而,如果将来你发现自己在一个更复杂的回归模型上运行 ANOVA,一定要记住这一点。*
在回顾了这些结果之后,交互项的增加似乎对模型性能没有太大的改善(至少在小数点后三位没有可测量的 R2 改善)。这是相当明智的。温度对能量消耗的影响不会因天的分类而改变,所以很明显,前面引用的置信区间适用于周末和工作日。
关闭思路
这一分析为德克萨斯海湾地区的能源消耗模式提供了一些很好的见解。然而,我想指出一些缺点。首先,我构建的自举线性模型的置信区间相当宽。由于意外天气事件和电网中断导致能源消耗的巨大自然差异,这并不奇怪。因此,上述模型中引用的数字估计值应被视为估计值。要进一步精确,就需要将消费模式细分为更具体的类别。我个人认为将我们手头的数据与同一时间段的天气报告结合起来会很有趣。这将允许我们建立一个更实用的多元回归模型,因为墨西哥湾沿岸地区比该州的其他地区更容易发生剧烈的天气变化。
此外,用于此分析的数据集仅涵盖 6 月至 8 月的三个月夏季。这意味着从这些结果中得出的任何论断都只真正适用于夏季。从这里使用的数据得出任何关于 11 月或 12 月能源消耗习惯的结论都是不明智的。同样,从这一分析中得出国家整体消费习惯的结论也是不可取的。我们的数据受到地点和时间的限制,因此我们的结论也是如此。
尽管如此,在过去的一个学期中,这个分析是一个快速而有趣的谜题。该语言内置的 lm()函数使构建回归模型变得简单,只需编写几行代码,而 ggplot2 库允许快速轻松地生成清晰的可视化效果。现代计算能力使得以前复杂的分析变得足够简单,任何人都可以在几分钟内完成。我鼓励大家自己去看看 ERCOT 的数据,看看能做些什么——你可能会发现一些有趣的东西!
英超 VAR 足球决策分析
用 Python 回顾英国足球(EPL)中有争议的视频助理裁判的实现
图片由来自 Pixabay 的 chiraphat phaungmala 拍摄
比赛集锦
TL:DR
- 孙香敏是最频繁卷入 VAR 倾覆事件的人
- 风险值事件倾向于在每一半的中间出现峰值,在每一半的末尾出现峰值
- VAR 决策没有明显偏向大 6 团队
- 在两个 EPL 赛季都实施 VAR 的球队中,布莱顿拥有最高有利于他们的推翻判决的比例(67.9%),而西布罗姆维奇最低(25.0%)
- 链接到这个项目的 GitHub 回购这里
我们现在已经准备好开始了,所以让我们继续阅读!
启动:背景&背景
乔纳森·沃德在 Unsplash 上拍摄的照片
2019 年英超联赛(EPL)引入了视频助理裁判( VAR )系统。它包括借助视频回放和音频耳机对裁判判决进行现场审查。
其目的是通过快速纠正明显的错误和严重的失误事件,减少人为错误对比赛结果的负面影响。尽管其意图如此,但由于其对比赛的破坏性影响,大量违反足球逻辑的有争议的规则,以及决策缺乏标准化,它已经受到了大量的抨击。
现在最近两个 EPL 季节已经结束,有足够的数据让我们回顾到目前为止的 VAR 决策。
上半年:数据采集和准备
(一)数据来源
本次分析的数据来自 ESPN 足球网站,其分析师在该网站上维护了发生在 EPL 的每个风险值事件的最新公开记录。
以下是关于这些数据的一些重要事实:
- 仅涉及被推翻的判决(例如,由现场裁判处理的处罚上诉不包括在内)
- VAR 仅审核四种事件类型 : ( 1 )进球/无进球、( 2 )判罚/无判罚、( 3 )直接红牌(非第二张黄牌/警告)、( 4 )认错人(如裁判罚错球员)
- 2019/2020 和 2020/2021 EPL 季节数据分析
- 数据有两个方面: (1) 团队 VAR 事件汇总统计 (2) VAR 个人事件信息
(二)数据准备
虽然数据以清晰的表格格式出现,但是在进行探索性分析之前,仍然需要执行几个预处理步骤。以下是采取的一些关键步骤:
- 对事件描述文本应用字符串操作和正则表达式,以提取裁判判决(即代表、反对、或中立)、事件类型、比赛时间以及所涉球员姓名等特征
- 标准化足球队的名称,因为它们在不同的数据集中以不同的方式表示(例如,曼联和曼联、西布罗姆维奇和西布罗姆维奇、狼队和狼队等)。)
- 删除重复的行,以防止重复计算每个事件,因为每个事件有一行代表团队的“决定”,另一行代表对手的“决定”。
两个重复行的示例,按作者表示同一 VAR 事件|图像
数据准备的代码和细节请参考 GitHub repo 。
下半年:分析和见解
现在是时候通过从数据中收集有价值的见解来实现一些目标了。我发现通过首先提出业务问题,然后以问答的形式组织分析后的见解来构建分析是最理想的。
问题 1:哪些玩家最常卷入风险值事件?
使用 Python 的Counter
子类及其most_common
方法,我们可以识别在 VAR 事件中出现频率最高的足球运动员姓名(名和姓)。我们可以很容易地发现一些熟悉的名字,只要看看计数为 6 或以上的值。
经常参与 VAR 颠覆活动的玩家的名字/姓氏|图片由作者提供
可以看出,VAR 倾覆事件中最常涉及的前五名参与者(括号中显示的数字)是:
- 孙香民 (10)
- 萨迪奥·马内 (8)
- 加布里埃尔·赫苏斯 (7)
- 卡勒姆·威尔逊 (7)
- 布鲁诺·费尔南德斯 (6)
自 2019/2020 赛季引入 VAR 以来,Son Heung-Min 是卷入 VAR 事件次数最多的球员|图片来源:http://www.soccer.ru/galery/940971.shtml(许可:维基共享,CC BY 3.0)
以上强调了领域知识在数据相关项目中的重要性,因为需要熟悉 EPL 足球运动员才能准确识别和解释这些名字。
问题 VAR 事件在比赛中最常发生在什么时候?
接下来,我们研究 VAR 推翻事件在比赛期间是如何分布的。我使用 Tableau 来创建可视化,而不是使用像seaborn
这样的库,因为 Tableau 的 GUI 使得生成和编辑美观的图表更加有效。
90 分钟内 VAR 倾覆事件的分布。注:上半场和下半场的补时已经分别包含在第 45 分钟和第 90 分钟的时间点|图片由作者提供
VAR 倾覆事件数量趋向于在每半场中间达到高峰(即上半场 24-25 分钟和下半场 76-77 分钟),在每半场结束达到高峰(即 45 和 90 分钟)。
每半场结束时大量的 VAR 事件可能反映了球队在试图赢得或挽救比赛时进攻(甚至抗议)方法的紧迫性和强度。
Qn 3:2020/2021 年的新风险值规则对事件类型的比例有何影响?
英超推出2020/2021 赛季新规则改善 VAR 实施,那么让我们看看它对 VAR 事件类型的影响。
就总数而言,与 2019/2020 赛季( 113 )相比,2020/2021 赛季( 128 )出现的 VAR 逆转略多。至于事件类型,最明显的区别是涉及处罚的事件比例更高(即+13.4%)。
VAR 倾覆事件类型对比(2019/2020 和 2020/2021 赛季)。事件% do 不等于到 100%,因为事件类型不与互斥|图片由作者提供
从表面上看,有人可能会认为新的处罚侵犯规则是这种增长的原因。然而,深入调查发现,与 2019/2020 年的4(36 起处罚事件)相比,只有3(58 起处罚事件)涉及侵占。这意味着这一较高的比例可能是由于偶然(或其他不确定的原因)。
新的越位规则也是最近的重大变化,但越位事件的比例仍然大致相同。总体而言,新规则似乎并未对风险值事件的概况造成重大变化。
问题 4:“六大”团队是否有更多有利于他们的风险值决策?
欧洲超级联赛的溃败引起了很多争议,EPL 的“六大”球队想要脱离出来,组建他们自己的精英比赛。根据对“大 6”的定义,看看风险值决策是否对这些顶级团队有任何偏见将是很有吸引力的。
EPL 六大球队。俱乐部价值基于来自福布斯(2021 年 4 月)|作者图片
三个指标用于评估团队从 VAR 推翻决策中获得的收益:
- **净得分:**支持决策的总数减去反对决策的总数
- **净目标分数:**根据所有风险值决策授予团队的净目标数
- 主观净得分:主观判定“赞成”的数量(即场上裁判的判定)减去主观判定“反对”的数量
通过三个净指标比较大 6 和非大 6 团队的箱线图。分数越高,团队优势越大|作者图片
仅通过观察方框图,VAR outcomes 似乎更倾向于支持非大 6,而不是,主要是在净主观得分和净得分。
为了从统计上而不是从视觉上证实这一点, Welch 的 t 检验被用于在所有三个指标上比较两组。
使用 Python 的 SciPy 库运行 Welch 的 t-tests |作者图片
Welch 的 t 检验得出的所有 3 项指标的 p 值均大于 0.05(即大 6 和非大 6 之间的得分无统计显著差异)。这意味着没有明显的风险值决策倾向于(或反对)6 大团队,这是令人鼓舞的。
奖金洞察力:如果你想知道,在净进球得分和净主观得分方框图中,大 6 的上部异常值实际上是曼联。
Qn 5:哪个 EPL 团队的有利决策比率最高(或最低)?
因为我们看到没有明显偏向六大团队的情况,所以深入了解每个团队的“决策”比率将会很有意思。这将允许我们评估哪些团队拥有对他们有利的最高比例的 VAR 决策。
“支持决策”的百分比是通过将支持团队的决策数除以风险值推翻事件的总数获得的。
EPL 团队的决策比率(降序)|作者图片
看起来布莱顿的风险值推翻决定的比例最高(67.9%),而诺里奇的比例最低。然而,鉴于诺维奇在实施 VAR 的两个赛季中只有一个赛季在 EPL(他们随后被降级),更公平的说法是西布罗姆维奇在两个赛季都在 EPL 的球队中比例最低。
顺便提一下,布莱顿布莱顿也从 VAR 推翻决定中受益最多(与曼联并列),这是基于对他们有利的决定的绝对数量(19)。
全职哨:结论
照片由 Jannes Glas 在 Unsplash 上拍摄
在这个激动人心的足球分析中,我们使用 Python 分析了公开的 EPL 风险值数据,以更深入地了解最近两个 EPL 赛季所做的风险值决策。
笔记本中有更多的见解,所以请在 GitHub repo 中查看。
在你走之前
欢迎您加入我的数据科学学习之旅!点击此媒体页面,查看我的 GitHub ,了解更多精彩的数据科学内容。同时,祝你自举愉快!
说完了,该回更衣室了,下一场比赛再见!
** 💔-steps-to-get-tableau-desktop-specialist-certified-in-2-weeks-abbef25778de> **
解析伊拉斯谟与熊猫的学习交流
在 Erasmus 计划 2011–12 中进行的 200,000 次研究交流的数据集分析结果
自 1987 年以来,伊拉斯谟项目每年为成千上万的欧洲学生提供在另一个欧洲国家度过一个学期或一年的机会,为他们提供一个简单的交流过程以及经济支持。这是一次真正有价值的经历,它打开了他们的思想和心灵,让他们了解欧洲不同的民族、语言和文化。
我在奥地利的维也纳做了我的伊拉斯谟交换,那也是一次难忘的经历。我在那里上过一门课,我们必须做一个关于数据分析的项目, Hilke van Meurs 和我决定对 2011-12 学年的 Erasmus exchange 数据进行分析,这些数据可以在欧盟开放数据门户中找到。一年后的今天,我和你们分享这个项目。
设置
我们在这个任务中的主要需求是使用 JupyterLab 作为工作环境,使用 Python 作为编程语言,使用 Pandas 作为数据处理库。此外,我们必须使用 Matplotlib 来绘制一些图形,以及 Scipy 和 Numpy 来执行一些操作。
理解数据
从欧盟开放数据门户下载的数据集是一个 CSV 文件,其中每一行代表一名学生,每一列给出关于她交换的信息,比如她来自的国家和去的大学、学习领域、交换长度……
伊拉斯谟数据集的预览
有很多列,其中很多对这个项目没有用,所以现在不描述它们,我会在我们需要使用它们的时候解释它们的意思。另一个重要的事实是,这个数据集不仅提供了关于学习交流的信息,还提供了其他类型的伊拉斯谟实习的信息,如实习。因为这个项目只关注学习交流,其他的将会被取消,我们很快就会看到。
下载和清理数据
所以让我们开始工作吧!首先,让我们从在 JupyterLab 中创建一个新的笔记本开始,导入一些我们需要的基本库,并设置绘图样式:
然后,我们必须从欧盟数据门户服务器下载数据集,并将其转换为熊猫数据框架:
最后,由于该数据集涵盖了学习和实习交流,并且我们希望仅关注学习交流,因此我们将删除与职位安排相对应的行和列:
分析单变量
年龄、获得的资助和学分
现在,我们的数据已经准备好进行分析,让我们开始计算一些单一变量的最小、最大、平均和标准偏差,如学生的年龄、他们获得的助学金或他们学习的 ECTS(学分)数。为了更好地理解这些数据,我们还会将其绘制成直方图。
例如,让我们看看如何获得学生年龄的那些统计指标(列年龄):
2011-12 学年最年轻的伊拉斯谟学生只有 17 岁,太神奇了!但最令人惊讶的是,年龄最大的竟是 83 岁,真是难以置信。我们非常震惊,于是我们在数据集中搜索关于这个人的更多信息,出乎意料的是,不止一个,而是两个英国绅士决定参加这个交换项目。然而,平均年龄是 22 岁。
这同样适用于总计( STUDYGRANT )和每月(study grant/length study period)收到的资助和学分数(TOTALECTSCREDITS)–您可以在完整的笔记本中找到代码。
性别百分比
确定男女比例也是非常有趣的。这可以通过从数据帧中获取性别列并计算’ F ‘(女性)和’ M '(男性)的出现次数来实现:
很简单,对吧?看起来 60.59%的学生是女性,而男性只有 39.41%。然而,这个比率在不同的目的地大学之间变化很大,我们稍后会看到。
60.59%的学生是女性,39.41%是男性
发送和接收大学
你很好奇欧洲送留学生比较多的大学有哪些?然后,只需从 DataFrame 中获取列’ HOMEINSTITUTION ',用 value_counts() 方法计算其唯一值和频率,并绘制成条形图:
发送机构前 10 名
如果你想获得接收机构的前 10 名,只需将’ HOMEINSTITUTION ‘替换为’ HOSTINSTITUTION '即可!不言而喻,前 10 个发送机构中有 8 个也是前 10 个接收机构。
语言
英语被认为是世界通用语言,但这并不意味着欧洲学生出国交流时会学习莎士比亚语言的课程。对于数据集中的每个学生,language teached列给出了他们接受课程时所用的语言,因此让我们为这些课程画出十种最流行的语言:
正如我们所料,英语是最受欢迎的,有 10.3 万名学生,其次是西班牙语,有 2.7 万名学生,几乎低 4 倍。
到目前为止,英语是教得最多的语言
那么,这是否意味着在英国和爱尔兰,伊拉斯谟的学生用英语授课的比例要比在西班牙用西班牙语、法语等授课的比例高得多?让我们去发现它!
伊拉斯谟学生用当地语言学习的前 10 个国家
一点也不!英国 91.9%的伊拉斯谟学生用英语学习(因此,尽管英语无所不能,但即使在英国也有外语课程),其次是爱尔兰的 86.8%。第三,西班牙 84.5%的伊拉斯谟学生用西班牙语上课,第四,法国 81.1%的学生用法语上课。第一名和第五名(英国和意大利)的差距只有 14%。
主题领域
另一个基本问题是伊拉斯谟学生最受欢迎和最不受欢迎的学科领域是什么。根据联合国教科文组织的 ISCED 分类,有九个学习领域:教育,人文&艺术,社会科学&商业&法律,科学,工程&制造业&建筑,农业,卫生&福利,服务。对于我们数据集的每一行,在列 SUBJECTAREA 中有一个代表学生学科领域的数字。然而,从那个字段我们只需要第一个数字,所以请注意代码,因为它有一个复杂的函数:
拥有超过 8 万名学生,目前最受欢迎的学习领域是社会科学、商业和法律。银牌和铜牌分别授予人文&艺术和工程、制造&建筑,分别为 44.7k 和 30.8k 的学生。
分析多个变量
按接收大学分列的性别比例
有没有想过欧洲有没有「女子大学」或者「男子大学」?嗯,我们很惊讶地知道,有许多机构只接收男性或女性学生,你知道吗?我们可以很容易地对进入大学的女生比例排名前 30 名,对进入大学的男生比例排名前 30 名。
令人惊讶的是,在这两个排名中,男性或女性的百分比都是 100%。除非你列出前 123 所大学,否则你不会看到低于 100%的男性比例,除非你列出前 256 所大学,否则女性比例也不会低于 100%。
接收大学的平均年龄
想知道哪些大学接收最老的学生,哪些是最年轻的?
虽然在最年轻的排名中,差距很小,从 18 岁(即巴塞罗那的波布伦努,事实上,它不是一所大学,而是一所技术学院中心)到前 10 名中的 19.5 岁,但在最老的排名中,差距更大:德国的第 21 所大学为 45 岁,而第 10 名是法国的阿尔伯特·加缪中学,其新生的平均年龄为 32 岁。
每个国家的学生流入和流出比率
我出生的国家,西班牙,是欧洲学生最向往的出国目的地之一。然而,很多西班牙学生也参加了伊拉斯谟竞赛,就像我一样,所以比例相当均衡。然而,有些国家向海外输送了大量学生,却几乎没有接收任何学生,反之亦然。通过柱状图,我们可以很容易地看到每个国家的发送/接收比率。
分析变量之间的相关性
母国和东道国
母国和目的地国是分类变量,而不是数字变量,因此计算相关指数并不简单。出于这个原因,我们选择了更直观的东西,比如热图。
在上面的热图中,每行代表一个国家,每列代表一个目的地。每个国家的结果都是标准化的,这意味着颜色代表每个国家(行)选择每个目的地(列)的学生的百分比。从图表中可以看出,这两个变量的熵值非常低,这意味着对于一个特定的国家来说,哪一个是首选目的地是完全可以预测的。让我们为一个国家检查一下:
如果原籍国和目的地国之间没有相关性,那么对于每个原籍国,每个目的地国将接收 2.86%的学生。然而,从上面的热图和饼图来看,情况并非如此。例如,在饼图中,我们可以看到西班牙学生非常喜欢意大利(21.3%)、法国(12.4%)、德国(11.1%)、英国(9.4%)、葡萄牙(6.8%)和波兰(6.6%)。
目的地和主题区域
欧洲各地有非常著名的大学,但是很难找到一所在每个知识领域都出类拔萃的大学。因此,了解每个学科领域是否存在对某些机构的偏好会很有意思。因为我们再次处理分类变量,让我们应用和以前一样的技术。
如果学科领域和目的地大学之间的相关性为零,对于每个学科领域,每个目的地大学将接收 0.04%的学生。然而,对于大多数学科领域,接收更多学生的机构在 1%和 3.7%之间,表明这两个变量之间的熵并不高。然而,从这个意义上说,我们找不到任何一所大学比其他大学更突出。“普通”类别的百分比非常高,只有三所院校接收了几乎 50%的学生。
母国和东道国以及每月补助金
当我在 2019 年为我的 Erasmus exchange 做文书工作时,我记得西班牙政府根据生活成本设置了三组目的地国家,每个月给每个人不同的补助金。我一到那里,就惊讶地发现一些来自其他欧洲国家的朋友收到的钱比我多或少。那么,每月的补助取决于什么:你要去的国家,还是你来自的国家?让我们去发现它!
每个目的地国家每月补助的方框图
每个派遣国每月赠款的方框图
比较这两个图,排除大量的异常值,很明显,在学生收到的钱的数量上,母国比目的地国是一个更具决定性的因素。在第一张图中,看起来每个目的地国家的每月赠款的平均值相当同质,对于大多数目的地国家来说,方差非常高,从平均值的 50%到 150%不等,而在第二张图中,方差非常低,平均赠款非常异质。因此,正如我在做这个分析之前所想的,每月的补助金主要取决于你来自哪个国家。
我希望这封信对你来说不会太长。事实上,在这篇文章中,我跳过了我们的一些见解,以免写得太长,所以如果你感兴趣,这里有完整的笔记本。我还想再次对 Hilke van Meurs 为这个项目所做的工作表示感谢。当然,如果你有任何问题或建议,请在评论中告诉我。
参考
- https://jupyter.org/install
- 熊猫 data frame:https://pandas . pydata . org/pandas-docs/stable/reference/API/pandas。DataFrame.html
- https://matplotlib.org/api/
- 伊拉斯谟 2011-12 年数据集:https://data . Europa . eu/eu ODP/en/data/dataset/伊拉斯谟-移动性-统计-2011-12
- GitHub 中的 Jupyter 笔记本:https://GitHub . com/gbarreiro/Erasmus-data-analysis/blob/main/Erasmus . ipynb
用 Python 分析金融数据
探索 Python 中的金融数据
照片由energepic.com在像素上拍摄
探索性数据分析(EDA)是每个数据科学家工作流程的重要组成部分。EDA 允许数据科学家总结他们正在处理的数据的最重要的特征。在金融数据分析中,这包括生成简单的汇总统计数据,如回报率和平均回报率的标准差,通过关联热图可视化股票之间的关系,生成股票价格时间序列图、箱线图等。
让我们来分析一下三只股票:亚马逊(Amazon)、谷歌(Google)和苹果(Apple)。我们将看到如何对这些股票进行简单的探索性数据分析,方法是生成汇总统计数据和可视化数据、风险和回报分析,以及生成滞后指标以了解股价趋势。对于想开始学习如何用 Python 分析金融数据的初学者来说,这应该是一个坚实的基础。在我们开始之前,这里有一些我们将使用的工具。
pandas-datareader 是一个 Python 库,允许用户轻松访问股票价格数据并执行统计分析任务,如计算回报、风险、移动平均线等。此外,matplotlib 和 seaborn 是 Python 中的库,进一步允许您创建数据可视化,如箱线图和时间序列图。这些库的组合使数据科学家能够用相对较少的代码行从金融数据中获得强大的洞察力。
股票风险分析对于理解股票价格波动的不确定性非常重要。这可以帮助投资者根据他们的风险承受能力选择他们想要投资的股票。我们可以使用移动平均线计算,通过描述股票价格运动的方向趋势,进一步为投资决策提供信息。
最后,布林线图是可视化价格波动的有用方法。布林线图和均线就是我们所说的滞后指标。这意味着它们基于长期变化,有助于我们理解长期趋势。这与用来预测未来价格变动的领先指标形成对比。
使用 Pandas-Datareader 访问财务数据
首先,我们需要在终端中使用以下命令安装 pandas-datareader 库:
pip 安装熊猫-datareader
接下来,让我们打开一个新的 Python 脚本。在脚本的顶部,让我们从 pandas_datareader.data 模块导入 web 对象。让我们也导入内置的 datetime 包,它将允许我们创建 Python datetime 对象:
import pandas_datareader.data as webimport datetime
现在让我们提取 Amazon 的股票价格数据,将其存储在一个名为 amzn 的变量中,并显示前五行数据:
amzn = web.DataReader(‘AMZN’,’yahoo’,start,end)print(amzn.head())
作者图片
我们看到数据框有高、低、开仓、收盘、成交量和调整收盘等列。这些值基于交易时段(通常是上午 9:30 到下午 4:00)的股票价格。让我们考虑一下这些列的含义:
- 高价:股票在交易过程中的最高价格
- 低价:股票在交易过程中的最低价格
- 收盘价:股票在交易时段结束时的价格
- 开盘价:股票在交易时段开始时的价格
- 调整后收盘价:对股票分割和股息进行调整后的收盘价
接下来,我们应该使用 pandas to_csv 方法将这些数据保存到一个. csv 文件中:
amzn.to_csv(f’amzn_{start}_{end}.csv’, index=False)
现在我们已经有了 AMZN 的数据,让我们提取 GOOGL 和 AAPL 的数据。我们将从谷歌开始,然后转移到 AAPL。
googl = web.DataReader(‘GOOGL’,’yahoo’,start,end)print(googl.head())googl.to_csv(f”googl_{start}_{end}.csv”, index=False)
作者图片
接下来,我们来拉一下 AAPL:
aapl = web.DataReader(‘AAPL’,’yahoo’,start,end)print(aapl.head())aapl.to_csv(f”aapl_{start}_{end}.csv”, index=False)
我们现在应该有三个文件,包含 AMZN、GOOGL 和 AAPL 两年的股票价格数据。让我们把这些文件读入新的熊猫数据帧:
import pandas as pdamzn_df = pd.read_csv(f’amzn_{start}_{end}.csv’)googl_df = pd.read_csv(f’googl_{start}_{end}.csv’)aapl_df = pd.read_csv(f’aapl_{start}_{end}.csv’)
探索和可视化财务数据
接下来,我们可以生成一些简单的统计数据。理解股票价格变动的一个重要指标是回报率。回报的定义是开盘价减去收盘价除以开盘价(R =[开盘价-收盘价]/开盘价)。让我们计算每个股票的收益。让我们从计算 AMZN 的日回报率开始:
amzn_df[‘Returns’] = (amzn_df[‘Close’] — amzn_df[‘Open’])/amzn_df[‘Open’]
作者图片
我们可以创建一个简单的可视化图形,即 AMZN 股票价格的每日回报直方图。我们可以使用 seaborn 进行样式设计,使用 matplotlib 生成直方图:
import matplotlib.pyplot as pltimport seaborn as snsamzn_df[‘Returns’] = (amzn_df[‘Close’] — amzn_df[‘Open’])/amzn_df[‘Open’]amzn_df[‘Returns’].hist()plt.title(‘AMZN Stock Price Returns Distribution’)plt.show()
作者图片
我们可以对谷歌重复这一点:
googl_df[‘Returns’] = (googl_df[‘Close’] — googl_df[‘Open’])/googl_df[‘Open’]googl_df[‘Returns’].hist()plt.title(‘GOOGL Stock Price Returns Distribution’)plt.show()
作者图片
和 AAPL:
aapl_df[‘Returns’] = (aapl_df[‘Close’] — aapl_df[‘Open’])/aapl_df[‘Open’]aapl_df[‘Returns’].hist()plt.title(‘AAPL Stock Price Returns Distribution’)plt.show()
作者图片
我们还可以计算每只股票的平均回报率和回报率的标准差,并将它们显示在直方图的标题中。这些统计数据对投资者来说非常重要。平均回报率让我们了解股票投资的盈利能力。标准差是衡量回报波动程度的指标。在金融界,我们称之为风险。通常情况下,高风险伴随着高回报。让我们展示一个 AMZN 的例子。首先,我们将平均值和标准偏差存储在变量中,并使用 f 字符串来格式化标题:
mean_amnz_returns = np.round(amzn_df[‘Returns’].mean(), 5)std_amnz_returns = np.round(amzn_df[‘Returns’].std(), 2)plt.title(f’AMZN Stock Price Returns Distribution; Mean {mean_amnz_returns}, STD: {std_amnz_returns}’)plt.show()
作者图片
另一个有用的数据可视化是箱线图。类似于直方图,这是另一种可视化数据的均值、离散度和偏斜度的方法。在我们的财务数据的背景下,它可以帮助我们比较每只股票的平均回报、回报的离差和回报的偏度,这有助于为投资决策提供信息。首先,让我们将每只股票的回报合并到一个数据框架中:
amzn_df[‘Ticker’] = ‘AMZN’googl_df[‘Ticker’] = ‘GOOGL’aapl_df[‘Ticker’] = ‘AAPL’df = pd.concat([amzn_df, googl_df, aapl_df])df = df[[‘Ticker’, ‘Returns’]]print(df.head())
为了生成箱线图,我们使用以下代码:
sns.boxplot(x= df[‘Ticker’], y = df[‘Returns’])plt.title(‘Box Plot for AMZN, GOOGL and AAPL Returns’)plt.show()
作者图片
我们将讨论的最后一个可视化是退货的关联热图。这种可视化有助于我们理解股票价格回报之间是否存在线性关系。这很重要,因为它可以提供投资者投资组合中股票之间关系的见解,因此也有助于了解投资者如何构建投资组合。为了创建我们的热图,让我们首先创建一个新的数据框,其中包含每个 ticker 的一列:
df_corr = pd.DataFrame({‘AMZN’:amzn_df[‘Returns’], ‘GOOGL’:googl_df[‘Returns’], ‘AAPL’:aapl_df[‘Returns’]})
接下来让我们计算每只股票收益之间的相关性:
作者图片
这张热图显示,每只股票都有正的线性关系。这意味着,当 AMZN 的日收益增加时,AAPL 和谷歌也可能增加。反之亦然。如果 AMZN 收益减少,其他也可能减少。一个好的投资组合包含多样化的资产。在这种情况下,这意味着我们应该选择彼此相关性不强的股票,如 AAPL、AMZN 和 GOOGL。这是因为如果一只股票的回报下降,你的整个投资组合的回报也会减少。在股票互不相关的多元化投资组合中,一只股票的价格不一定会随着其他股票的价格一起上涨或下跌。
滞后指标
我们接下来要做的计算是两种不同的滞后指标,移动平均线和布林线图。移动平均线是分析师用来消除股价短期波动以了解价格方向趋势的常用技术。在这里,我们将绘制 AMZN、GOOGL 和 AAPL 的移动平均线。先说 AMZN。我们将绘制 AMZN 调整后收盘价的 10 天移动平均线,并考虑 2021 年 1 月 23 日之后的股价:
cutoff = datetime.datetime(2021,1,23)amzn_df[‘Date’] = pd.to_datetime(amzn_df[‘Date’], format=’%Y/%m/%d’)amzn_df = amzn_df[amzn_df[‘Date’] > cutoff]amzn_df[‘SMA_10’] = amzn_df[‘Close’].rolling(window=10).mean()print(amzn_df.head())plt.plot(amzn_df[‘Date’], amzn_df[‘SMA_10’])plt.plot(amzn_df[‘Date’], amzn_df[‘Adj Close’])plt.title(“Moving average and Adj Close price for AMZN”)plt.ylabel(‘Adj Close Price’)plt.xlabel(‘Date’)plt.show()
作者图片
在上图中,蓝线是移动平均线,橙色是调整后的收盘价。我们可以为 GOOGL 做同样的事情:
googl_df[‘Date’] = pd.to_datetime(googl_df[‘Date’], format=’%Y/%m/%d’)googl_df = googl_df[googl_df[‘Date’] > cutoff]googl_df[‘SMA_10’] = googl_df[‘Close’].rolling(window=10).mean()print(googl_df.head())plt.plot(googl_df[‘Date’], googl_df[‘SMA_10’])plt.plot(googl_df[‘Date’], googl_df[‘Adj Close’])plt.title(“Moving average and Adj Close price for GOOGL”)plt.ylabel(‘Adj Close Price’)plt.xlabel(‘Date’)plt.show()
作者图片
最后是 AAPL:
aapl_df[‘Date’] = pd.to_datetime(aapl_df[‘Date’], format=’%Y/%m/%d’)aapl_df = aapl_df[aapl_df[‘Date’] > cutoff]aapl_df[‘SMA_10’] = aapl_df[‘Close’].rolling(window=10).mean()print(googl_df.head())plt.plot(aapl_df[‘Date’], aapl_df[‘SMA_10’])plt.plot(aapl_df[‘Date’], aapl_df[‘Adj Close’])plt.title(“Moving average and Adj Close price for AAPL”)plt.ylabel(‘Adj Close Price’)plt.xlabel(‘Date’)plt.show()
我要讨论的最后一种图是布林线图,这是一种可视化移动平均线离差的方法。波段由上限和下限定义,上限和下限与简单移动平均线相差两个标准差。这对交易者很有用,因为这让他们可以利用价格波动的优势。让我们为 AMZN 生成一个布林线图:
amzn_df[‘SMA_10_STD’] = amzn_df[‘Adj Close’].rolling(window=20).std()amzn_df[‘Upper Band’] = amzn_df[‘SMA_10’] + (amzn_df[‘SMA_10_STD’] * 2)amzn_df[‘Lower Band’] = amzn_df[‘SMA_10’] — (amzn_df[‘SMA_10_STD’] * 2)amzn_df.index = amzn_df[‘Date’]amzn_df[[‘Adj Close’, ‘SMA_10’, ‘Upper Band’, ‘Lower Band’]].plot(figsize=(12,6))plt.title(’10 Day Bollinger Band for Amazon’)plt.ylabel(‘Adjusted Close Price’)plt.show()
作者图片
对于谷歌来说:
googl_df[‘SMA_10_STD’] = googl_df[‘Adj Close’].rolling(window=10).std()googl_df[‘Upper Band’] = googl_df[‘SMA_10’] + (googl_df[‘SMA_10_STD’] * 2)googl_df[‘Lower Band’] = googl_df[‘SMA_10’] — (googl_df[‘SMA_10_STD’] * 2)googl_df.index = googl_df[‘Date’]googl_df[[‘Adj Close’, ‘SMA_10’, ‘Upper Band’, ‘Lower Band’]].plot(figsize=(12,6))plt.title(’10 Day Bollinger Band for Google’)plt.ylabel(‘Adjusted Close Price’)plt.show()
最后对 AAPL 来说:
aapl_df[‘SMA_10_STD’] = aapl_df[‘Adj Close’].rolling(window=10).std()aapl_df[‘Upper Band’] = aapl_df[‘SMA_10’] + (aapl_df[‘SMA_10_STD’] * 2)aapl_df[‘Lower Band’] = aapl_df[‘SMA_10’] — (aapl_df[‘SMA_10_STD’] * 2)aapl_df.index = aapl_df[‘Date’]aapl_df[[‘Adj Close’, ‘SMA_10’, ‘Upper Band’, ‘Lower Band’]].plot(figsize=(12,6))plt.title(’10 Day Bollinger Band for Apple’)plt.ylabel(‘Adjusted Close Price’)plt.show()
作者图片
如果你有兴趣访问这篇博客中使用的代码,可以在 GitHub 上找到。
有各种各样的有用工具可以从财务数据中提取、分析和生成见解。这些工具的组合使得初学者可以很容易地开始使用 Python 处理金融数据。这些技能可以用于个人投资、算法交易、投资组合构建等等。对于任何对金融感兴趣的分析师或数据科学家来说,能够快速生成统计见解、可视化关系并精确定位金融数据的趋势是非常宝贵的。
如果你有兴趣学习 python 编程的基础知识、Pandas 的数据操作以及 python 中的机器学习,请查看Python for Data Science and Machine Learning:Python 编程、Pandas 和 sci kit-初学者学习教程 。我希望你觉得这篇文章有用/有趣。
本帖原载于 内置博客 。原片可以在这里找到https://builtin.com/data-science/financial-data-analysis。
用自然语言处理分析印度诗歌
使用 Python 对“毗湿奴”和“魔鬼”斯洛卡进行分类
布达扬·巴德汉在 Unsplash 上拍摄的照片
“文本分类”是一种机器学习技术,用于分析文本,然后根据模式或结构对其进行组织或分类。文本分类在人工智能领域有很多 应用 比如新闻文章分析、仇恨言论识别、性别分类等。在这篇文章中,我使用“文本分类”和使用 Python 的自然语言处理(NLP)来分析印度教经文并对它们进行分类。在我们更深入地研究 Python 的技术方面之前,让我们快速地看看我们将处理哪些数据。
“Sahasranama”——字面上有 1000 个名字(其中“ sahasra ”的意思是 1000,而“ nama ”的意思是名字)——是一首赞美印度教神的圣歌。https://en.wikipedia.org/wiki/Lalita_Sahasranama【颂难近母女神】和 毗湿奴 【颂摩诃毗湿奴】就是这样两个颂难近母女神和摩诃毗湿奴的诗句,各有 1000 个不同的名字。我从以下链接中获得了用于我们分析的数据:‘Lalitha Sahasranama’和’Vishnu Sahasranama’,并对其进行了清理,删除了“om”和“namah”,并将数据保存为 文本文件 。
导入库:
第一步是导入我们分析所需的库。从下面的代码中可以看出,我们使用了 3 个不同的库。
*#Import required librariesfrom nltk.classify import accuracy #For accuracy predictor
import random #For randomly shuffling the names
import nltk #Natural Language toolkit*
NLTK —自然语言工具包
NLTK 准确性——用于显示我们预测的准确性
Random —用于为我们的训练集和测试集随机排列名称
加载数据和标记:
在“读取”模式下使用 open() 功能,然后使用 readlines() 功能将文件的内容分配给一个列表。
读取数据并标记它
下一步是将标签’ Devi ‘和’ Vishnu '分配给被读取的相应诗句。这个标签后面会用来给诗句分类。
标签分配的输出 Jupyter 笔记本的屏幕截图
random . shuffle()函数用于随机打乱列表,使数据均匀分布在两个列表中。
特征提取:
定义特征提取的函数
我们定义一个函数来从列表中传递的诗句中提取特征。定义的函数提取最后 2 个字符来开发模型。
从诗歌列表中提取特征 Jupyter 笔记本截图
使用朴素贝叶斯分类器创建模型:
图像专家:走向数据科学— 朴素贝叶斯分类器。什么是量词?|作者 Rohith Gandhi |走向数据科学
朴素贝叶斯分类器基于贝叶斯定理,该定理用于通过假设第二个事件 B 已经发生来找出事件 A 发生的概率。
第一步是将数据分为训练集(前 1000 节)和测试集(后 1000 节)。
检查最具信息性的特征和模型准确性
nltk . classify . accuracy()函数用于显示使用训练集或测试集作为参数的预测结果的准确性。
show _ most _ informational _ features(n)函数基于特征提取突出显示可用诗句的最具信息性的 n 个特征。
分类器精度和“显示大多数信息特征”的输出如下所示。这个分类器有将近 97%的准确率。我们也看到,与神摩诃毗瑟奴相对应的诗句通常以“ya”结尾,而与女神难近母相对应的诗句通常以“ai”作为最后两个字符。
我们的数据集最具信息性的特征 Jupyter 笔记本截图
检查分类输出:
检查分类输出 Jupyter 笔记本的屏幕截图
让我们检查分类输出,并将其与之前分配给诗句的原始标签进行比较。为此,我们创建一个空列表,然后使用(classifier . classify(name _ features(name)))函数比较模型的输出,并将其与之前最初分配的标签进行比较。如果我们有兴趣查看那些不匹配的,我们可以简单地替换“If”条件来查找输出,其中 model_output!=神。这里显示了一个正确分类输出的示例。
检查模型输出与标签
整个代码可以通过 Github 库 下载。
参考资料:
- 分类(bgu.ac.il) —使用 NLTK 进行性别分类的优秀范例
- Python |使用 NLTK 的性别识别— GeeksforGeeks
- 朴素贝叶斯分类器。什么是量词?|作者 Rohith Gandhi |走向数据科学
- nltk.classify 包— NLTK 3.6.2 文档
- Python 编程教程
- Python 的自然语言工具包(NLTK)教程第 3 部分|作者:Ishan Dixit | Medium
使用 QGIS 和 PostGIS 函数分析孟买的出租房屋
基于 QGIS 的空间数据分析
作者图片
介绍
孟买是印度人口最多的大都市之一,人口持续增长,超过 2000 万。它也被认为是印度的经济首都,因为这里有大量的工业和组织总部。因此,来自全国各地的人们带着各种各样的学习和工作前景来到孟买,这使得房地产行业繁荣起来,出租或租赁的公寓价格飞涨。
在这个项目中,我们将尝试使用 PostGIS 和 QGIS 分析 2020 年孟买出租或出售的公寓,并根据一些预定义的条件得出结论。
动机
几个月前,我的表弟试图在市区内找到一套合适的公寓出售。她几乎没有条件将搜索范围从整个孟买缩小到一些特定的地点。条件如下。
- 她想了解这些房产的价格,以便决定她的预算。
- 公寓应该在孟买国际机场的 5 公里半径内(因为她在机场工作)。
- 公寓应该靠近海滩,面朝大海。
- 最后,她还想找到去孟买海军造船厂的最快路线,因为我的 BIL 在那里工作。
这激起了我的兴趣,我参与了这个项目,并为他们找到了一套符合她大部分标准的好公寓。
履行
从分析开始,我从 Kaggle 导入了孟买房价数据集。该数据集包含位于孟买市的各种公寓的详细信息。该数据集中可用列的描述如下。
- 面积:房屋的建筑面积
- 浴室数量:可用的浴室数量
- 卧室数量:可用卧室的数量
- 城市:物业所在的城市
- desc:属性的文本描述
- 开发商名称:房地产开发商的名称
- floor_count:建筑物的总层数
- floor_num:物业所在的楼层
- 家具:家具状态
- id:唯一的 ID
- id_string:用于抓取特定 HTML 页面元素的唯一 id 字符串。
- 纬度:位置的纬度
- 地点:财产所在的地点
- 经度:位置的经度。
- post_date:酒店在网站上发布的日期。
- 发帖人姓名:发帖人姓名
- 价格:财产的价格
- 项目:住宅区的名称
- 标题:网站上物业广告的标题
- 交易:财产交易的类型
- 类型:住宅区的类型
- URL:单个属性的 URL
- user_type:发布广告的用户的类型
我已经将数据下载为 CSV 文件,然后用 python 编写了一个小程序来清理数据,并将其加载到 PostgreSQL 的一个表中。在这里可以找到笔记本。
我发现这些列中很少有空值,所以为了简化分析,我考虑删除这些列。在数据清理过程之后,现在需要将数据帧转换为 GeoPandas 数据帧,以便在 PostGIS 中表示空间数据。这里使用的 CRS 是 EPSG:4326。然后将数据加载到 PostgreSQL 数据库中,表名为 mumbai_house_price_raw 。
分析
我们将执行以下分析,然后在分析过程中得出结论。
- 在地图上可视化整个数据集
- 按价格区间分析公寓
- 寻找机场半径 5 公里内的地方
- 选择面向大海的公寓
- 距离海军船坞的距离
在地图上可视化整个数据集
现在我们已经在 PostgreSQL 表中有了整个数据集,我们可以很容易地将其导入 QGIS,并可视化孟买的各种房屋。首先,让我们将 OpenStreetMap 导入 QGIS 作为背景层。
转到 Web → QuickMapServices → OSM → OSM 标准。
图层→添加图层→添加 Postgis 图层。选择 PostGIS 中可用的表的名称,然后单击添加。
PostgreSQL 表中的所有数据点现在都将加载到 QGIS 图层中,并且这些点将绘制在地图上。为了更好的理解,我还提供了孟买机场和海军船坞的准确位置。
按价格区间分析公寓
如上图所示,地图上显示了超过 30000 套公寓。然而,看看这些公寓的价格范围如何因地区而异会很有意思。基本上,我们试图回答的是当地是否对房价有影响。
为此,我们将房价分成如下 3 个部分。
- 低于 20K
- 20K 到 40K
- 40K 以上
我将在 PostgreSQL 表中添加一列,并更新关于 bin 的相关信息。
现在,我们需要刷新已经在 QGIS 中获取的图层。这将带来我们刚刚创建的新列’ house_price_category 。一旦新列位于图层中,下一步就是基于此类别在地图上显示点。
右键单击图层→属性→符号系统→分类→值= house_price_category →颜色渐变=为 3 个类别创建手动颜色渐变→分类。
这将把地图上的所有点分类到三个箱中,如下所示。
从上面的分析中,我们现在对在孟买市找房子的预算有了一个概念。虽然很少房子的价格低于 40K(绿色和蓝色,T1),但大多数房子的价格高于 40K(T2 红色,T3)。为了验证上述观察结果,我使用 SQL 做了一个快速检查,以找到每个类别中的公寓数量。
经核实,在 5 万套以上的公寓中,大约有 2 万多套。所以,如果我们保持高预算,租一套更好的公寓的可能性更大。
寻找机场半径 5 公里以内的地方
孟买机场位置:Lon: 72.874374,Lat: 19.096713
- 在 PostgreSQL 中创建一个查询,该查询将过滤机场 5 公里半径内的建筑物名称→创建并将其存储在视图中。
- 将上一步创建的视图提取到 QGIS 中,并绘制公寓图。
以下是距机场 5 公里范围内所有公寓的平面图。
选择面朝大海的公寓
在这里,我们需要找到面朝大海的公寓。这是一个棘手的部分,因为我们需要某种基准来决定公寓是靠近还是远离海岸,以及公寓是否面向西方。对于那些靠近海滩但面朝其他方向的公寓,应该排除在分析之外。
我们可以从 OSM 获取海岸线。为此,我们需要安装快速浏览插件,然后选择矢量→快速浏览→快速浏览。在快速查询页签中,提供关键字为自然、值为海岸线,选择画布范围点击运行查询。
这是在 QGIS 中作为孟买海岸线的一部分导入的。我们可以导出这条海岸线,并将其保存为一个 SQL 转储,然后加载到 PostgreSQL 表中。你可以看到部分海岸线用黑色突出显示。
既然海岸线已经准备好了,我们可以在海岸的一边创建一个 1000 米的缓冲区,它会显示缓冲区内的公寓。
转到数据库管理器,编写一个简单的 SQL 查询,如下所示,根据海岸线几何数据获取缓冲区。将其作为新图层导入到 QGIS 中。
对于面朝大海的公寓,他们需要面朝西方。“ desc ”列包含该信息,我们将创建一个视图,使用 REGEX 过滤匹配单词‘T14’朝西’或‘T16’朝西’的记录。将此新视图导入 QGIS 并绘制输出。
以下是最终输出。
在这里,正如你所看到的,我们有一些朝西的公寓和 1000 米的海岸线缓冲区。位于缓冲区的公寓是我们的兴趣点,因为它们都在海滩的 1000 米范围内,并且都朝西。所以这些公寓可以通过实地参观来进一步调查。
最终分析-距海军船坞的距离
经过实地考察,他们决定敲定位于 Juhu Tara 路的 2BHK 公寓,详情如下。
现在,我们将设法找到最快和最短的路线乘车到海军船坞。
海军造船厂位置:经度:72.832096,纬度:18.926257
为此,我们将使用名为 ORS 工具的开放路线服务插件。
一旦插件安装完毕,下一步就是在openrouteservice.org注册并获得一个 API 密钥。
如上图所示,我们选择了起点作为家,终点作为海军船坞交汇处。上面显示了驾驶汽车时最快的路线,距离约为 19.5 公里。
或者,我们也可以进行最短路径分析,看看最快路径和最短路径是否相同。仅通过改变参数重复上述过程。
如上图所示,最短路径约为 19.2 公里,在某些点上与最快路径不同。
结论
到目前为止,在这个项目中,我们已经广泛利用 QGIS 和 PostGIS 功能来分析孟买市的房屋,并得出了购买或租赁符合我们要求的房屋的结论。我们还计算了从公寓到海军船坞的最快和最短的路线,并了解到两条路线之间有一些小的差异。
QGIS 所有图层
上面是我们在这个项目中分析过的所有图层的示意图,下面会提到图例。
- 小圆点(红/绿/蓝)——所有可供出售的公寓。
- 绿色大圆圈——机场 5 公里半径内的公寓。
- 带黑点的绿色大圆圈——机场半径 5 公里内的公寓,面朝西。
- 黑线-该区域的海岸线。
- 橙色斑块——海岸线的缓冲区,距离海岸线 1000 米。
- 蓝线——从公寓到海军船坞的最快路线。
- 绿线——从公寓到海军船坞的最短路线。
该项目及其源代码可以在 https://github.com/aveek22/cs621-spatial-db 的找到。
用 R 分析墨尔本房价
数据分析综合实践指南。
哈姆扎·扎伊迪在 Unsplash 上的照片
有几个库和包为数据科学家、分析师或任何对数据感兴趣的人提供了执行高效数据分析的功能。它们中的大多数都有很好的文档记录,所以您可以很容易地找到一个函数是做什么的。
然而,学习这些库的最好方法是通过实践。仅仅知道一个函数做什么是不够的。我们应该能够在正确的时间和地点回忆和使用它们。因此,我强烈建议练习学习一个包或库。
在本文中,我们将使用 R 包探索并深入了解 Kaggle 上可用的墨尔本房屋数据集。
对于数据分析和操作,我们将使用 r 的 data.table 包。
> library(data.table)> house_prices <- fread("Downloads/melb_data.csv")> head(house_prices)
(图片由作者提供)
该数据集包含墨尔本房屋的几个属性及其价格。因为这个数据集的焦点是价格,所以最好先了解一下价格列。
> house_prices[, summary(Price)] Min. 1st Qu. Median Mean 3rd Qu. Max.
85000 650000 903000 1075684 1330000 9000000
我们使用 price 列上的 summary 函数来获得基本统计数据的概述。平均房价约 107 万。
我们知道一般的平均房价。我们可能需要比较不同地区的房价。这是一个按任务分组的方法,可以通过添加用于分组的列名来轻松完成。
> house_prices[, mean(Price), by = Regionname]
(图片由作者提供)
聚合列表示为“V1 ”,这并不能提供很多信息。我们可以为聚合列指定一个名称,只需稍微改变一下语法。让我们也计算一下每个地区的房屋数量以及平均房价。
> house_prices[, .(avg_price = mean(Price), number_of_houses = .N), by = Regionname]
(图片由作者提供)
数据集中有 3 种类型的房屋,h 代表住宅,u 代表单元住宅,t 代表联排住宅。data.table 包还允许过滤以及聚合和分组。
例如,我们可以计算北部大都市地区每种房屋类型的平均土地面积。
> house_prices[Regionname == 'Northern Metropolitan', .(avg_size = mean(Landsize)), by = Type] Type avg_size
1: h 619.2491
2: u 495.0265
3: t 317.3257
我觉得还是详细阐述一下 data.table 库使用的语法结构比较好。
datatable[ filter/order , select/aggregate/update , by ]
第一个逗号之前的表达式用于排序或过滤。在前面的示例中,我们根据 region name 列过滤了观察值(即行)。
第二部分用于汇总、选择或更新。正如您在示例中看到的,我们已经计算了这一部分的平均价格。最后一部分是根据给定列中的类别对行进行分组。
语法结构提供了执行数据操作、选择和转换的有效方式。例如,我们可以创建一个子集,其中只包含价格低于 100 万英镑的房屋的地址、房间数量和价格。
> subset = house_prices[Price < 1000000, .(Address, Rooms, Price)]
> head(subset)
(图片由作者提供)
我们还可以在选择列的同时执行数据转换或聚合。例如,我们可以在子集中以百万为单位表示价格。
> subset = house_prices[
Price < 1000000,
.(Address, Rooms, Price_million = (Price/1000000))
]
> head(subset)
(图片由作者提供)
如果我们使用“keyby”参数而不是“by”参数,那么结果集将根据类别的升序进行排序。考虑下面的例子。
> house_prices[
,.(avg_distance = mean(Distance), avg_price = mean(Price))
,keyby =.(Type, Regionname)
]
(图片由作者提供)
正如我们所看到的,type 和 region name 列中的类别是按升序排序的。
data.table 包允许链式操作,这进一步简化了更复杂操作的语法。回想一下前面的例子,我们计算了每种类型和地区名称组合的房屋的平均距离和价格。
我们可能希望根据聚合值(如平均价格)对组进行排序。下面是我们如何完成这项任务。
> house_prices[
,.(avg_distance = mean(Distance), avg_price = mean(Price))
,by =.(Type, Regionname)
][order(avg_price)]
(图片由作者提供)
默认情况下,order 函数按升序对值进行排序。我们可以通过在列名前面添加一个减号(例如 order(-avg_price))来将其更改为降序。
结论
我们已经做了几个例子来演示 data.table 包用于数据分析和操作的简单而有效的方法。
能够将过滤、选择、转换和聚合组合到一个方括号中,这使得操作更加直观。
在 data.table 包中还有更多的内容要介绍,但是我们在本文中介绍的内容为高效的数据分析提供了一组不错的操作。
感谢您的阅读。如果您有任何反馈,请告诉我。
使用仪表板分析 ML 模型
显然用于创建机器学习模型仪表板
来源:作者
解释机器学习模型是一个困难的过程,因为通常大多数模型都是一个黑盒,我们并不真正知道模型内部发生了什么。创建不同类型的可视化有助于理解模型是如何执行的,但是很少有库可以用来解释模型是如何工作的。
一个模型的性能可以基于不同的度量标准,如分类报告、MAE、MSE 等。类似地,有不同的可视化显示数据的漂移,这意味着特征分布的变化,我们也可以在目标变量中找到这种漂移。
显然是一个开源 Python 库,用于创建交互式可视报告、仪表盘和 JSON 配置文件,有助于在验证和预测期间分析机器学习模型。它可以创建 6 种不同类型的报告,涉及数据漂移、分类或回归的模型性能等。
在本文中,我们将探索并创建交互式报告/仪表板。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装开始。下面给出的命令可以做到这一点。
!pip install evidently
导入所需的库
在这一步中,我们将导入创建 ML 模型所需的库。我们还将导入一些库,这些库将用于创建一个仪表板来分析模型性能。此外,我们将导入熊猫来加载数据集。
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from evidently.dashboard import Dashboard
from evidently.tabs import RegressionPerformanceTab
from evidently.model_profile import Profile
from evidently.profile_sections import RegressionPerformanceProfileSection
加载数据集
在这一步中,我们将加载数据,并将其分为参考数据和预测数据。
raw_data = pd.read_csv('/content/day.csv', header = 0, sep = ',', parse_dates=['dteday'])ref_data = raw_data[:120]
prod_data = raw_data[120:150]ref_data.head()
数据集(来源:作者)
创建模型
在这一步中,我们将创建机器学习模型,对于这个特定的数据集,我们使用随机森林回归模型。
target = 'cnt'
datetime = 'dteday'
numerical_features = ['mnth', 'temp', 'atemp', 'hum', 'windspeed']
categorical_features = ['season', 'holiday', 'weekday', 'workingday', 'weathersit',]
features = numerical_features + categorical_featuresmodel = RandomForestRegressor(random_state = 0)model.fit(ref_data[features], ref_data[target])ref_data['prediction'] = model.predict(ref_data[features])
prod_data['prediction'] = model.predict(prod_data[features])
创建仪表板
在此步骤中,我们将创建仪表板,用于解释模型性能和分析模型的不同属性,如 MAE、MAPE、误差分布等。
column_mapping = {}
column_mapping['target'] = target
column_mapping['prediction'] = 'prediction'
column_mapping['datetime'] = datetime
column_mapping['numerical_features'] = numerical_features
column_mapping['categorical_features'] = categorical_featuresdashboard = Dashboard(tabs=[RegressionPerformanceTab])dashboard .calculate(ref_data, prod_data, column_mapping=column_mapping)dashboard.save('bike_sharing_demand_model_perfomance.html')
仪表板(来源:作者)
在上面的图片中,我们可以清楚地看到显示模型性能的报告,您可以下载我们使用上面的代码为本文创建的 HTML 报告。HTML 报告是可共享的,可以在不同的浏览器中打开。
继续尝试使用不同的数据集和机器学习模型仪表板。如果您发现任何困难,请在回复部分告诉我。
本文是与 Piyush Ingale 合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
分析音乐品味
使用 Spotify API 的音乐属性来评估我的音乐品味,并预测我是否会喜欢一首歌
阿列克谢·鲁班在 Unsplash 上的照片
我是一个音乐迷,大约 8 年来,我一直专门使用 Spotify 的平台来听音乐和播客,发现新音乐,并与朋友合作播放列表。Spotify 也有一个强大的 API,可以提供 Spotify 上 5000 多万首歌曲的大量信息,包括独特的音频属性——捕捉歌曲各种分类方式的数字特征。更多关于音频属性的信息可以在这里找到。
Spotify 使用这些音频功能以及一整套复杂的模型来识别您喜欢的新音乐的良好匹配(为什么您的 Discover Weekly 播放列表可以如此有效地向您显示您将重复播放一整周的下一首歌曲)。在这篇文章中,我分析了我的流媒体历史的特征,并使用机器学习方法来尝试和预测我是否会喜欢我输入到模型中的歌曲。
我从 Spotify 请求您的数据时收到的 zip 文件中获得了. JSON 格式的流媒体历史记录。如果您想为您的帐户获取相同的信息,请从桌面登录您的帐户,单击“隐私设置”,然后单击“下载您的数据”下的“请求”
我的流历史数据帧的前几行。图片作者。
使用 Spotify 的 API,我获得了数据帧中每首歌曲的音频属性。
在删除了一些不太有用的返回列后,我们剩下的是:
具有音频功能的数据帧。图片作者。
我听了多少音乐?
print(‘Streaming history shows a total of %s listened minutes’ % format((df[‘msPlayed’].sum()*.001)/60))>>> Streaming history shows a total of 30602.300566666665 listened minutes
根据这个列表,在 12/6/19 到 12/6/20 之间大约有 30.6k 分钟(这和我的“2020 Wrapped”总结告诉我的差不多)。
我很好奇每首歌的节奏(每分钟节拍数)有多准确。对于我列表中最慢的两首和最快的两首歌曲,我也用软件录制了 BPM。看起来 API 中的一些录制的节奏实际上是我对节奏分类的细分,因为四首歌中有三首是我录制的 BPM 的两倍:
探索性数据分析
在深入 EDA 之前,我生成了两个数据集,一个“好”和一个“坏”播放列表,用于训练一个模型来分类我喜欢和不喜欢的音乐。虽然使用具有 15,800 个数据点的流媒体历史数据集是理想的,但数据将是高度不对称的,因为我没有长度相等的播放列表来播放我不喜欢的歌曲。相反,我在我的账户上使用了不同的播放列表——202 首歌曲。我为我不喜欢的歌曲生成了一个相当于 200 首歌曲的播放列表。这不是一个有趣的任务,但浏览“热门电台歌曲”让它很快过去。感谢 Spotify!
深入研究 EDA,让我们首先绘制每个音频特性的频率分布。
虽然一些要素的分布显示出明显的重叠,但我们现在将保留它们,因为包含所有要素的数据集和维度很小。我对节奏的分布感到非常惊讶——我不期望看到明显的区别。跨 3 个数据集比较的每个特征的平均值绘制如下(在最小最大缩放速度和响度特征之后)。
图片作者。
在一些特征中,例如效价和可跳舞性,好/坏之间的平均值相当接近。对于某些功能,我的“好”播放列表准确地代表了流历史的样本,但对于其他功能,流历史更接近于“坏”所有歌曲在工具性、语言性和生动性方面的价值都相当低。
我将好的/坏的数据集连接起来,并添加了一个“目标”列,用于监督学习。最后一个要查看的 EDA 图是一个相关矩阵,用于查看每个特性之间的相关程度,以及这些特性与目标的相关程度。
响度和能量是正相关的,而能量和声音是负相关的。不幸的是,这些特性和识别好与坏的目标之间没有太多的关联,所以我怀疑用这些数据生成的模型有多大用处。
监督学习
我尝试了各种监督学习方法,利用网格搜索来优化每种方法的超参数。
对数据训练 K-最近邻模型。
对于 kNN,最佳超参数如下:
{'metric': 'manhattan', 'n_neighbors': 23, 'weights': 'distance'}
然后,我用调整后的超参数重新拟合分类器。
除了 kNN,我还测试了 SVM、逻辑回归和随机森林分类器。随机森林分类器似乎给出了所有分类器中最高的准确度。
图片作者。
然而,即使是最好的结果也只有大约 84%的准确率——不是很好。只有 400 首歌曲用于训练模型,一些特征的频率分布明显重叠,我怀疑我能达到的模型精度。没有额外的特征选择来改进模型,因为使用所有特征作为输入获得了最高的精度。
后续步骤
我需要更多的数据。所以我联系了一些朋友,其中一个同意把他的流媒体数据发给我。他的音乐品味足够多样,但与我的截然不同。完美!这个策略将试图训练一个模型来辨别我的音乐品味和我朋友的音乐品味之间的区别,而不是“好”和“坏”之间的区别。
我按照上面相同的步骤将 json 字典转换成包含音频特性的数据帧。Joe 在他的流历史中有更少的独特歌曲,所以我通过从我的流历史中随机抽样独特的条目来确保类分布对于目标变量是相等的。
然后,我重新拟合模型,将我的流历史与新的流历史数据集进行比较。
相关矩阵仍然不是最佳的。没有一个特征与用于比较两组流历史数据点的目标变量高度相关。图片作者。
尽管更新的相关性矩阵缺乏增加的相关性,但当输入 300%以上的数据时,每个模型的交叉验证分数表现得更好(与手动选择“不喜欢”的歌曲样本相比,通过使用我朋友乔的流媒体历史,样本的多样性更大)。
图片作者。
通过在 XGBoost 模型上调整超参数,我能够达到大约 90%的准确率。
为了进一步测试模型的性能,我从 Joe 和我在 Spotify 上的“每周发现”播放列表中抓取了歌曲,这是一个包含 30 首歌曲的播放列表,每周都会更新你没有听过的新歌,Spotify 根据他们的推荐算法认为你会喜欢这些新歌。使用此播放列表中的歌曲可以确保我们不会意外地让模型根据之前在流媒体历史中看到的数据进行预测。
结果…令人失望。
用于预测乔和我的流历史之间的分类的混淆矩阵结果。图片作者。
当将优化后的模型应用于这个新数据时,我无法实现高于 38-55%的分类准确率。从上面的图表来看,该模型有大量的误报,并且它过度分类了更可能是乔的播放列表的歌曲。
其他模型产生了相同的结果——从主数据集中保留的测试数据具有相当高的准确性,但在尝试对 discover weekly 歌曲进行分类时,类似的预测具有大约 50%的准确性。
我还尝试过采样我的数据来改变类别分布,以便为“我的音乐”类别保留更高百分比的歌曲我还尝试重新拟合 XGBoost 模型,添加 early_stopping_rounds 参数(在 20 轮后停止),以确保模型不会过度拟合训练数据。
在训练 XGBoost 模型时绘制对数损失和分类误差,以确定一个合适的训练时期,并在该时期尽早停止。我用了 20 的值。
虽然模型的表现不如我希望的那样好,但我也想检查特征的重要性——模型说什么特征对我的音乐品味最重要?
图片作者。
响度、速度、效价和能量似乎是预测的最重要特征,而乐器性是最不重要的。
包扎
我仍在熟悉机器学习实践,我可能错过了数据处理或特征工程步骤。然而,我对《发现周刊》预测准确性低的假设并不是建模问题的结果,而是方法和用于该方法的数据量的结果。我最终采用的方法是——尝试对属于某个人的播放列表的歌曲进行分类,这可能是一项具有挑战性的任务,尤其是考虑到我必须处理的数据点数量有限。
关于我将从我的朋友 Joe 那里接收到的数据,我曾错误地做出一个假设,即数据集将具有相似数量的歌曲,并且歌曲多样性的广度将大致相同。在我的流媒体历史中,我有 16260 首歌曲,其中 27%是独特的。Joe 的流媒体历史记录仅包含 2109 首歌曲(但独立实例的百分比非常相似,为 30%!).如果 Joe 的流媒体历史也有至少 4000 首独特的歌曲,那么该模型可能会表现得更好。
还要记住的是,流媒体历史记录包括没有从头到尾播放的歌曲,因此如果您正在播放喜爱的播放列表,并且在一两秒钟后跳过了一首歌曲,它仍然会显示在流媒体历史记录中。也许你不喜欢那首歌,所以模特的表现会受到影响。
作为快速检查,看看这个事实对唯一条目的百分比有多大影响,我在过滤了大于 30000 的“msPlayed”后再次计算了这个数字,假设如果你听一首歌至少 30 秒,你可能会听完整首歌。结果与我所期望的相反。我的流媒体历史记录中歌曲的变化从 27%下降到 20%。乔保持稳定,仅从 30%下降到 29%。我想我听的音乐种类没有我想象的那么多!
最终,如果我有办法为“坏”歌曲生成大量数据点,我会很乐意回到这个项目。我认为我的第一个想法是根据我喜欢或不喜欢的歌曲对模型进行分类,这可能是实现具有令人满意的性能的模型的更好方法,但是即使花费在管理 200 首糟糕歌曲的播放列表上的时间也是非常长的,更不用说数量级更大的播放列表了。从互联网上的其他地方获取这些数据也是不可能的,因为好的和坏的音乐对听众来说是主观的。Spotify 在一个大规模矩阵中拥有数亿个数据点,他们用这些数据点来推荐音乐。我敢肯定,当您有能力查看如此大规模的大数据时,本项目中使用的音频属性功能会提供更多见解。
感谢阅读!如果您对如何提高 discover weekly 数据的模型性能有什么见解,请随时联系我们。这个项目的代码可以在我的 github 这里找到。
另外,我发现了一篇文章,其中的分析与我执行的分析非常相似,这让我感觉比作者无法在原始数据集之外的数据上实现高性能模型要好一些。那篇文章可以在这里找到。
用机器学习分析学校用电
人工智能在学校项目中的发现
今年,我与温布尔登高中的一组教师合作,开发并推出了我们的 AI in Schools 计划的第一个迭代,通过分析真实数据,向高中生教授数据科学和机器学习技能。
https://nwheeler443.medium.com/the-ai-in-schools-program-896f7000f31f
我们关注了气候变化问题,并特别关注了学校的用电情况。女孩们使用三个数据源来调查学校的用电情况:
- 学校能源使用数据是作为能源火花计划的一部分收集的。
- 女孩们还对 Arduinos 进行了编程,以收集学校周围战略位置的光线、运动和温度数据。
- 我们从整个伦敦的家庭获取智能电表数据作为“大数据”集,以补充和比较我们的学校用电数据。
我们的发现
我们使用 Kaggle 分析数据,因此您可以自己用笔记本这里、这里和这里探索代码和数据。
1。学校的能源使用量很高,甚至在学校关闭时也是如此
学校的基准能耗约为 20 千瓦/小时,最高日能耗通常达到约 120 千瓦/小时。相比之下,伦敦典型家庭的最高能耗不到 5 千瓦/小时。因此,让学生有机会设计干预措施来减少学校的能耗,可能会比鼓励学生改变自己家中的能耗产生更大的影响。
我们还可以看到,在 2020 年,当学生呆在家里时,能源使用会明显下降。
三年来学校的能源使用情况
三个伦敦家庭的能源使用
2。能源使用显示出明显的时间趋势。
当我们绘制几个月来学校的能源使用情况时,我们可以看到能源使用的每日趋势,在上课时间达到峰值,在放学时间下降。我们还可以看到能源使用的每周趋势在周末下降,尤其是在周日。也有固定的假期,学生可以休息一下,一周的能量消耗会大幅下降。
3。脸书的 Prophet 时间序列建模工具捕捉到了其中的一些趋势
我们尝试了脸书的 Prophet 工具,该工具在用户很少输入的情况下对时间序列数据进行建模,这意味着初学者可以快速采用它,而无需学习时间序列建模的数学基础来建立模型。下面是真实的能源使用数据(蓝线)和来自训练模型的预测(红线)。
我们可以看到,该模型学习了每日振荡趋势,并学习了周末的能源使用下降。它没有意识到的是,周末的能源使用差异要小得多,所以它重复了同样的振荡趋势,但平均值更低。这导致周六夜间的能源使用预测为负值,而周末的能源使用预测过高。
该模型还没有学会的另一件事是如何预测学校假期。因此,该模型对节假日和学期时间的峰值能源使用进行平均,导致学期时间的能源使用预测不足,节假日的能源使用预测过高。
4。包含额外的元数据可改善预测
学生们使用 Arduinos 收集了整个学校的光线、温度和运动数据。每个组都有来自一个位置的一种数据类型。当这个数据被包含在模型中时,能源使用预测随着时间的推移会有所改善。
在两天的期限内,原始模型(左)和包含运动作为协变量的模型(右)的预测。
5.所有数据来源都有缺点
我们拥有的最大数据源是一个关于伦敦电力使用的公开数据集,但这个使用数据看起来与我们在学校看到的模式非常不同。学校用电高峰在工作日,而家庭用电高峰在上班前后。同样,家庭在周末用更多的电,学校在工作日用更多的电。
根据伦敦家庭数据训练的模型预测的能源使用(红色)与真实的学校能源使用(蓝色)
第二大数据源是学校的智能电表数据,这对预测未来的能源使用要有用得多。但是,学校放假和停课不会在可预测的时间间隔内发生,也不会以 Prophet 精心设计的方式进行建模,因此预测通常会连续几周出错。
根据学校能源使用数据训练的模型预测的能源使用(红色)与实际的学校能源使用(蓝色)
最小的数据集是 Arduinos 收集的数据。运动数据与电力使用特别相关,但我们只有几周的数据用于建模,其中一些时间是在期中休息期间,所以我们只能对未来几天进行预测(见发现 4)。
运动数据(蓝色)与程序持续期间的能耗(红色)的关系图
摘要
检查学校能源使用的真实数据提供了有用的见解,可以导致干预措施,以减少学校的能源消耗。例如,当学校不使用时,将整个学校的供暖设置为下降,可能会导致假期和未来封锁期间的消费下降。
这些数据还让学生们有机会培养自己的编程、数学、批判性思维和项目管理技能。学生们收集的数据部分涵盖了一个期中假期,这意味着峰值用电量低于平时。这让学生们有机会看到算法所犯的错误,并试图找出为什么某一周的用电量被大大高估了。
随着该项目在温布尔登高中的继续,我们计划从 Arduinos 中收集更多的数据,随着时间的推移,这将有望导致更好的模型。这是关于构建人工智能以做出有价值的预测的一个很好的教训——提前计划并尽早开始收集数据是值得的。但收集正确的数据也很重要,因为大量不相关或误导性的数据可能比少量相关数据更糟糕。
使用高级分析基准模型调查价格趋势
利用 ML 深入了解房地产价格趋势…看看我们是否能胜过线性回归模型。
作者照片
1.介绍
在我的上一篇文章“去年房地产价格如何变化”
中,我描述了处理非同质商品(如房地产)价格数据的主要挑战,通过我们的分析,样本构成各不相同。
我建议至少阅读前一篇文章的介绍,它将为你提供一些关于我们正在试图解决的问题的背景。
简单回顾一下,我们的目标是消除样本变化对分析时间段的影响,这样我们就可以自信地回答这个问题:不管样本变化如何,价格本身变化了多少。在使用两个更简单的解决方案完成这项任务后:商业智能分析和统计测试,我们可以继续利用高级分析并比较这些方法的结果。
这篇文章的代码可以在 GitHub 上获得(笔记本的第 6 部分& 7)。
2.高级分析方法
作者图片
这种方法依赖于利用机器学习来精确建模我们在某个时间点的价格环境——在我们的例子中,华沙房地产价格为 2020 年第二季度,然后将其作为基准,与模型未看到的时间段(在我们的例子中为 2020 年第四季度)的数据进行比较。为了更容易理解整个过程,我准备了一个简单的 5 步图如下。
价格基准管道
作者图片
- 我们从想要比较的时期创建一个基线数据集。我们将这些数据分为训练和测试数据,以确保我们不会过度拟合——这是我们在这种方法中需要避免的主要风险。
- 我们使用训练集来训练我们的模型,其目的是复制我们基线数据的定价环境。
- 我们使用我们的测试集来评估我们的模型是否可以作为基线数据的可靠定价基准。首先,我们需要避免过度拟合,并确保我们的模型没有高估或低估的趋势。
- 一旦我们对第 1-3 点感到满意,并可以假设我们可以可靠地模拟基线数据的价格,我们就可以将我们想要比较和估计的 2020 年第 4 季度到 2020 年第 2 季度房地产价格的数据输入到这个模型中。
- 最后一步是比较比较数据集中的实际价格——在我们的例子中,是 2020 年第四季度的价格与 2020 年第二季度同一房产的基准价格。如果我们努力地执行前面的步骤,从基准的平均变化将会给我们一个在两个被分析的时期之间的价格趋势的相当精确的视图。
3.可靠的基准模型清单
我们的方法在很大程度上依赖于这样的假设,即我们能够从基准期对定价环境进行建模,并将其转移到比较期。如果我们在第 1-3 阶段不小心,继续使用一个模型,这个模型不能完成这个任务,我们也不能完成这个基本假设,基准测试的结果可能会非常误导人。
此外,一旦我们过了阶段 3,我们就没有进一步的方法来验证我们的模型是否可靠。在继续基准测试流程之前,我们需要进行三项关键的健全性检查:
3.1 分析平均绝对百分比误差和平均百分比误差
首先,我们需要确保我们的模型能够很好地预测价格。我建议使用两个关键 KPI:
- 平均绝对百分比误差-告诉我们模型预测值与实际值的差距。在房地产的例子中,任何低于 10%的都很好,阈值取决于商品和价格的波动性。但是,如果您试图评估几个百分点的变化,并且您的平均模型误差为 20%+则您可能没有足够的特征来为价格建模。
- 平均百分比误差—告诉我们我们的模型是否有高估或低估的趋势。这个值应该尽可能接近 0%,这意味着平均价格预测与实际价格一致,这是基准中的一个理想特征。
测试集性能
在我们的模型中,我们的 mean_percentage_error 在 1%左右,这已经足够好了,因为我们没有明显的高估或低估倾向。平均绝对百分比误差为 9%,这也是可以接受的。
3.2 不惜一切代价避免过度配合
过度拟合总是不好的,但是如果我们想用我们的模型作为价格基准,过度拟合会产生更坏的影响。通过这种方法,我们不再专注于对单个样本的完美预测,而是依赖于获得正确的关键价格驱动因素。
当我为我的模型使用神经网络时,通过结合退出和批量标准化来避免过度拟合。我还在 160 个周期后停止了训练,尽管为了避免过度适应的风险,在以后的周期中可能会有所改善。
3.3 误差分布应接近平均值= 0 的正态分布
测试集上的误差分布
第 3.3 点。与前两个任务有很强的联系——如果你答对了,它应该被确认为一个均匀的误差分布。如果您的误差分布严重偏斜或不以 0 为中心,这意味着您的模型在整个数据范围内没有稳定的性能。
这可能与过度拟合训练集有关,这通常会导致 mean_percentage_error 远离 0。这是一个大问题,因为如果它甚至不能在基线数据集上获得正确的平均预测,就很难依赖这个基准作为可靠的定价表示。
如果分布不均匀,这意味着您可能会遗漏一些关键特征,推动具有特定特征的房地产价格,从而导致该数据子集的持续高估或低估。
4.结果分析
一旦我们确信我们的模型在基线 2020 年第二季度数据集上足够好,我们就可以用它来预测 2020 年第四季度的房地产价格与半年前相比会是什么样子。
2020 年第二季度-第四季度对比
我们可以看到,对于我们的基准测试集,我们模型的预测价格仅为 77 PLN/m2,比实际值低 0.46%,这是一个令人满意的性能,但在对我们的比较数据集进行基准测试时,我们还应该考虑这一轻微的低估。
我们 2020 年第四季度数据集的平均价格基准比 2020 年第二季度高出 161 波兰兹罗提/平方米,这表明我们样本的构成变为质量稍高的公寓——即使在 2020 年第二季度的基线期,它们的平均价格也将高于基线期的样本。
当我们将 2020 年第四季度每平方米的平均实际价格与基线期基准价格进行比较时,差异增加了近 3%。在减去 0.5 个百分点后,我们可以估算出最终价格上涨 2.5%或 255 波兰兹罗提/平方米。
如果我们回到上一篇文章,我们可以看到 a 用一种简单得多的基于统计的方法和线性模型得出了非常相似的结果(2.5%,270 PLN/m2)。那么我们在复杂的神经网络模型上的所有工作都是不必要的吗?
恰恰相反,用更简单的线性回归方法得到类似的结果,更容易验证和理解,而复杂的 ML 模型可以让我们对后者更有信心,并利用其灵活性来增加我们分析的深度。
5.利用 ML 模型的灵活性
线性回归模型可以很好地分析整个样本的主要趋势和价格驱动因素,但我不建议用它来准确预测单个结果。
另一方面,一旦我们完成了我们的基准模型清单,并对我们的基准预测有信心,我们就可以用它来评估价格在更细粒度数据上的表现。
2020 年 Q2 nad 第四季度的价格与基准分布
让我们从基准分布的变化分析开始,我们可以看到 2020Q4 的红色直方图在整个数值范围内稍微向右移动。这表明价格上涨是大多数价格的总体趋势。
映射价格变化
按位置汇总基准结果可用于绘制地理价格趋势图。在上面的地图上,我们可以看到华沙的大部分地区,尤其是中心地区是稳定的。另一方面,我们可以看到郊区和最大的公园和绿地附近的房价大幅上涨近 10%,这可能表明这一特征开始在买家决策中发挥重要作用。
其他使用案例
基于不限于时间段的各种特征,使用 ML 模型的基准的类似方法可以用于比较不同的数据集。
在修改我们用来划分基线和比较数据集的内容后,我们可以使用相同的原则来估计 A/B 测试对更广泛的客户群中的一个群体的治疗效果,或者比较最终报价和有效报价之间的价格。如果我们在训练模型时很勤奋,我们可以将可靠的结果与复杂模型的灵活性结合起来。
6.摘要
我希望这两篇关于分析非统一商品价格趋势的不同方法的文章表明,这一挑战比听起来要复杂得多。
我想总结一下关于方法选择的指导方针:
- 如果你正在对过去进行广泛的分析,商业智能方法可能是最有效的。这一步对于更复杂的方法也是一个很好的起点,并且最容易向更广泛的受众解释。
- 如果您希望对您的结果更有信心,并确保样本变化不会导致误导趋势,那么统计方法是对上一步的良好安全检查。
- 如果您想深入研究定价问题并成功完成前两种方法,您可能可以安全地使用本文中描述的最复杂的方法。
我建议不要从高级分析方法开始,而不使用更简单的方法进行至少一次简单的分析,原因有两个:
- 基于 ML 的方法是最难解释的,并且有许多可能导致误导结果的陷阱。如果您在前面的步骤中了解了数据和关键驱动因素,那么避免它们会容易得多
- ML 模型的灵活性是一把双刃剑,正如 R.Coase 所说*“如果你折磨数据足够长的时间,它会承认任何事情”*并且相信我 ML 模型可以是一台令人印象深刻的数据折磨机器。如果您想要用于分段的时间变量在线性模型中不重要,则应用更复杂的变量只会提供任何重要的结果…如果它们实际上是误导性的或由过度拟合引起的。
感谢您的宝贵时间!我希望所描述的方法能帮助你进行价格分析。
使用 Python 的 LUX 库分析生产数据
仅使用交互式可视化技术执行预测性维护任务
乔纳森·博尔巴在 Unsplash 上的照片
作为数据科学家,我们都知道我们将大部分时间花在探索性的数据分析、数据清理和预处理上。通常,开发机器学习、做所有的训练、验证和测试工作都是次要的。一些最大似然模型比其他模型表现得更好,你可以调整一些参数,最终得到更好或更差的结果。但是通常,你会很快找到一个能很好地处理数据的模型。
因此,问题是如何加快最初的探索性数据分析步骤。由于这一步涉及大量的交互式工作,一个可能的解决方案是使用所谓的无代码或低代码库。使用这些库可以让你快速检查你的数据集,大大减少甚至不需要编码。换句话说,您可以完全专注于分析数据集的创造性工作。
在 Python 内部,几个低代码/无代码库已经上市,而在本文中,我们将重点关注 Lux 。
Lux 宣传自己是一个 Python 库,可以在处理 Pandas 数据帧的同时实现可视化和数据分析过程的自动化。因此,Lux 会自动建议突出显示底层数据集中有趣的趋势和模式。
使用案例
网上已经有一些使用 Lux 进行数据分析的教程。尽管如此,大多数教程都是针对较小的数据集,重点是对 Lux 进行一般性介绍。因此,在本文中,我们将尝试对来自生产领域的大量数据进行深入分析。
该数据集已于 2020 年在 AI4I 会议上在本文中介绍,随后被上传到 UCI 机器学习知识库。它是免费的,可以通过这个链接下载。
总之,数据集描述了由 10 000 个数据点和 14 个特征组成的生产工厂的模拟。对于我们的任务,我们对以下各列感兴趣:
- 类型:此栏由字母 L、M 和 H 组成。L 代表低(所有产品的 50%),M 代表中(30%),H 代表高(20%)产品质量变体。
- 空气温度[K]:由随机游走产生,大约 300 开尔文
- 过程温度[K]:通过随机游走生成,并加上空气温度加 10 开尔文
- 转速[rpm]:使用 2860 W 的功率计算,并叠加正态分布噪声
- 扭矩[Nm]:40Nm 左右的正态分布值
- 工具磨损[分钟]:对于质量变量,H/M/L 5/3/2 分钟的工具磨损加到过程中使用的工具上。
- 机器故障:表明机器是否出现故障的标签。
数据集包含更多信息,例如给出机器故障原因的详细信息。但是因为我们不想搞清楚这一点,所以其他列将被忽略。总之,用例的目标可以总结如下
通过使用 Lux 库的交互式可视化,找出机器故障的一些可能原因
对其他图书馆的快速调查
正如介绍中提到的,Python 中有几个低代码/无代码库。以下是对其他一些例子的快速回顾:
- Bamboolib :是一个在熊猫数据框架上工作的 GUI,可以很容易地集成到 Jupyter 笔记本中。可视化和分析数据集是相当交互式的。不幸的是,它不是开源的,免费版只能让你使用有限的功能。
- 米托:给你的 Jupyter 笔记本添加某种 Excel 电子表格。您在电子表格中所做的更改会被翻译成 python 代码。这对于市民数据科学家来说尤其有趣,因为他们可以在熟悉的环境中进行数据分析
- PyCaret :这不是探索性的数据分析,而是提供了一个低代码的 ML 库。它特别适合数据科学新手,因为您可以用很少的代码行解决完整的 ML 任务
设置 Lux
让我们开始吧。首先,我们需要安装所需的库 Lux 和 Pandas。要安装这两个库,只需在命令提示符下使用 PyPI 和以下命令,并键入
pip install lux-api
pip install pandas
此外,要激活 LUX 作为 Jupyter 笔记本扩展,请在命令提示符下键入以下两个命令。注意,也许你需要重启 Jupyter 内核
jupyter nbextension install --py luxwidget
jupyter nbextension enable --py luxwidget
接下来,在 Jupyter 笔记本中导入这两个库,并从 UCI 存储库中加载原始数据集。加载完。csv 文件,你应该会看到一个按钮写着“切换熊猫/力士”。当然还有你的数据框的摘录。
作者图片
首先,我们删除完成任务不需要的列。此外,我们需要重命名剩余的列。如果列名中包含方括号,Lux 表示分布图有困难。因此,需要用圆括号替换它们。注意,本文是用 Lux 0 . 4 . 0 版编写的。也许这个问题在未来的版本中不会继续存在。
最后,用 Lux 检查结果(在 Jupyter 笔记本中,只需单击切换按钮)。情节应该是这样的:
作者图片
让我们看看选项卡后面有什么:
- 相关性:有 10 个散点图显示不同过程值的行为。空气温度和过程温度显示出或多或少的线性行为。最后一幅图显示了扭矩和合理速度之间的非线性行为。
- 分布:以直方图的形式显示每个过程变量的分布。
- 发生:Flux 自动将定量变量和分类变量彼此分开。在数据帧中有两个分类属性,即机器故障和类型。此外,我们移动条形图,您可以获得以下信息:9661 次生产正常运行,339 次出现机器故障
一大特点:意图属性
到目前为止,这并没有给人留下深刻的印象,但是这个库提供了一个很好的特性,叫做意图属性。可以选择一个(甚至几个)将在图中突出显示的列。
在我们的例子中,只需一行代码,就可以检查机器在不同质量类型下的表现。因此,只需输入
作者图片
那挺有意思的。尤其是第二个情节。在“H”高,“L”低和“M”中等质量的三种类型中,现在 Lux 还标记是否有机器故障。通过点击“过滤器”标签,甚至有一个更详细的看法。通过悬停在条形图上(要做到这一点,下载 jupyter 笔记本),Lux 只给我们记录的数量,但是计算故障率是相当直接的。结果是:
- 男:83/2914 = 0.028
- l:235/5765 = 0.04
- h:21/982 = 0.021
因此:低品质产品的机器故障率最高。最后,让我们看看是否有可能找出导致机器故障的原因。请记住,这是我们最初想要实现的实际目标。让我们将 intent 的属性设置为“机器故障”并检查结果。
作者图片
Lux 告诉我们,如果机器出现故障,过程变量的平均值会如何变化。
检查结果,两个变量突出,即“工具磨损”和“扭矩”。如果机器出现故障,这两个变量都有较高的值。
让我们进一步研究扭矩。因此,标记该地块,并点击右上角的放大镜。
作者图片
现在,我们得到了所有变量的散点图,如果有一个机器故障或没有额外的标记。滚动到“扭矩”而不是“转速”,可以让我们清楚地了解情况。如果机器在低扭矩和高转速下运行,或者在高扭矩和低转速下运行,则存在机器故障。
最后,选择这个散点图并点击放大镜。同样,结果也很有趣。作为附加信息,数据分为三种产品质量。通过比较这些图,我们看到,转速大于 2.500、扭矩大于 60 NM 的产品很少能生产出高质量的产品。因此,高质量的产品很少导致机器故障。
作者图片
结论
本文将介绍 Lux 库,并评估它是否可以分析生产数据。请记住,这篇文章只是触及了库提供的可能性的表面。
对我来说,有几件事很有趣:
- 令人印象深刻的是只需要几行代码。此外,理解它们并不复杂
- 令人印象深刻的是,几乎不需要统计知识。你需要对散点图和直方图有一个基本的了解,但仅此而已。
- 不需要 ML/AI 来寻找机器故障的原因之一。请记住,这是分析生产数据时的常见结果。用一些领域知识仔细查看生产数据通常足以获得对数据的新见解。
- 最后,最令人印象深刻的是浏览数据集是多么的快速和直观。通过不必编写代码,可以专注于主要任务,分析过程数据并获得新的见解。
如果你有兴趣,你可以通过点击这个链接下载 Jupyter 笔记本和使用过的数据集
用 Apache Spark 3.0 分析堆栈溢出数据集
在 Amazon EMR 上使用 Spark SQL 和 Jupyter 进行端到端数据分析
从 Pixabay 下载的图像
数据科学家和分析师经常选择 Python library Pandas 进行数据探索和转换,这是很常见的,因为它的 API 漂亮、丰富且用户友好。Pandas 库提供了 DataFrame 实现,当数据量适合单台机器的内存时,这真的非常方便。对于更大的数据集,这可能不再是最佳选择,而 Apache Spark 等分布式系统的强大功能变得非常有用。事实上,Apache Spark 成为了大数据环境中数据分析的标准。
在本文中,我们将看到一步一步地分析特定数据集的方法,即来自堆栈溢出数据库的转储。本文的目标并不是通过一些具体的结论进行详尽的分析,而是展示如何使用 Apache Spark 和 AWS 堆栈(EMR、S3、EC2)进行这样的分析。我们将在这里展示所有的步骤,从从堆栈交换存档下载数据,上传到 S3,数据的基本预处理,到使用 Spark 的最终分析,包括使用 Matplotlib 和 Pandas 绘制的一些漂亮的图表。
在这里,我们将看到使用 Spark 和 Python 生态系统对大数据集进行数据分析的一种非常常见的模式。该模式有三个步骤,第一,用 Spark 读取数据,第二,做一些减少数据大小的处理——这可能是一些过滤、聚合,甚至是数据的采样,最后将减少的数据集转换成 Pandas 数据框架,并在 Pandas 中继续分析,这允许您使用 Matplotlib 在幕后绘制图表。
我们将在本文中使用的所有代码也可以在我的 GitHub 库中找到,所以请随意查看。
本文假设读者对 AWS 有一些基本的了解,比如在那里有一个帐户,能够生成 EC2 密钥对,等等。**此外,让我在这里强调,这些服务,如 EC2、EMR 和 S3,需要信用卡信息,亚马逊将向您收取使用费用。**因此,请确保在完成后终止 EC2 实例和 EMR 集群,并在不再需要时从 S3 中删除数据(包括日志、笔记本和其他可能在此过程中创建的文件)。
EC2 和集群设置的步骤将通过 AWS 文档的相关链接进行简要描述,AWS 文档非常广泛,其他资源也可以在网上找到。让我们看看我们将执行的所有步骤:
- 从 Stack Exchange 归档文件下载数据转储(这是一个 7z 压缩的 XML 文件)
- 解压缩下载的文件
- 将文件上传到 S3(AWS 上的分布式对象存储)
- 将 XML 文件转换为 Apache Parquet 格式(再次在 S3 上保存 Parquet)
- 分析数据集
对于步骤 1–3,我们将使用一个带有更大磁盘的 EC2 实例。对于第 4 步和第 5 步,我们将使用 Spark 3.0 和 JupyterLab 在 AWS 上部署一个 EMR 集群。
我们将使用 Spark 执行的分析本身独立于运行 Spark 的云,因此,如果您不想使用 AWS,但您在其他地方运行 Spark,并且您可以将数据存储到您的存储系统,您仍然可以使用我们将在下面使用的查询。
数据集
栈溢出很受程序员欢迎,你可以在那里提问,也可以回答其他用户的问题。转储本身可以在栈交换档案中找到,并且可以在知识共享许可 cc-by-sa 4.0 下获得(更多信息参见细节)。
数据由更多的文件组成,分别是帖子、用户、评论、徽章、投票、标签、历史记录、和帖子链接。在本文中,我们将只使用压缩 XML 中有 16.9 GB 的 Posts 数据集(截止到 2021 年 12 月)。解压缩后,大小增加到 85.6 GB。要查看各个表及其列的含义,我建议查看 Stack Exchange 上的这篇帖子,这篇帖子很好地描述了这一点。我们将处理的帖子包含所有问题及其答案的列表,我们可以根据 _Post_type_id 来区分它们,其中值 1 代表问题,值 2 代表答案。
数据下载和解压缩
为了从 Stack Exchange 归档文件中下载数据,我们将使用 EC2 实例 t2.large 和 200 GB 的磁盘空间。为了做到这一点,你需要登录到 AWS 控制台,进入 EC2 实例,点击启动实例并选择操作系统,例如,Ubuntu Server 18.04 LTS。接下来,您需要指定实例类型,使用 t2.large 很好,但是其他选项可能也不错。然后单击配置实例详细信息,并在添加存储选项卡中添加一个磁盘卷。您需要指定磁盘的大小,我选择 200 GB,但是更小的磁盘应该也可以。只需记住,解压缩后数据集将有近 90 GB。我在这里添加了一些与描述的步骤相关的截图:
作者创造的形象。
作者创造的形象。
此外,AWS 会建议您设置一些安全组来限制可以使用该实例的 IP 地址,所以您可以随意这样做,并查看 AWS 文档。最后,要启动实例,您需要有一个 EC2 密钥对,如果您还没有,您可以继续并生成它。同样,要生成新的密钥对,请参见 AWS 文档。在实例运行之后,您可以从终端使用您的密钥(您需要在下载密钥的同一个文件夹中)对它进行 ssh:
ssh -i key.pem ubuntu@<the ip address of your instance>
然后,在控制台上安装 pip3 和 p7zip (第一个是 Python3 的包管理系统,我们将用它来安装 2 个 Python 包,第二个是用来解压 7z 文件的):
sudo apt update
sudo apt install python3-pip
sudo apt install p7zip-full
接下来安装 Python 包请求和 boto3 ,我们将使用它们进行数据下载和 S3 上传:
pip3 install boto3
pip3 install requests
然后使用 vi data_download.py 创建一个新文件,并在其中复制以下 Python 代码(在 vi 编辑器中,您需要通过按 i 键切换到插入模式):
url = 'https://archive.org/download/stackexchange/stackoverflow.com-Posts.7z'local_filename = 'posts.7z'
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
然后保存(按 esc 键并使用 :wq 命令)并使用python 3 data _ download . py运行。数据下载本身可能需要一段时间,因为如上所述,该文件有近 17 GB。接下来使用以下命令解压缩文件
7z x /home/ubuntu/posts.7z
之后,创建另一个 python 文件 *vi upload_to_s3.py,*并将数据上传到 s3 的代码复制到那里:
from boto3.session import *
import osaccess_key = '...'
secret_key = '...'
bucket = '...'
s3_output_prefix = '...'session = Session(
aws_access_key_id=access_key,
aws_secret_access_key=secret_key
)
s3s = session.resource('s3').Bucket(bucket)local_input_prefix = '/home/ubuntu'
file_name = 'Posts.xml'input_path = os.path.join(local_input_prefix, file_name)
output_path = os.path.join(s3_output_prefix, file_name)s3s.upload_file(input_path, output_path)
正如您在代码中看到的,您需要填写 S3 的凭证( access_key 和 secret_key )、您的 bucket 的名称和 s3_output_prefix ,这是文件上传的最终目的地。如果没有 access_key 和 secret_key ,可以生成(参见文档)。如果您没有存储桶,您可以创建它。
让我也提一下,还有其他方法如何访问堆栈溢出数据,即有一个公共的 API 允许您查询数据库,还有一个 Python 包装器构建在其上。
数据预处理
从存档中下载数据并存储在 S3 上后,我们现在将做一些基本的预处理,为分析查询准备数据。更具体地说,我们将把格式从 XML 转换为 Apache Parquet,并将列重命名/重新键入为更方便的格式。
正在启动 EMR 群集
对于这个预处理步骤,以及实际的数据分析,我们将使用 Spark 3.0 和 JupyterHub 启动一个 EMR 集群。要启动集群,请转到 EMR(在 AWS 服务中)并点击创建集群。之后,你就需要指定一堆设置了。转到高级选项,在那里您可以选择 EMR 版本并检查集群上将安装哪些应用程序。这里我们使用了 emr-6.1.0 ,我们将需要的关键组件是 Hadoop、Spark、JupyterHub 和 Livy(另见所附截图):
作者创造的形象。
在下一步中,您可以配置您的群集将有多少个节点,您可以使用默认设置,但是对于一些查询,您将不得不等待一段时间—它不会有超级响应。换句话说,拥有一个更大的集群会导致更快的查询,但是集群的成本也会更大。在下一步中,您可以为群集选择一个有意义的名称,并取消选中终止保护。最后,在点击创建集群之后,它会将您带到一个页面,您会看到您的集群正在启动。接下来,您可以点击笔记本并创建一个笔记本,您可以从中运行 Spark 查询。为笔记本选择一个名称,并选择该笔记本将连接到的已创建群集。几秒钟后,您可以点击打开 JupyterLab 按钮,打开 Jupyter:
作者创造的形象。
在 JupyterLab 中,你会看到你可以打开使用的笔记本。除此之外,您还可以使用菜单中的上传按钮来上传其他笔记本。
对于数据预处理和分析,您可以将我的存储库克隆到您的本地机器上,并上传这两个笔记本:
- stack overflow-Data-Analysis/Data-prepare/Data-prepare . ipynb
- stack overflow-Data-Analysis/Data-Analysis/Posts-General-Analysis . ipynb
在笔记本本身,确保你使用的是正确的内核,你可以在右上角看到(也可以看上面的截图)。出于我们的目的,我们将需要 PySpark 内核。
转换为拼花地板格式
让 EMR 集群运行 Spark 和 Jupyter,我们就可以开始处理数据了。我们要做的第一步是将格式从原始的 XML 转换成 Apache Parquet,这对于 Spark 中的分析查询来说要方便得多。为了读取 Spark SQL 中的 XML,我们将使用 spark-xml 包,它允许我们指定格式 xml 并将数据读入数据帧
作为这个 ETL 过程的一部分,我们还将所有列重命名为 snake-case 样式,并将 creation_date 列转换为 TimestampType 。将数据转换为拼花后,大小从 85.6 GB 减少到 30 GB,这是因为拼花压缩,也因为我们没有在最终的拼花中包括所有列。这里我们可以考虑的另一个步骤是按照创建年份甚至可能是从创建日期中导出的创建月份来划分数据。如果我们只想分析数据的某一部分,也许是最后一段时间等等,这将是很方便的。
数据分析
最后,我们将进入探索数据并可能揭示其一些有趣属性的部分。我们将回答关于数据集的 5 个分析问题:
1.计算计数
让我们计算以下有趣的计数:
- 我们有多少问题
- 有多少个答案
- 有多少问题已经接受了答案
- 有多少用户提问或回答了一个问题
在上面的代码中,我们首先读取了所有的帖子,但是只选择了在进一步的分析中需要的特定列,并且我们缓存了它们,这将非常方便,因为我们将在所有的查询中引用数据集。然后,我们根据 post_type_id 将帖子分成两个数据帧,因为值 1 代表问题,值 2 代表答案。帖子总数为 53 949 886,其中 21 641 802 是问题,32 199 928 是回答(数据集中还有其他类型的帖子)。当过滤 accepted_answer_id 不为空的问题时,我们得到了具有可接受答案的问题的数量,它是 11 138 924。对 user_id 列上的数据集进行重复数据删除,我们得到提问或回答问题的用户总数为 5 404 321。
2.计算响应时间
我们在这里将响应时间定义为从提出问题到得到被接受的答案所经过的时间。在下面的代码中,您可以看到我们需要将问题与答案连接起来,这样我们就可以将问题的创建日期与其被接受的答案的创建日期进行比较:
当根据响应时间对数据进行排序时,我们可以看到最快的可接受答案出现在一秒钟内,您可能会想,为什么有人能如此快速地回答一个问题。我明确地检查了其中的一些问题,发现这些问题是由发布问题的同一个用户回答的,所以显然他/她知道答案,并将其与问题一起发布。
作者创造的形象。
将响应时间从几秒钟转换为几个小时,并进行汇总,我们可以显示在问题发布后的每个小时内有多少问题得到了回答。
这里我们将时间限制为 24 小时,以查看问题发布后第一天内的行为。正如您在图表中看到的,大多数问题都在第一个小时内得到了回答:
作者创造的形象。
3.查看问题/答案的数量如何随着时间的推移而变化
观察每个时间单位的问题和答案的数量如何随着时间的推移而变化是非常有趣的。要使用 Spark 计算聚合,我们可以使用 window() 函数进行分组,它有两个参数,第一个是具有时间含义的列的名称,第二个是我们希望对时间维度进行分组的时间段。这里我们选择时间单位为一周。在聚合本身中,我们可以使用 when 条件计算答案和问题,如下所示:
按窗口分组创建了一个具有两个结构字段的结构类型*,*开始、和结束,因此在这里为了绘图,我们使用了开始字段,它是每周开始的日期。
作者创造的形象。
4.计算标签的数量
每个问题都有一些代表一些主题的标签—在堆栈溢出数据集中,这些通常是用户询问的一些技术。然而,标签是以字符串的形式存储的,格式为*<tag 1><tag 2><…>*,所以为了分析它们,将这个字符串转换成这些标签的数组并去掉尖括号是很有用的。为此,我们将首先使用 split 函数拆分字符串,之后,我们将使用高阶函数 TRANSFORM 使用regexp _ replace删除数组中每个元素的尖括号。为了计算所有标签的总非重复计数,我们将最终 展开 该数组并对其进行重复数据删除:
计数的结果显示 61 662 个不同的标签。要查看哪些标签被使用的次数最多,我们只需按标签对展开的数据集进行分组,计算每个标签的数量,并按计算出的频率进行排序。这就产生了这个列表,从这个列表中可以看出使用最多的标签是 javascript:
作者创造的形象。
5.查看一些特定标签的流行程度
将 tags 列转换为一个数组后,我们现在可以过滤这个数组并研究特定的标记。这里我们将看看人们用标签 apache-spark 或 apache-spark-sql 问了多少问题。为此,我们可以使用函数 array_contains ,该函数有两个参数,第一个参数是数组的列,第二个参数是一个特定的元素,我们希望确定它是否包含在数组中。该函数返回真或假,因此我们可以在过滤器内部直接使用它。像这样过滤问题后,我们可以根据创建日期按周对它们进行分组。最后,我们将其转换为熊猫数据帧并绘制成图:
最终的曲线图显示,在 Stack Overflow 上,人们在 2014 年开始对 Spark 感兴趣,每周被问及最多的问题是在 2017 年和 2018 年:
作者创造的形象。
结论
在本文中,我们看到了如何使用 Spark 来分析公开可用的数据集,但是,我们首先需要下载、解压缩并存储在某个分布式存储系统中,这样我们就可以使用 Spark 有效地访问它。
堆栈溢出数据集包含大量有趣的信息,我这样说不仅仅是指实际答案形式的内容,还包括问题、答案、评论和用户之间一些有趣的关系。在本文中,我们展示的只是冰山一角,我们已经看到了这个数据集上的一些基本查询,在未来的一些帖子中,我们将回到它并应用一些更高级的分析工具,如使用 Spark 的机器学习和图形处理来揭示数据的更多属性。
如何分析 NDVI 趋势
利用时间序列陆地卫星图像分析年最大 NDVI 趋势
由 Unsplash 上的hkon grim stad拍摄的照片
归一化差异植被指数(NDVI) 是一个简单的图形指示,可用于分析遥感数据,通常来自空间平台,以确定被观察的目标是否有活着的绿色植被。
归一化差异植被指数的卫星数据可用于量化生态系统生产力的变化模式(NDVI)。另一方面,利用 NDVI 时间序列对趋势的估计会因所研究的卫星数据集、相关的时空分辨率和所使用的统计方法而有很大差异。我们分析了各种趋势估计方法的有效性,并表明性能随着 NDVI 时间序列的年际变化的增加而降低。
ArcGIS
环境系统研究所维护着 ArcGIS,这是一个用于处理地图和地理信息的地理信息系统。它用于创建和利用地图、收集地理数据、分析地图信息、分发和查找地理信息、在各种应用程序中使用地图和地理信息,以及管理数据库中的地理数据。
ArcGIS 的产品/服务(作者创建)
在这个场景中,我使用了 Arcpy.ia 和 ArcGis API for Python。arcpy.ia 是一个用于管理和处理影像和栅格数据的 Python 模块。该模块还提供了 ArcGIS Image Analyst 扩展模块提供的所有地理处理方法,以及用于实现栅格处理工作流自动化的增强功能和类。
事不宜迟,让我们开始吧。我将在解释代码时描述这个过程。首先,我将所需的模块导入到我的工作流中。
import osimport matplotlib.pyplot as pltimport arcpyarcpy.CheckOutExtension("ImageAnalyst")
根据时间序列 Landsat 图像创建栅格集合
获取文件夹中所有陆地卫星场景的列表。
我建立了我的数据文件夹。我从美国地质调查局收集了这些数据,你可以在美国地质调查局注册获得类似的数据。我还创建了四个数组供将来使用。
美国地质调查局网站
folder = r"\\landsat\\LE70820552011359EDC00"raster_lists = []acquisition_time = []names = []quality_bands = []
在下面的代码中,我从源文件夹中检索所有 tif 文件,并将它们添加到栅格数据集中。我还包括每个数组的获取时间和文件名。但是,在添加文件名之前,我用. xml 对其进行了更改。
for directory in sorted(os.listdir(folder)):for file in os.listdir(folder+"\\"+directory):if file.endswith("xml") and len(file.split(".")) == 2:raster_lists.append(folder+"\\"+directory+"\\"+file)time = file.split("_")[3]acquisition_time.append(time[:4]+"-"+time[4:6]+"-"+time[6:])names.append(file.replace(".xml", ""))quality_bands.append(folder+"\\"+directory+"\\"+file.replace(".xml", "") + "_pixel_qa.tif")
创建栅格集合
为了生成栅格集合,我使用了 raster collection 方法。RasterCollection 对象可以轻松地对一组栅格进行排序和过滤,并为后续处理和分析准备集合。RasterCollection 对象有六种方法可用于为集合栅格中匹配波段上的每个像素生成统计数据(最大值、最小值、中值、平均值、多数和总和)。
rc = arcpy.ia.RasterCollection(raster_lists, {"Varieble": "Landsat7", names, "STDTime": acquisition_time, "Quantity": quality_bands})
过滤器
我们使用的数据集涵盖了 18 年的数据。所以我只用了 10 年的数据。我们可以通过使用 filterByCalanderRange 函数来实现这一点。
filtered_rc = rc.filterByCalenderRange(calender_field = "YEAR", start = 1997, end = 2007)
可视化栅格集合
不,我们可以查看栅格集合。
filtered_rc
结果如下。如我们所见,它显示变量、名称等等。
结果(作者创建)
项目中的可视光栅
下面的代码从集合的最终条目中检索栅格。我使用 arcpy.ia.Render 函数来呈现结果,并使用 exportImage 方法将其显示为图像。
要改进符号系统,请使用渲染功能来调整栅格对象的外观。当在 Jupyter 笔记本上工作时,数据显示是一个重要的优势,这个功能非常有用。该函数使用指定的渲染规则或颜色映射生成一个光栅对象。必须至少给出一个呈现规则或颜色映射。
first_item = filtered_rc[0]['Raster']rendered_raster = arcpy.ia.Render(first_item_raster, rendering_rule = {"bands": [3, 2, 1], "min": 500, "max": 1000, colormap='NDVI'})rendered_raster.exportImage(width = 500)
这是结果图。正如我们所看到的,这张图片有很多云。因此,我们必须清理这个形象。
结果图像(作者创建)
预处理
在预处理阶段,我将处理之前获得的图像,去除云、阴影、水和雪。
在下面的代码中,我首先检索栅格和每个栅格的质量。然后,我保存需要从栅格中移除的像素值。接下来,我使用 arcpy.ia.Apply 和 bandRaster 来应用于每个栅格。bandRaster 将屏蔽指定 RGB 波段中的像素。然后,我分配一个已清理的评定者,并将其分配给 return。
def clean(item):raster - item["Raster"]qa_raster = arcpy.Raster(item["Quantity"])values_tb = (qa_raster != 68) & (qa_raster != 72) & (qa_raster != 80) & (qa_raster != 96) & (qa_raster != 132) & (qa_raster != 136) & (qa_raster != 112) & (qa_raster != 144) & (qa_raster != 160) & (qa_raster != 176)masked_clean_band_list = []for bandRaster in raster.getRasterBands([1, 2, 3, 4, 5, 6]):masked_clean_band = arcpy.ia.Apply((values_tb, bandRaster, 0), "Local", args = {"Operation": "StdTime"})masked_clean_band_list.append(masked_clean_band)masked_clean_raster = arcpy.ia.CompositeBand(masked_clean_band_list)return {"raster": masked_clean_raster, "Name" : item["Name"], "StdTime" : item["StdTime"]}cleaned_rc = filtered_rc.map(clean)
设想
使用这段代码,我在集合的第二个项目中检索栅格。
first_item_raster = cleaned_rc[0]['Raster']rendered_raster = arcpy.ia.Render(first_item_raster, rendering_rule = {"bands": [3, 2, 1], "min": 500, "max": 1000, colormap='NDVI'})renderes_raster.exportImage(width = 500)
如下图所示,整个水域都被遮罩掉了。
结果图像(作者创建)
计算 NDVI
我定义了一种称为 clacNDVI 的方法来计算 NDVI,并使用 arcpy.ia.NDVI 从项目栅格和两个波段值创建 NDVI 栅格。最后,我返回项目、名称和标准时间等参数。
def clacNDVI(item):ndvi = arcpy.ia.NDVI(item['Raster'], nir_band_id = 4, red_band = 3)return {"raster": ndvi, "Name": item["Name"], "StdTime": item["StdTime"]}ndvi_rc = cleaned_rc.map(calcNDVI)
当我们调用这个函数时,我们得到了 NDVI 栅格。
设想
让我们用和我之前一样的方式来可视化栅格。
first_item_raster = ndvi_rc[0]['Raster']rendered_raster = arcpy.ia.Render(first_item_raster, rendering_rule = {"bands": [3, 2, 1], "min": 0, "max": 1.0, colormap='NDVI'})rendred_raster.exportImage(width = 500)
这与上一个栅格相同。然而,它现在显示 NDVI。
结果图像(作者创建)
每年获得最大 NDVI
我使用下面的代码转换了多维栅格集合。此方法返回一个多维栅格数据集,栅格集合中的每个项目代表多维栅格中的一个切片。
anual_max_ndvi_mdraster = arcpy.ia.Aggregate(ndvi_mdraster, demension_name = "StdTime", raster_function = "MaxIgnoreNoData", aggregate_definition = {"interval": "yearly"})
我使用 arcpy.ia.Aggregate 函数来确定每年的最大 NDVI。此方法基于提供的多维栅格生成栅格对象。默认情况下,将为与所选维度链接的所有变量计算聚合。在本例中,我使用 STDTime 作为维度时间,使用 MaxIgnoreNoData 作为栅格函数,其时间间隔为一年。
生成趋势
现在,我对年度最大多维栅格应用线性趋势。线性趋势线是估计基本线性关系的最佳拟合直线。线性趋势表示以一致的速度增加或减少的变化速度。
max_ndvi_linear_trend = arcpy.ia.Apply(Annual_max_ndvi_mdraster, "TrendAnalysis", raster_function_arguments = {"DimensionName": "StdTime", "RegressionType": 0})
设想
我们可以使用下面的代码检索趋势栅格的斜率。getRasterBands 为多波段栅格数据集中提供的每个波段返回一个栅格对象。在这种情况下,我使用 1 作为栅格波段。
slope - max_ndvi_linear_trend.getRaterBands(1)
再变换
为了修改负像素值,我使用了重映射函数。重映射功能允许您更改或重分类栅格数据像素值。这可以通过提供映射到输出像素值的像素值范围或者通过使用表格将像素值映射到输出像素值来实现。因此,输出将是一个布尔映射。
increase_decrease_trend_map = arcpy.ia.Remap(slope, input_ranges=[-10000, 0, 0, 10000], output_values=[-1, 1])
提供;给予
我用不同颜色的渲染函数进行渲染(绿色和灰色)。
rendered_raster = arcpy.ia.Render(increase_decrease_trend_map, colormap = {"values":[0, 1], "colors": ["#B0C4DE", "green", "gray"]})rendered_raster.exportImage(width = 500)
当我们看这张图片时,我们可以看到绿色区域的 NDVI 在增加。图像上的灰点代表 NDVI 减少的区域。
结果图像(作者创建)
让我们回顾一下
NDVI 是使用 GIS 工具对影像执行的逐像素数学计算。它是通过测量红光和近红外光的吸收和反射来确定的植物健康指标。NDVI 可用于研究世界各地的土地,使其既适用于重点实地研究,也适用于大陆或全球范围的植被监测。ArcGIS 是一个用于处理地图和地理信息的地理信息系统,由环境系统研究所维护。ArcGIS 可用于计算 NDVI。
参考