Udacity数据分析(进阶)-清洗与分析数据

Udacity数据分析(进阶)-清洗与分析数据

简介

数据集来自推特用户 @dog_rates 的档案, 推特昵称为 WeRateDogs。WeRateDogs 是一个推特主,他以诙谐幽默的方式对人们的宠物狗评分。这些评分通常以 10 作为分母。WeRateDogs 拥有四百多万关注者,曾受到国际媒体的报道。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests
import json
import os

收集数据

#导入Twitter档案
twitter_archive_enhanced=pd.read_csv('twitter-archive-enhanced.csv')
#导入图像预测数据
url='https://raw.githubusercontent.com/udacity/new-dand-advanced-china/master/%E6%95%B0%E6%8D%AE%E6%B8%85%E6%B4%97/WeRateDogs%E9%A1%B9%E7%9B%AE/image-predictions.tsv'
response=requests.get(url)
with open(os.path.join('image-predictions'),mode='wb') as file:
    file.write(response.content)
image_predictions=pd.read_csv('image-predictions',sep='\t')
image_predictions.to_csv('image_predictions.tsv', index=False)
#导入额外附加数据
tweet_list=[]
with open('tweet_json.txt','r') as f:
    for row in f:
        json_dict= json.loads(row)
        to_append= {
            'tweet_id':json_dict['id_str'],
            'retweet_count':json_dict['retweet_count'],
            'favorite_count':json_dict['favorite_count']
        }
        tweet_list.append(to_append)
df_json=pd.DataFrame(tweet_list, columns=['tweet_id','retweet_count','favorite_count'])
tweet = pd.DataFrame(tweet_list, columns = ['tweet_id','retweet_count','favorite_count'])

数据评估

#设置显示列数及列宽
pd.options.display.max_columns=1000
pd.set_option('max_colwidth',200)
twitter_archive_enhanced.sample(5)

在这里插入图片描述

tweet_id:档案中的推特 ID
in_reply_to_status_id:回复ID
in_reply_to_user_id:被回复推文原始用户ID
timestamp:发文时间
source:消息来源(使用设备)
text:推文内容
retweeted_status_id:转发ID
retweeted_status_user_id:转发用户ID
retweeted_status_timestamp:转发时间
expanded_urls:推文链接
rating_numerator:评分分子
rating_denominator:评分分母
name:宠物名
doggo:狗的成长阶段,分类变量
floofer:狗的成长阶段,分类变量
pupper:狗的成长阶段,分类变量
puppo:狗的成长阶段,分类变量
twitter_archive_enhanced.info()

在这里插入图片描述

twitter_archive_enhanced.rating_denominator.value_counts()

在这里插入图片描述

twitter_archive_enhanced.text[twitter_archive_enhanced.rating_denominator==110]

在这里插入图片描述
评分的分母并不全为10,看起来这里有错误

twitter_archive_enhanced.name.value_counts().head()

在这里插入图片描述

twitter_archive_enhanced.text[twitter_archive_enhanced.name=='a'].iloc[0]

在这里插入图片描述
狗狗的名字中出现了55次"a",从上面看,很显然"a"并不是一个狗的名字,应该是作者在提取数据时发生了错误

dog_stage=twitter_archive_enhanced[['doggo','pupper','puppo','floofer']]
dog_stage.replace('None',np.nan).notnull().sum(axis=1).value_counts()

在这里插入图片描述
狗狗的分类不光有大量缺失值,而且还有对应2种类型的情况

image_predictions.sample(5)

在这里插入图片描述

tweet_id:档案中的推特 ID
jpg_url:预测的图像资源链接
img_num:最可信的预测结果对应的图像编号
p1:算法对推特中图片的一号预测
p1_conf:算法的一号预测的可信度
p1_dog:一号预测该图片是否属于“狗”(有可能是其他物种,比如熊、马等)
p2:算法对推特中图片预测的第二种可能性
p2_conf:算法的二号预测的可信度
p2_dog:二号预测该图片是否属于“狗”
p3:算法对推特中图片预测的第三种可能性
p3_conf:算法的三号预测的可信度
p3_dog:三号预测该图片是否属于“狗”
image_predictions.info()

在这里插入图片描述

sum(image_predictions.jpg_url.duplicated())

在这里插入图片描述
image_predictions表中预测的图像资源链接有66条重复项,应该为转发的内容,需要删除

tweet.sample(5)

在这里插入图片描述
在这里插入图片描述

tweet.info()

在这里插入图片描述

all_columns = pd.Series(list(twitter_archive_enhanced) + list(image_predictions) + list(tweet))
all_columns[all_columns.duplicated()]

在这里插入图片描述
质量

twitter_archive_enhanced表

