Python数据分析实战Tricks总结
matplotlib & seaborn 可视化
matplotlib 图内中文乱码显示:
- 在最开始处加上以下代码:
# plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
# plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
词云可视化
- 词云:只是简单根据词频进行可视化展示,没有去除停用词等
from wordcloud import WordCloud
# greatcloud = WordCloud(width=2400,height=1400,relative_scaling=.5).generate(str(sub_df['review_body']))
# plt.imshow(greatcloud,interpolation='bilinear')
# plt.axis('off')
# plt.show()
相关性图 / 变量分布图 / 箱线图
-
图像详细可参考:Python统计分析可视化库seaborn
-
多属性相关性:
- 协相关矩阵(各个相关系数,默认皮尔逊)
- sns.pariplot:分布图+相关点图 - 还可以根据不同索引画在一张图上
- sns.heatmap:相关性热力图(适合多变量相比,因为相关性最低的区域一定是黑色),协相关矩阵的可视化表达
- sns.clustermap:分层相关性热力图,了解不多
- sns.PairGrid:网格化相关性图,可以分别在上中下使用不同的图像类型
-
单个属性的分布:
- sns.distplot:分布图+参数拟合(kde=False,则不展现拟合线)
- sns.countplot:计数分布图(离散型数据)
- sns.rugplot:展示原始的数据离散分布(dist是域分布,这里是边缘分布,更加实际离散)
- sns.kdeplot:内核密度估计图,也显示了统计分布
-
两两属性的相关性图:
-
sns.joinplot:相关分布图(数值与数值型)
- kind:默认,点图
- kind:'hex',深度频次图
- kind:'reg',点图+简单回归线
- kind:‘kde’,核密度分布图
-
sns.boxplot:箱线图(hue也可以加上不同属性对应的箱线图)(以下都是数值与离散值型)
-
sns.voilinplot:小提琴图,结合了boxplot图和密度痕迹,也可以用hue表示不同属性对应图
-
sns.stripplot:离散散点图,hue属性
-
sns.swarmplot:与stripplot类似,但是他不会重叠数据点,stripplot会重叠一样的数据
-
sns.factorplot:类似与PairGrid,可以显示任何想要的图像类型
-
sns.pairplot(tips)
sns.pairplot(tips ,hue ='sex', markers=["o", "s"]) # markers颜色
sns.heatmap(tips.corr())
sns.clustermap(tips.corr())
g = sns.PairGrid(tips)
g.map_diag(sns.distplot)
g.map_upper(plt.scatter)
g.map_lower(sns.kdeplot)
sns.distplot(tips['total_bill'])
sns.distplot(tips['total_bill'],kde = False)
sns.countplot(x = 'smoker', data = tips)
sns.rugplot(tips['total_bill'])
sns.kdeplot(tips['total_bill'], shade=True)
sns.jointplot(x = 'total_bill', y = 'tip', data = tips)
sns.jointplot(x = 'total_bill', y = 'tip', data = tips ,kind = 'hex')
sns.jointplot(x = 'total_bill', y = 'tip', data = tips ,kind = 'reg')
sns.jointplot(x = 'total_bill', y = 'tip', data = tips ,kind = 'kde')
sns.boxplot(x = 'day', y= 'total_bill', data = tips)
sns.boxplot(x = 'day', y= 'total_bill', data = tips, hue = 'sex')
sns.violinplot(x = 'day', y= 'total_bill', data = tips)
sns.violinplot(x = 'day', y= 'total_bill', data = tips, hue = 'sex', split = True)
sns.stripplot(x = 'day', y = 'total_bill', data = tips)
sns.stripplot(x = 'day', y = 'total_bill', data = tips, jitter= True,hue = 'sex', dodge = True)
sns.swarmplot(x = 'day', y = 'total_bill', data = tips)
sns.factorplot(x = 'day', y = 'total_bill', kind = 'box', data = tips)
pandas & numpy 数据分析
数据集描述:
- 数据集统计描述:
df.describe()
- 数据集查看变量信息和缺失情况:
df.info()
- 更深度的数据集描述报告:
profile = df.profile_repor(title = "Dataset Report")
profile.to_file(output_file = Path("./dataset_report.html"))
数据集初步处理
- 去重复值:drop_duplicates()
df = df.drop_duplicates()
- 空值处理:
- pd.isna() / pd.isnull() / nnp.isnan() / Series=Series(前三nan为True,后者nan为False) - 返回布尔矩阵
- dropna() 删除NaN
- fillna() 设置NaN值
df.dropna() #NaN行
df.dropna(axis=1) #NaN列
dropna(how='all')
df.fillna(0)
df.fillna(method="bfill/ffill") # 向后填充/向前填充
df.fillna({"column1":1, "column2":0})
- 换值处理:replace
df['column'].replace({11:22}) #注意inplace
- 计数统计:
- count():按顺序统计
- value_counts():按排序统计
- cumsum():样本值累计和 - 应用:按时间轴变化图
df['column'].count()
df.count() ## axis=1按列,相当于统计非NaN值
df['column'].value_counts()
df['column'].cumsum()
- 区间映射:将xmin-xmax区间映射到a,b区间
Xmin = np.min(x_scale)
Xmax = np.max(x_scale)
#将数据映射到[2,8]区间 即a=2,b=8
a = 2
b = 8
y_scale = a + (b-a)/(Xmax-Xmin)*(x_scale-Xmin)
格式变换
- 读取数据集时,数值型变量一开始都是
str
,需要转换成float
:
df['column'] = df['column'].astype('float')
- str转datetime/timestamp:
df['time'] = pd.to_datetime(df['time'],format = ''%m/%d/%Y'') # str='02/12/2015'
- timestamp转datetime:因为timestamp不能进行计算,需要要转datetime
datetime.strptime(df.loc[:]['time'].strftime('%Y-%m-%d %H:%M:%S'),"%Y-%m-%d %H:%M:%S")
简单tricks
- for循环进度条:tqdm
- from tqdm import tqdm
from tqdm import tqdm
for i in tqdm(range(len(temp))):
pass
- 需要对每行进行遍历计算:
- 使用apply:时间比较长而且不知道进度
- 使用for:一般习惯使用,每行计算结果append入列表最后转为一列
res = []
for i in ..:
...
res.append()
df['new_column'] = pd.Series(res)
-
删除行删除列:
- df.drop([...], axis=0/1, inplace=True)
-
索引行索引列:
- df.loc[行][列]
- df[列][行]
-
深拷贝:df.copy(deep=True
-
找满足某个条件的行:
# 选出所有好评评论
querySer = df.loc[:,'star'] >= 4
df_good = df.loc[querySer,:]
- 统计不同的某列下的一些情况:groupby聚合
# 不同产品下各有多少条评论
# sub_df = pd.DataFrame(df_good.groupby(["product_id"],sort=True)["star"].size()).reset_index()
数据集初步分析 - 举例
- 题目:选出获得好评最多的淘宝产品
- 选出所有好评的评论
- 根据产品进行聚合
- 按好评数目降序排列
# 选出所有好评评论
querySer = df.loc[:,'star'] >= 4
df_good = df.loc[querySer,:]
# 根据产品进行聚合 - 聚合的size,就是以'product_id'索引下的条目数
# sub_df = pd.DataFrame(df_good.groupby(["product_id"],sort=True)["star"].size()).reset_index()
# 列重命名
# NameDict = {'product_id':'好评数'}
# sub_df.rename(columns = NameDict,inplace=True)
# 按好评数降序排列
# sub_df=sub_df.sort_values(by='好评数',ascending=False ,na_position='first')
# 取前5结果
sub.df.head(5)
- 题目:1-5星评论占比与分布
- 根据星级进行聚合
- 计算占比
- 分布图
#按星级进行聚合 - 因为是星级数量,所以也是size
# sub2_df = pd.DataFrame(df.groupby(["star"],sort=True)["product_id"].size()).reset_index()
#列重命名
# NameDict = {'product_id':'Review_Number'}
# sub2_df.rename(columns = NameDict,inplace=True)
# sub2_df
# a=sub2_df.loc[:,'Review_Number'].sum()
#定义新列
# aDf = pd.DataFrame()
# aDf['Percentage']=sub2_df['Review_Number']/a
# sub2_df = pd.concat([sub2_df,aDf],axis=1)
# sub2_df
# 画星级与评论数占比图
# sub2_df.plot(x='star',y=u'Percentage',kind='bar')
# plt.show()
- 题目:写出帮助票数最多的用户/评论
sub_df = df.sort_values(by='helpful_votes',ascending=False)
- 题目:各个产品评论数量与平均星级之间的关系
sub['num'] = pd.DataFrame(sub1.groupby(["product_id"],sort=True)["star"].size())
sub['mean'] = pd.DataFrame(sub1.groupby(["product_id"],sort=True)["star"].mean())
sub[['num','mean']].corr()
Scikit-learn 等算法模型包
LDA 文本主题模型
-
详细可参考:用scikit-learn学习LDA主题模型
-
LDA七个变种类型的文本聚类方法(仍然是Topic Model):【NLP】目前有比Topic Model更先进的聚类方式么?比如针对短文本的、加入情感分析的?
import nltk #nltk英文分词 / jieba中文分词
from tqdm import tqdm
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
#从文件导入停用词表
stpwrdpath = "stop_words_english.txt"
stpwrd_dic = open(stpwrdpath, 'rb')
stpwrd_content = stpwrd_dic.read()
#将停用词表转换为list
stpwrdlst = stpwrd_content.splitlines()
stpwrd_dic.close()
cntVector = CountVectorizer(stop_words=stpwrdlst)
# 整合所有评论分词
corpus = []
for i in tqdm(range(len(mc))):
text = nltk.word_tokenize(mc.loc[i]['review_body'])
corpus.append(' '.join(text))
# 获取词频向量
cntTf = cntVector.fit_transform(corpus)
# print(cntTf)
# 输出选取词特征
vocs = cntVector.get_feature_names()
# print('主题词袋:', len(vocs))
# print(vocs)
# 主题模型
lda = LatentDirichletAllocation(n_topics=6,
learning_method='online',
learning_offset=50.,
random_state=0)
docres = lda.fit_transform(cntTf)
# 类别所属概率
LDA_corpus = np.array(docres)
# print('类别所属概率:
', LDA_corpus)
# print(len(LDA_corpus))
# 每篇文章中对每个特征词的所属概率矩阵:list长度等于分类数量
# print('主题词所属矩阵:
', lda.components_)
# 构建一个零矩阵
LDA_corpus_one = np.zeros([LDA_corpus.shape[0]])
# 对比所属两个概率的大小,确定属于的类别:
LDA_corpus_one[LDA_corpus[:, 0] < LDA_corpus[:, 1]] = 1
# print('所属类别:', LDA_corpus_one)
# 打印每个单词的主题的权重值
tt_matrix = lda.components_
id = 0
for tt_m in tt_matrix:
tt_dict = [(name, tt) for name, tt in zip(vocs, tt_m)]
tt_dict = sorted(tt_dict, key=lambda x: x[1], reverse=True)
# 打印每个类别前5个主题词:
tt_dict = tt_dict[:5]
print('主题%d:' % (id), tt_dict)
id += 1
nlp 情感分析
- 详细参考:自然语言处理的情感分析之TextBlob& SnowNLP
- TextBlob包 - 英文情感分析(开源)
- 中间分词用的nltk
from textblob import TextBlob
text = "I am happy today. I feel sad today."
blob = TextBlob(text)
#分句
blob = blob.sentences
print(blob)
#第一句的情感分析
first = blob.sentences[0].sentiment
print(first)
#第二句的情感分析
second = blob.sentences[1].sentiment
print(second)
#总的
all= blob.sentiment
print(all)
- SnowNLP包 - 中文情感分析(开源)
- 针对中文,所有算法都是自己实现的,并且自带了一些训练好的字典
from snownlp import SnowNLP
s = SnowNLP(u'这个东西真心赞')
s1=SnowNLP(u'还是很 设施也不错但是 和以前 比急剧下滑了 和客房 的服务极差幸好我不是很在乎')
s.words # [u'这个', u'东西', u'真心',
# u'很', u'赞']
print(s.words)
s.tags # [(u'这个', u'r'), (u'东西', u'n'),
# (u'真心', u'd'), (u'很', u'd'),
# (u'赞', u'Vg')]
print(s.tags)
p =s.sentiments # 0.9769663402895832 positive的概率
print(p)
print(s1.sentiments)
PCA 降维
X = df.copy(deep=True)
pca = PCA(n_components=1) # 降维维度k
newX = pca.fit_transform(X)
# print(newX)
newX = pd.DataFrame(newX)