1.source列包含多余的html文本内容,需要删除
2.转发的推文需要删除
3.expanded_urls存在缺失值
4.评分分母不全为10,从text中重新提取
5.狗狗分类缺失值较多,还有对应两种类型的情况
6.name列提取错误,如a
7.tweet_id列格式不正确,应该为字符串,目前为int64
8.in_reply_to_status_id和in_reply_to_user_id缺失项较多,需要删除

image_predictions表

9.图片链接中含有66条重复值,应该为转发内容,需要删除
10.tweet_id列也存在相同问题,应该为字符串,目前为int64

tweet表

暂无

整洁度

1.twitter_archive_enhanced表中doggo、floofer、pupper、puppo属于类型变量,应该为1列
2.所有表格中观察对象相同,可以将三个数据片段进行合并

数据清理

#复制数据集
archive_enhanced_clean = twitter_archive_enhanced.copy()
image_predictions_clean = image_predictions.copy()
tweet_clean = tweet.copy()

1.source列包含多余的html文本内容,需要删除

#方法一
from bs4 import BeautifulSoup
#提取HTML中的source文本
df_list=[]
for i in archive_enhanced_clean.source:
    soup=BeautifulSoup(i,'lxml')
    sources=soup.find('a').string
    df_list.append(sources)
#存入dataframe
archive_enhanced_clean.source=df_list
#改进后方法二
archive_enhanced_clean.source = archive_enhanced_clean.source.str.extract('>(.+)<',expand = True)
#测试结果
archive_enhanced_clean.source.value_counts()

在这里插入图片描述
2~3.转发、无照片的推文需要删除

#删除转发行内容
archive_enhanced_clean=archive_enhanced_clean[archive_enhanced_clean.retweeted_status_id.isnull()]
#删除图片缺失行内容
archive_enhanced_clean=archive_enhanced_clean[archive_enhanced_clean.expanded_urls.notnull()] 
#确认删除完成
archive_enhanced_clean.info()

在这里插入图片描述

#删除转发相关信息列
archive_enhanced_clean.drop(archive_enhanced_clean[['retweeted_status_id','retweeted_status_user_id','retweeted_status_timestamp']],axis=1,inplace=True)
#确认删除结果
archive_enhanced_clean.info()

在这里插入图片描述
4.评分分母不全为10,从text中重新提取(此处有审阅老师的修改建议,放在本文最后)

import re
#查找所有分母为10的评分
df_rating=[]
pattern = re.compile(r'\d+\/10')
for text in archive_enhanced_clean.text:
    string=text
    rate=pattern.findall(string)
    df_rating.append(rate)
#加入数据集
archive_enhanced_clean['rating']=df_rating
#转化成str,同时存在两种类型分类用&连接
archive_enhanced_clean['rating']=archive_enhanced_clean['rating'].apply(lambda x:'&'.join(x) if len(x)>1 else ''.join(x))
#将缺失值替换为np.nan
archive_enhanced_clean['rating']=archive_enhanced_clean['rating'].replace('',np.nan)
#查看结果
archive_enhanced_clean['rating'].value_counts()

在这里插入图片描述

#查看评分分子超过2位或者包含多个评分的文本内容
archive_enhanced_clean.text[archive_enhanced_clean['rating'].str.len()>6]

在这里插入图片描述

sum(archive_enhanced_clean['rating'].str.len()>6)

在这里插入图片描述
部分评分内容有误,好在数量不多(也不少),手动修改一下。

index提取内容修改内容
76612/10&11/1012/10
13599/10&2/109/10
14594/10&13/104/10
15085/10&10/105/10
152510/10&6/1010/10
189710/10&4/1010/10
19708/10&11/108/10
201010/10&7/10&12/1010/10
206411/10&8/108/10
22168/10&1/108/10
226310/10&4/104/10
#针对要修改的部分新建dic
dic={766:'12/10',1359:'9/10',1459:'4/10',1508:'5/10',1525:'10/10',1897:'10/10',1970:'8/10',2010:'10/10',2064:'8/10',2216:'8/10',2263:'4/10'}
for (key,value) in dic.items():
    archive_enhanced_clean.loc[key,'rating']=value
#查看结果
sum(archive_enhanced_clean['rating'].str.len()>6)+11

在这里插入图片描述

#删除评分分子、分母列
archive_enhanced_clean.drop(archive_enhanced_clean[['rating_numerator','rating_denominator']],axis=1,inplace=True)

5.狗狗分类缺失值较多,还有对应两种类型的情况

archive_enhanced_clean['stage']=archive_enhanced_clean.text.str.lower().str.findall('(doggo|pupper|puppo|floof)')
archive_enhanced_clean['stage'] = archive_enhanced_clean['stage'].apply(lambda x: ','.join(set(x)))
#将缺失值替换为np.nan
archive_enhanced_clean['stage']=archive_enhanced_clean['stage'].replace('',np.nan)
#查看结果
archive_enhanced_clean['stage'].value_counts()

在这里插入图片描述

#删除多余分类列
archive_enhanced_clean.drop(archive_enhanced_clean[['doggo','puppo','pupper','floofer']],axis=1,inplace=True)

6.name列提取错误,如a

#从text提取宠物名信息
archive_enhanced_clean['name'] = archive_enhanced_clean.text.str.findall('(?:This is|named|Meet|Say hello to|name is|Here we have|Here is)\s([A-Z][^\s.,]*)')
#转化成str,同时存在两种名字用,连接
archive_enhanced_clean['name'] = archive_enhanced_clean['name'].apply(lambda x: ','.join(set(x)))
#将缺失值替换为np.nan
archive_enhanced_clean['name']=archive_enhanced_clean['name'].replace('',np.nan)
#检查结果
archive_enhanced_clean['name'].value_counts()

在这里插入图片描述
8.in_reply_to_status_id和in_reply_to_user_id需要删除

archive_enhanced_clean.drop(archive_enhanced_clean[['in_reply_to_status_id','in_reply_to_user_id']],axis=1,inplace=True)

9.图片链接中含有66条重复值,应该为转发内容,需要删除

#删除重复列
image_predictions_clean=image_predictions_clean[~image_predictions_clean.jpg_url.duplicated()]
#检查结果
sum(image_predictions_clean.jpg_url.duplicated())

在这里插入图片描述
7、10.修改tweet_id数据类型

image_predictions_clean['tweet_id']=image_predictions_clean['tweet_id'].astype('str')
archive_enhanced_clean['tweet_id']=archive_enhanced_clean['tweet_id'].astype('str')
type(image_predictions_clean['tweet_id'][0]),type(archive_enhanced_clean['tweet_id'][0])

在这里插入图片描述

整洁度

1.twitter_archive_enhanced表中doggo、floofer、pupper、puppo属于类型变量,应该为1列------已修改
2.所有表格中观察对象相同,可以将三个数据片段进行合并

#合并三个数据集
df_clean = archive_enhanced_clean.merge(image_predictions_clean,how='inner',on='tweet_id').merge(tweet_clean,how='left',on='tweet_id')
#查看数据集情况
df_clean.info()

在这里插入图片描述

df_clean.head(5)

在这里插入图片描述

保存数据集

df_clean.to_csv('twitter_archive_master.csv', index=False)

数据分析

df=pd.read_csv('twitter_archive_master.csv')

提取评分分子部分并删除缺少评分的行

df=df[df.rating.notnull()]
df['rating_numerator']=df['rating'].apply(lambda x:x.split('/')[0])
df['rating_numerator']=df['rating_numerator'].astype(int)

提出问题

1.最常使用的宠物名是什么?

2.狗狗评分是否与点赞数有关?

3.哪种品种的狗最受大家欢迎?

1.最常使用的宠物名是什么?

#提取宠物种类
pet_name=df.name.dropna()
names=[]
for idx in pet_name.index:
    name=pet_name.loc[idx]
    if name.find(',')>=0:
        names.append(name.split(',')[0])
        names.append(name.split(',')[1])
    else:
        names.append(name)
from wordcloud import WordCloud
from PIL import Image
from os import path
#添加狗狗图片背景
dog_mask = np.array(Image.open(path.join("dog.png")))
#绘制词云图
wc = WordCloud(background_color="white", max_words=2000, mask=dog_mask)
wc.generate(' '.join(pet_name))
plt.imshow(wc, interpolation='bilinear')
plt.axis("off")
plt.show()

在这里插入图片描述
Charlie、Oliver和Cooper出现的次数最多,这些都是人们常用的宠物名。

2.狗狗评分是否与点赞数有关?

df_favorite=df[['rating_numerator','favorite_count']]
#由于存在异常值,选择分子小于20的部分进行绘图
df_favorite=df_favorite[df_favorite.rating_numerator<20]
import seaborn as sns
sns.set_style("white")
%matplotlib inline
#绘制回归图
sns.set(style="darkgrid")
sns.lmplot(x='rating_numerator', y='favorite_count',data = df_favorite)
plt.show()

在这里插入图片描述
从回归图上我们可以看出,狗狗的评分和点赞数呈正相关关系。
说明人们对狗狗的喜爱程度与狗狗的评分是有正相关关系的,也可能由于评分对狗狗的受喜爱程度产生了影响。
3.哪种品种的狗最受大家欢迎?

df_varieties=df[['p1','p1_dog','p2','p2_dog','p3','p3_dog','favorite_count']]
#提取狗的品种清单
varieties=[]
for e in df_varieties.index:
    if df_varieties.p1_dog.loc[e]==True:
        varieties.append(df_varieties.p1.loc[e])
    elif df_varieties.p2_dog.loc[e]==True:
        varieties.append(df_varieties.p2.loc[e])
    elif df_varieties.p3_dog.loc[e]==True:
        varieties.append(df_varieties.p3.loc[e])
    else:
        varieties.append(np.nan)
df_varieties['variety']=varieties
#删除缺失值
df_varieties=df_varieties[df_varieties.variety.notnull()]
#统计各品种数量,并选择前10名
datas=df_varieties.groupby('variety')['favorite_count'].size().sort_values(ascending=False).head(10)
datas=datas.reset_index()
datas.rename(columns={'favorite_count':'count'},inplace=True)
#绘制条形图
sns.barplot(x=datas.variety,y=datas['count'],color='#9B30FF')
plt.title('Count of dogs varieties')
plt.xticks(rotation=90)
plt.show()

在这里插入图片描述

#汇总各品种狗的推文点赞数
favorite=df_varieties.groupby('variety')['favorite_count'].sum().sort_values(ascending=False).head(10)
favorite=favorite.reset_index()
favorite.rename(columns={'favorite_count':'total'},inplace=True)
#绘制条形图
sns.barplot(x=favorite.variety,y=favorite['total'],color='#9B30FF')
plt.title('Favorite count of dogs varieties')
plt.xticks(rotation=90)
plt.show()

在这里插入图片描述

对于狗狗品种,无论从出现频率和点赞总数来看,golden retriever都是最多,前四个品种中排名也很稳定。看来,golden retriever的狗狗最常见,也最受人们的赞赏。

结论

从分析结果我们可以看出,人们经常会给宠物起Charlie,Oliver等名字;WeRateDogs的评分在一定程度上也影响了人们对狗狗的喜爱程度,从点赞数和评分的相关性就可以看出。而对于狗狗的品种,也可以看出大家都喜欢性格温顺(golden retriever和labrador retriever)或者长相可爱(Pembroke和Chihuahua)的犬类。

反思

本次分析对异常值(评分)和缺失值进行了填充或删除,可能会对分析结论造成一定影响。有趣的是常见的宠物名一般都是男性的名字,由于数据不足,宠物的性别对评分和受喜爱程度是否有相关性也不得而知,其他因素(如狗狗的stage,转发数与点赞和评分之间的关系等等)也未做深入的分析,后续可以进行深入研究。

链接:https://pan.baidu.com/s/1Fbul-Hb_YKMIRZxtZ3XU6Q
提取码:17xf

关于评分的清洗,提供其他思路供参考

关于评分的清洗,确实存在一些评分不为10的情况,不过这些情况中,存在一种情况是,多个狗狗的总分,比如说9只狗狗被评分 99/90,规律是:分母是10的N倍,且分子可以被 N 整除,另外,评分中还存在个别分子是小数的情况,比如 11.26/10 被提取为 26/10 等,所以提取评分时,可以使用分子是小数、分母是非0的10的倍数的模式来匹配:

# 提取出的分子是带有小数点的,分母是10的倍数
rating = archive_enhanced_clean.text.str.extract('((?:\d+\.)?\d+)\/([1-9]+[0]+)', expand = True)
# 提取出来的结果是个 dataframe 数据集,有两列,分别命名为分子和分母
rating.columns = ['rating_numerator', 'rating_denominator']
# 用新提取的数据替换掉原有的数据,记得修改分子的类型
archive_enhanced_clean['rating_numerator'] = rating['rating_numerator'].astype(float)
archive_enhanced_clean['rating_denominator'] = rating['rating_denominator']

当然,这样重新提取后,还是可能存在一个推文中有多个评分的情况,针对有多个分数的情况,因为具体涉及到的问题不同,我们可以使用 findall 找出所有 text 中有多个分数的数据,然后将其 index 和 text 打印出来,查看具体是哪种情况,单独处理:

archive_enhanced_clean['rating'] = archive_enhanced_clean.text.str.findall('((?:\d+\.)?\d+\/[1-9]+[0]+)')
for index in archive_enhanced_clean.index:
  rating = archive_enhanced_clean.loc[index,'rating']
  if len(set(rating))>1: # 如果有大于一个不同的匹配值
      print(index)
      print(archive_enhanced_clean.loc[index,'text'])

如果在清理后,想要将一些多个狗狗总评分的数据,修改为分母为 10 的模式,可以直接使用向量运算:

archive_enhanced_clean['rating_numerator']  = archive_enhanced_clean['rating_numerator'] / archive_enhanced_clean['rating_denominator'] *10
archive_enhanced_clean['rating_denominator'] = 10

其他链接

Markdown 语法说明 (简体中文版)

写在最后

数据清洗真的需要花时间去做,多查资料,多尝试,坚持下去会有豁然开朗的感觉。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值