xiaoxiaozi

xiaoxiaozi 查看完整档案

成都编辑西南交通大学  |  软件工程 编辑实验楼  |  python 编辑编辑
编辑

Learn by doing @ shiyanlou.com

个人动态

xiaoxiaozi 发布了文章 · 2019-10-23

不用虚拟机直接在线用的 Linux,统统都在这里!

玩过 Linux 的同学,几乎都用过虚拟机!然而,你们肯定不晓得?不用装虚拟机,也有体验 Linux 的办法。下面一起来看看吧,到底如何不用虚拟机,照样能玩 Linux。

头图.png

其实方法很简单,你只需要拥有一台可以联网的电脑,直接访问以下网址。

1.JS/UIX - Terminal

直接进入,点击 open terminal。就可以开始把玩了!它提供非常简单的终端环境,并没有自带 gcc 等编译套件,适合用于练习基本命令和 shell 脚本。

2.cb.vu

使用的是 FreeBSD,整体也是非常流畅,不过同样不支持代码编译运行。

3.copy.sh

可以全屏体验,给你一种在真实Linux上玩耍的感觉。同时支持多个发行版本哦!

4.实验楼

选择 Linux 课程,点击进入课程并打开默认在线环境,就可以开始使用一个完整的在线 Linux 环境,几乎和本地安装的 Linux 系统没差!

而且还提供了教程文档的指引,真实 Linux 小白也能轻松玩转 Linux。

5.Bash Shell

专门用来练习 Shell 编程的好地方。

6.ShellCheck

如同它的名字,这是一个用来检查你的脚本是否存在问题的工具。

知乎专栏同步:https://zhuanlan.zhihu.com/p/88087469

查看原文

赞 0 收藏 0 评论 0

xiaoxiaozi 发布了文章 · 2019-10-16

精选 22 个 C++ 项目,推荐新人练手首选!

C/C++ 作为元老级的编程语言,任时光更迭依旧屹立不倒,哪怕如今炙手可热的AI,其底层也是用其编写。

那么作为新手该如何快速上手 C++ 呢?当然是敲代码啊!一切不写代码的学编程都是瞎搞。下面为大家精选了 22 个 C++ 项目,推荐新人练手首选!

1.C++ 实现基数树

使用 C++ 实现Radix树:一种基于二进制表示的键值的查找树,尤其适合处理非常长的、可变长度的键值,Patricia 的基本思想是构建一个二叉树。

2.C++ 实现并行计算的K-Means聚类算法

使用 C++ 实现一个完整的面向对象的可并行K-Means算法。

3.C++ 实现 STL 标准库和算法

实现 C++ STL 的容器和算法的实现。

4.C++ 实现内存泄露检查器

内存泄漏一直是 C++ 中比较令人头大的问题, 即便是很有经验的 C++ 程序员有时候也难免因为疏忽而写出导致内存泄漏的代码。本项目使用 C++ 实现一个内存泄漏检查器。
image

5.C++ 实现高性能内存池

获得内存池所分配的内存速度高于从堆中获得分配的内存的速度,一个长期稳定运行的服务在追求极致的过程中,实现内存池是必不可少的。和标准库中的默认分配器一样,内存池本质上也是分配器,本项目设计并使用 C++实现一个高性能内存池。
image

6.C++ 实现高性能 RTTI 库

RTTI 是运行时类型识别的英文缩写,C++ 本身提供了运行时类型检查的运算符 dynamic_cast 和 typeid,然而 dynamic_cast 的效率其实并不理想,需要牺牲一定性能。本项目将使用 C++ 手动实现一个高性能 RTTI 库。
image

7.C++ 实现智能指针

使用C++语言实现智能指针的过程,来了解C++基本程序设计的方法,包括类的定义与使用,运算符的重载,模板类的使用方法,以及引用计数技术。

8.C++ 实现即时通信软件

使用 C++ 实现一个具备服务端和客户端的即时通信聊天室,涉及网络编程,C++面向对象程序设计等知识。

image

9.C++实现课程管理系统

使用C++ 实现一个课程管理系统,在这个过程中会介绍 C++ 11 的很多特性,同时可以熟悉 Linux下 的 C++ 。

10.C++ 实现银行排队服务模拟

使用 C++对银行排队服务进行模拟,以事件驱动为核心思想,手动实现模板链式队列、随机数产生器等内容,进而学习概率编程等知识。作为可选进阶,这个模型同时还能稍加修改的应用到 CPU 资源争夺模型中。

11.C++操作 redis 实现异步订阅和发布

操作 redis 实现异步订阅和发布,其中将介绍 redis 基础知识,在linux中安装和使用 redis ,常用的 hiredis API,并实现一个例程。

12.C++ 使用 openGL 实现吃豆人游戏

通过 C++ 和 openGL 库来实现了一个吃豆人的小游戏。使用了标准模板库,既对自己之前知识的检阅也是对 C++ 编程能力的一种提升。
image

13.C++ 解决迷宫问题

通过 C++ 实现了一个迷宫游戏,游戏不仅涉及到简单的 C++ 游戏思想,还涉及到深度优先遍历算法。

image

14.C++ 基于 OpenCV 实现实时监控和运动检测记录

使用 C++ 和 OpenCV 提供的库函数,实现摄像头的实时监控功能,并通过监控画面的运动检测选择是否记录视频。监控人员可选择输出图像的模式以更容易的分辨监控中的异常情况。

15.C++ 实现简易 Docker 容器

C++ 与 Linux 的 Namespace 及 Control Group 技术相结合,实现一个简易 Docker 容器。

16.C++ 开发 Web 服务框架

将综合使用 C++11 及 Boost 中的 Asio 实现 HTTP 和 HTTPS 的服务器框架。

17.C++ 编写 json 生成器

用 C++ 编写一个 json 生成器,生成 json 数据,并学习编写测试用例。

18.C++ 利用 QT 实现 PDF 阅读器

利用 QT 开发环境来实现一个 PDF 阅读器。主要内容包含了 QT 的基本用法以及图形界面的设计,还有第三方库 poppler 的使用。

image

19.C++17 自制脚本语言

使用 C++ 语言自制一个脚本语言。麻雀虽小五脏俱全,它完整支持函数,条件/位/逻辑运算,原生字符串/数组类型等特性。主要将从理论出发,逐步构建词法分析器,语法分析器,AST,运行时,最终实现一个完整的脚本语言,并且使用该脚本语言解决一些实际问题。

20.C++ 实现太阳系行星系统

使用 C++实现 OpenGL GLUT 实现一个简单的太阳系行星系统,将涉及一些三维图形技术的数学基础、OpenGL 里的三维坐标系、OpenGL 里的光照模型、GLUT 的键盘事件处理。

21.C++11 从零实现 NoSQL 数据库

使用 C++11 实现了一个完全兼容 redis 的 kv 数据库项目——Qedis;该项目会使用到一些 C++11 核心特性和 STL 库,并利用已有的 tcp 网络库,逐步构建出一个完全兼容 Redis 的更高性能的内存数据库。

22.C++ 实现 XML 解析

通过 C++ 实现 XML 文档内容解析,充分利用了 C++ 功能特性和泛型编程思想。通过本课程可以规范自己的编程习惯并积累大型项目开发经验。

知乎专栏同步:https://zhuanlan.zhihu.com/p/86779615

查看原文

赞 7 收藏 6 评论 0

xiaoxiaozi 分享了头条 · 2019-10-14

自学与转行程序员,一定要学的计算机专业课。完成学习可具备普通计算机专业本科毕业水平。

赞 0 收藏 0 评论 0

xiaoxiaozi 分享了头条 · 2019-10-12

爬虫写的好,当真是买房买的早。技术买房我看行!

赞 1 收藏 0 评论 0

xiaoxiaozi 发布了文章 · 2019-10-10

大连地区酒店数据分析

本项目来自实验楼《楼+ 数据分析与挖掘实战》第6期学员 Miss_candy。《楼+数据分析与挖掘实战》是实验楼以满足数据分析或数据挖掘初级工程师职位需求而定制的课程内容。包含 35 个实验,20 个挑战,5 个综合项目,1 个大项目。6 周时间,让你入门数据分析与挖掘。

数据读取

数据是在2019-08-27日取得的,08-28~08-29号的酒店价格,酒店价格会随着旅游淡旺季有浮动变化,目前大连属于季节转换的交界处,价格水平趋于合理但仍比正常水平偏高。

import pandas as pd
import jieba
from tqdm import tqdm_notebook
from wordcloud import WordCloud
import numpy as np
from gensim.models import Word2Vec
import warnings

warnings.filterwarnings('ignore')
df = pd.read_csv('https://s3.huhuhang.com/temporary/b1vzDs.csv')
df.shape

输出:

(2475, 7)

数据清洗

#获取的数据会有重复的情况,首先根据酒店的名字将一项,将名称完全相同的项从数据表中删除
df = df.drop_duplicates(['HotelName'])
df.info()

输出:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 2219 entries, 0 to 2474
Data columns (total 7 columns):
Unnamed: 0            2219 non-null int64
index                 2219 non-null int64
HotelName             2219 non-null object
HotelLocation         2219 non-null object
HotelCommentValue     2219 non-null float64
HotelCommentAmount    2219 non-null int64
HotelPrice            2219 non-null float64
dtypes: float64(2), int64(3), object(2)
memory usage: 138.7+ KB

经过删除重复项后,获得的酒店信息包含2219条有效信息, 其中5列有效信息分别为:

  • “HotelName” 酒店名称
  • “HotelLocation” 酒店所在位置的区命
  • “HotelCommentValue” 酒店在评分
  • “HotelCommentAmount" 酒店已获得的评价条数
  • "HotelPrice" 酒店的最低价格

由于一部分酒店由于新开业(或其他途径原因),暂时没有评分数(没有评分数的酒店在数据获取的过程中赋值”0“),因此,我们将这部分数据单独取出来,作为new_hotel数据集,用于后续的一些分析和预测。

df_new_hotel = df[df["HotelCommentValue"]==0].drop(['Unnamed: 0'], axis=1).set_index(['index'])
df_new_hotel.head()

输出

image

对于已有评分的酒店,也从原始数据集中分离出来,用于分析和建模。

df_in_ana = df[df["HotelCommentValue"]!=0].drop(["Unnamed: 0", "index"], axis=1)
df_in_ana.shape

输出:

(1669, 5)

数据分析

import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
%matplotlib inline

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
sns.distplot(df_in_ana['HotelPrice'].values)

输出:

<matplotlib.axes._subplots.AxesSubplot at 0x7f7353b9c240>

image

通过对酒店价格的分布情况进行可视化,大概可知, 大部分的酒店价格集中在500元/晚以下,其中以200-300元/每晚的价格最为集中;500元/晚以上的酒店就不怎么多了。 因此,这里根据价格分布以及实际的物价水平,将酒店根据价格情况划分为以下几个等级:

  • ”廉价“型酒店,每晚价格低于100元
  • "经济“型酒店,每晚价格在100-300元
  • ”舒适“型酒店,每晚价格在300-500元
  • ”高端“型酒店,每晚价格在500-1000元
  • "奢华“型酒店,每晚价格在1000元以上
df_in_ana['HotelLabel'] = df_in_ana["HotelPrice"].apply(lambda x: '奢华' if x > 1000 else \
                                                        ('高端' if x > 500 else \
                                                        ('舒适' if x > 300 else \
                                                        ('经济' if x > 100 else '廉价'))))

划分之后,先来大概了解一下不同类型的酒店的数量占比情况:

hotel_label = df_in_ana.groupby('HotelLabel')['HotelName'].count()
plt.pie(hotel_label.values, labels=hotel_label.index, autopct='%.1f%%', explode=[0, 0.1, 0.1, 0.1, 0.1], shadow=True)

输出:

([<matplotlib.patches.Wedge at 0x7f735196bf28>,
  <matplotlib.patches.Wedge at 0x7f7351974978>,
  <matplotlib.patches.Wedge at 0x7f735197d358>,
  <matplotlib.patches.Wedge at 0x7f735197dcf8>,
  <matplotlib.patches.Wedge at 0x7f73519096d8>],
 [Text(1.0995615668223722, 0.0310541586125, '奢华'),
  Text(0.8817809341165916, 0.813917922292212, '廉价'),
  Text(-1.1653378183544278, -0.28633506441395257, '经济'),
  Text(0.9862461234793722, -0.6836070391108557, '舒适'),
  Text(1.1898928807304072, -0.15541857156431768, '高端')],
 [Text(0.5997608546303848, 0.016938631970454542, '0.9%'),
  Text(0.5143722115680117, 0.47478545467045696, '21.9%'),
  Text(-0.679780394040083, -0.16702878757480563, '62.0%'),
  Text(0.5753102386963004, -0.3987707728146658, '11.0%'),
  Text(0.6941041804260709, -0.09066083341251863, '4.1%')])

image

从饼图的结果可知,有超过50%的酒店是经济型的,21.9%的酒店则属于廉价型,高端和奢华型的比例相应较少,比较符合旅游城市的一般定位。

下面再来了解一下酒店的地理位置分布情况:

from pyecharts import Map
map_hotel = Map("大连酒店区域分布图", width=1000, height=600)

hotel_distribution = df_in_ana.groupby('HotelLocation')['HotelName'].count().sort_values(ascending=False)
hotel_distribution = hotel_distribution[:8]

h_values = list(hotel_distribution.values)
district = list(hotel_distribution.index)

map_hotel.add("", district, h_values, maptype='大连', is_visualmap=True,
                         visual_range=([min(h_values), max(h_values)]), 
                         visual_text_color="#fff", symbol_size=20, is_label_show=True)
map_hotel.render('dalian_hotel.html')

在这里,由于从网站获取位置信息时,部分酒店的位置信息本身填写并不规范,导致获取得到的信息呈现一定的差异化,由于这些差异化的信息并不方便进行统一的规划,并且其所占比例不大,因此在sort之后处于比较靠后的位置,我们只截取靠前的8个主要区域的信息,可以看到,对于目前已经收集到酒店,大部分的酒店位于沙河口区,金州区,与大连主要景点的分布直接相关,比如知名的星海广场,跨海大桥位于沙河口区,金石滩以及发现王国则位于金州区。(实际上,高新园区在map上并没有对应的内容,因为它不属于行政区域,而是作为甘井子区和沙河口区交接处的一个技术开发区,其占比对沙河口区和甘井子区都没有影响, 并不妨碍我们对数据进行分析)。

大连酒店区域分布图

image

大连是一个旅游城市,不同行政区(地理位置),酒店的定位和水平应该也是不相同的,因此,了解各种档次的酒店在不同区域的分布是一个很有意思的问题:

hotel_distribution = df_in_ana.groupby('HotelLocation')['HotelName'].count().sort_values(ascending=False)
hotel_distribution = hotel_distribution[:8]
hotel_label_distr = df_in_ana.groupby([ 'HotelLocation','HotelLabel'])['HotelName'].count().sort_values(ascending=False).reset_index()
in_use_district = list(hotel_distribution.index)
hotel_label_distr = hotel_label_distr[hotel_label_distr['HotelLocation'].isin(in_use_district)]

fig, axes = plt.subplots(1, 5, figsize=(17,8))
hotel_label_list = ['高端', '舒适', '经济', '奢华', '廉价']
for i in range(len(hotel_label_list)):
    current_df = hotel_label_distr[hotel_label_distr['HotelLabel']==hotel_label_list[i]]
    axes[i].set_title('{}型酒店的区域分布情况'.format(hotel_label_list[i]))
    axes[i].pie(current_df.HotelName, labels=current_df.HotelLocation, autopct='%.1f%%', shadow=True)

通过各种档次酒店在不同地区的分布情况可知,各类型酒店在沙河口区、金州区以及中山区都是优势分布的,比较有趣的是,奢华型酒店在旅顺口区是没有分布的,这种类型的酒店除了在沙河口区比较集中之外,还在中山区占有相当大的比例,这和历史地理原因有很大的关系,大连人常说,中山区是传说中的”富人区“,许多商务型出行的人会把住地选在中山区,也促进的这一地区在高端、奢华系酒店的投入增长。

除了对酒店价格(档次)的要求之外,我们在出行定酒店时也会考虑酒店的评价情况,评分越高,评价越多的,我们会更倾向于预订,因此,针对有评分的数据集,我们来看一看大连这些酒店的情况。

首先根据评分情况结合消费者对评分的一般认知,对于酒店进行一下标注:

  • 4.6分以上的为”超棒“
  • 4.0-4.6分的为”还不错“
  • 3.0-4.0分的为“一般般”
  • 3.0分以下的为“差评”
df_in_ana['HotelCommentLevel'] = df_in_ana["HotelCommentValue"].apply(lambda x: '超棒' if x > 4.6 \
                                                                      else ('还不错' if x > 4.0 \
                                                                      else ('一般般' if x > 3.0 else '差评' )))

根据评分等级和酒店档次聚类,我们对数据进行可视化。

hotel_label_level = df_in_ana.groupby(['HotelCommentLevel','HotelLabel'])['HotelName'].count().sort_values(ascending=False).reset_index()
fig, axes = plt.subplots(1, 5, figsize=(17,8))
for i in range(len(hotel_label_list)):
    current_df = hotel_label_level[hotel_label_level['HotelLabel'] == hotel_label_list[i]]
    axes[i].set_title('{}型酒店的评分情况'.format(hotel_label_list[i]))
    axes[i].pie(current_df.HotelName, labels=current_df.HotelCommentLevel, autopct='%.1f%%', shadow=True)

由各类型酒店的评价分布情况可知, 差评主要出现在廉价型酒店和经济型酒店,而其中以廉价型酒店为差评重灾区,对于每晚最低价格300以上的舒适型,高端型和奢华型酒店,基本没有差评的出现,也印证了“钱花在哪哪就好“的一般认知,其中以奢华型酒店的好评(”超棒“)比例最高。评价”超棒“的比例并没有随着酒店档次的升高而提高,对于高端型酒店,其”超棒“评价的比例相对价格更低的舒适型酒店反而有所下降,原因也许是人们对酒店价格所对应的服务期待值大于酒店实际能够提供的服务水平,一方面提醒消费者不要盲目认为贵就是好,一方面提醒酒店,有多少能耐就做多少能耐对应的事,价格虚高不可取。

酒店清单

根据目前的内容,我们可以制作一份”种草清单“和”防踩雷清单“:

”种草清单“主要收集各档次酒店中评价好,评价条数多(多人检验,符合要求),价格相应合理的酒店名单,供各种不同出行需求的朋友选择; ”防踩雷清单“则主要收集差评酒店,提醒大家不要勇于”试错“”碰运气“。

种草清单

# 廉价酒店
df_pos_cheap = df_in_ana[(df_in_ana['HotelLabel']=='廉价') \
                         & (df_in_ana['HotelCommentValue']> 4.6) \
                         & (df_in_ana['HotelCommentAmount']> 500)].sort_values(by=['HotelPrice'], ascending=False)
df_pos_cheap

输出:

image

# 经济型酒店
df_pos_economy = df_in_ana[(df_in_ana['HotelLabel']=='经济') \
                         & (df_in_ana['HotelCommentValue']> 4.6) \
                         & (df_in_ana['HotelCommentAmount']> 2000)].sort_values(by=['HotelPrice'])
df_pos_economy

输出:

image

# 舒适型酒店
df_pos_comfortable = df_in_ana[(df_in_ana['HotelLabel']=='舒适') \
                         & (df_in_ana['HotelCommentValue']> 4.6) \
                         & (df_in_ana['HotelCommentAmount']> 1000)].sort_values(by=['HotelPrice'])
df_pos_comfortable

输出:

image

# 高端酒店
df_pos_hs = df_in_ana[(df_in_ana['HotelLabel']=='高端') \
                         & (df_in_ana['HotelCommentValue']> 4.6) \
                         & (df_in_ana['HotelCommentAmount']> 1000)].sort_values(by=['HotelPrice'])
df_pos_hs

输出:

image

# 奢华酒店
df_pos_luxury = df_in_ana[(df_in_ana['HotelLabel']=='奢华') \
                         & (df_in_ana['HotelCommentValue']> 4.6) \
                         & (df_in_ana['HotelCommentAmount']> 500)].sort_values(by=['HotelPrice'])
df_pos_luxury

输出:

image

雷区清单

df_neg = df_in_ana[(df_in_ana['HotelCommentValue'] < 3.0) \
                         & (df_in_ana['HotelCommentAmount'] > 50)].sort_values(by=['HotelPrice'], ascending=False)
df_neg

输出:

image

酒店名字的科学

对于处于比较极端的酒店类型,比如很贵很贵的高端型酒店,一般是走商务典雅大气风格,名字听起来就会觉得很”贵“; 而便宜一些的,依靠价格走流量的,针对学生或经济基础比较差的人群,名字要么走小清新的路子,要么就简单粗暴,一听就是”划算“,我们通过词云来验证一下,这个理论对于大连地区的酒店是否符合。

wget -nc "http://labfile.oss.aliyuncs.com/courses/1176/fonts.zip"
unzip -o fonts.zip
from wordcloud import WordCloud

def get_word_map(hotel_name_list):
    word_dict ={}
    for hotel_name in tqdm_notebook(hotel_name_list):
        hotel_name = hotel_name.replace('(', '')
        hotel_name = hotel_name.replace(')', '')
        word_list = list(jieba.cut(hotel_name, cut_all=False))
        for word in word_list:
            if word == '大连' or len(word) < 2:
                continue
            if word not in word_dict:
                word_dict[word] = 0
            word_dict[word] += 1

    font_path = 'fonts/SourceHanSerifK-Light.otf'
    wc = WordCloud(font_path=font_path, background_color='white', max_words=1000, 
                            max_font_size=120, random_state=42, width=800, height=600, margin=2)
    wc.generate_from_frequencies(word_dict)

    return wc

为了保证绘制词云的数据量充足,这里不按照原来的酒店档次划分标准来选取数据,而是选择价格低于150的酒店和高于500的酒店,作为两个相对极端的类型,看看他们在起名上有没有什么典型的区别。

part1 = df_in_ana[df_in_ana['HotelPrice'] <= 150]['HotelName'].values
part2 = df_in_ana[df_in_ana['HotelPrice'] > 500]['HotelName'].values
fig, axes = plt.subplots(1, 2, figsize=(15, 8))
axes[0].set_title('价格较低酒店的名字词云')
axes[0].imshow(get_word_map(part1), interpolation='bilinear')
axes[1].set_title('价格较高酒店的名字词云')
axes[1].imshow(get_word_map(part2), interpolation='bilinear')

输出:

<matplotlib.image.AxesImage at 0x7f73515c1908>

image

从结果来看,两类酒店的店名词云还是有明显差异的。 价格低廉的酒店,名字中出现”客舍“, ”主题“,”青年“,”快捷酒店“,”旅馆“, ”旅店“等次的频率较高,符合我们对这类酒店的定位认知; 高端的酒店,名字中包含”星海“,”海景“,”温泉“,”广场“的频率较高,由于大连比较知名的地标是沙河口区的星海广场,附近的酒店(特别是高档酒店),非常喜欢在名字中体现”星海“这个词,除了突出地理位置之外,似乎也能通过这个词给酒店增加一些格调。另外,高端酒店似乎不太喜欢给自己起名字叫”xx宾馆“,更喜欢叫”酒店“或”酒店式公寓“。 比较疯狂的一点是,无论是便宜一些的酒店,还是贵一点的酒店,都很喜欢”公寓“这个词。这似乎也是目前酒店事业发展的一种趋势。

看名识酒店

名字作为人或事物的一种象征,由它引起的第一印象是非常重要的,我们刚刚分析了比较极端的酒店类型在名字上的特点,在一定程度上,可以根据名字在判断酒店是否处于一定的档次,”三岁看一生”,对于刚刚开始运行,没有评分的小白酒店,我们可以根据对其价格的预测结果判断一下酒店的定价方案是否符合其定位,之前我们分析了不同档次酒店的评价特点,结合这些已知结果,大概的了解一下这些小白酒店是否具有标价虚高,或者是否值得我们当一次小白鼠,走一条“发现之路”。 不过这里面另外涉及到一个问题,新开的酒店因为环境和时代原因,在起名字的策略上会和之前的酒店产生差异,这种差异在建模预测的过程中会产生比较显著的影响,因此,这里我们只是利用学习过的方法,做一个有趣的实验,结果不会准确,但过程是很有趣的:)

df_in_ana['HotelPrice'].median()

输出:

156.0

通过前面的词云分析和已有评价的酒店的价格中位数,我们将价格150设为划分阈值,价格低于150元/晚的酒店,标注为1,而高于这个价格的,标注为0,这样的划分方式,使得两部分的数据量基本均衡,也在一定程度上体现出酒店名称的差异。

df_in_ana['PriceLabel'] = df_in_ana['HotelPrice'].apply(lambda x:1 if x <= 150 else 0)
df_new_hotel['PriceLabel'] = df_new_hotel['HotelPrice'].apply(lambda x:1 if x <= 150 else 0)
# 设定分词方式
def word_cut(x):
    x = x.replace('(', '')  # 去掉名称中出现的()
    x = x.replace(')', '')
    return jieba.lcut(x)
#设置训练集和测试集
x_train = df_in_ana['HotelName'].apply(word_cut).values
y_train = df_in_ana['PriceLabel'].values
x_test = df_new_hotel['HotelName'].apply(word_cut).values
y_test = df_new_hotel['PriceLabel'].values

训练集包含1669条信息,标注为1的数据共790条, 测试集包含550条信息,标注为1的数据共195条。

# 通过Word2Vec方法建立词向量浅层神经网络模型,并对分词之后的酒店名称进行词向量的求和计算
from gensim.models import Word2Vec
import warnings

warnings.filterwarnings('ignore')
w2v_model = Word2Vec(size=200, min_count=10)
w2v_model.build_vocab(x_train)
w2v_model.train(x_train, total_examples=w2v_model.corpus_count, epochs=5)

def sum_vec(text):
    vec = np.zeros(200).reshape((1, 200))
    for word in text:
        try:
            vec += w2v_model[word].reshape((1, 200)) 
        except KeyError:
            continue
    return vec 

train_vec = np.concatenate([sum_vec(text) for text in tqdm_notebook(x_train)])
# 构建神经网络分类器模型,并使用training data对模型进行训练
from sklearn.externals import joblib
from sklearn.neural_network import MLPClassifier
from IPython import display 

model = MLPClassifier(hidden_layer_sizes=(100, 50, 20), learning_rate='adaptive')
model.fit(train_vec, y_train)

# 绘制损失变化曲线,监控损失函数的变化过程
display.clear_output(wait=True)
plt.plot(model.loss_curve_)

输出:

[<matplotlib.lines.Line2D at 0x7f73400b8198>]

image

ps:因为数据量少,且数据本身所包含的信息相对不足,在这里,训练的结果并不太好。

# 之后对测试集进行词向量求和
test_vec = np.concatenate([sum_vec(text) for text in tqdm_notebook(x_test)])
# 用训练好的模型进行预测, 将结果倒入测试用表中
y_pred = model.predict(test_vec)
df_new_hotel['PredLabel'] = pd.Series(y_pred)
# 建模预测的结果
from sklearn.metrics import accuracy_score

accuracy_score(y_pred, y_test)

输出:

0.6163636363636363

实际上,预测的准确率只有60%左右,是一个相当不理想的结果,我们将数据展开,主要的原因在哪里。

new_hotel_questionable = df_new_hotel[(df_new_hotel['PriceLabel'] ==0) & (df_new_hotel['PredLabel']==1)]
new_hotel_questionable = new_hotel_questionable.sort_values(by='HotelPrice', ascending=False)
new_hotel_questionable

输出:

image

分歧比较明显的结果显示,很多新开的酒店,特别是价格很高的,都是“别墅”类型的度假型酒店,这一类型在已经评价的数据集中体现并不明显,建模的分类器对其不敏感,错分的可能就会大大增加。

plt.figure(figsize=(15, 7))
plt.imshow(get_word_map(new_hotel_questionable['HotelName'].values), interpolation='bilinear')

输出:

<matplotlib.image.AxesImage at 0x7f7333b06d68>

image

绘制词云来看新开的酒店们,其在名称上与建模所用的数据集相比,增加了一些原来没有的词,比如“号店”,“分店”,“别墅”等,导致预测的准确率下降。

认识新酒店

除开对名字方面的认识,我们还可以了解一下新开的这些酒店在地理位置的分布和均价的变化上有什么体现。

new_hotel_distri = df_new_hotel.groupby('HotelLocation')['HotelName'].count().sort_values(ascending=False)[:7]
plt.pie(new_hotel_distri.values, labels=new_hotel_distri.index, autopct='%.1f%%', shadow=True)

输出;

([<matplotlib.patches.Wedge at 0x7f7333ae1240>,
  <matplotlib.patches.Wedge at 0x7f7333ae1c50>,
  <matplotlib.patches.Wedge at 0x7f7333ae9630>,
  <matplotlib.patches.Wedge at 0x7f7333ae9fd0>,
  <matplotlib.patches.Wedge at 0x7f7333af29b0>,
  <matplotlib.patches.Wedge at 0x7f7333afd390>,
  <matplotlib.patches.Wedge at 0x7f7333afdd30>],
 [Text(0.4952241217848982, 0.9822184427113841, '金州区'),
  Text(-1.0502523061308453, 0.32706282801144143, '甘井子区'),
  Text(-0.7189197652449374, -0.8325589295300148, '沙河口区'),
  Text(0.10878704263418966, -1.0946074087794706, '旅顺口区'),
  Text(0.6457239222346646, -0.8905282793117135, '中山区'),
  Text(0.9702662169179598, -0.5182503915171803, '西岗区'),
  Text(1.0890040760087287, -0.1551454879665377, '普兰店区')],
 [Text(0.2701222482463081, 0.5357555142062095, '35.1%'),
  Text(-0.5728648942531882, 0.17839790618805892, '20.1%'),
  Text(-0.39213805376996586, -0.4541230524709171, '16.8%'),
  Text(0.059338386891376174, -0.597058586606984, '9.0%'),
  Text(0.35221304849163515, -0.4857426978063891, '7.8%'),
  Text(0.5292361183188871, -0.2826820317366438, '6.6%'),
  Text(0.5940022232774883, -0.08462481161811146, '4.5%')])

image

由饼图可以发现,有超过30%的新酒店选择了金州区,沙河口区作为老牌的酒店扎堆地,只有16%的从业者将新店选择在这里。

df_new_hotel['HotelLabel'] = df_new_hotel["HotelPrice"].apply(lambda x: '奢华' if x > 1000 \
                                                              else ('高端' if x > 500 \
                                                              else ('舒适' if x > 300 \
                                                              else('经济' if x > 100 \
                                                              else '廉价')))) 
new_hotel_label = df_new_hotel.groupby('HotelLabel')['HotelName'].count()
plt.pie(new_hotel_label.values, labels=new_hotel_label.index, autopct='%.1f%%', explode=[0, 0.1, 0.1, 0.1, 0.1], shadow=True)

输出:

([<matplotlib.patches.Wedge at 0x7f7333abbdd8>,
  <matplotlib.patches.Wedge at 0x7f7333a44828>,
  <matplotlib.patches.Wedge at 0x7f7333a4d208>,
  <matplotlib.patches.Wedge at 0x7f7333a4dba8>,
  <matplotlib.patches.Wedge at 0x7f7333a59588>],
 [Text(1.0859612910752763, 0.17518011955161772, '奢华'),
  Text(0.6137971106588083, 1.0311416522218948, '廉价'),
  Text(-1.1999216970224413, 0.01370842860376746, '经济'),
  Text(0.46080283077562195, -1.1079985339111122, '舒适'),
  Text(1.1494416996723409, -0.3446502271207151, '高端')],
 [Text(0.5923425224046961, 0.09555279248270056, '5.1%'),
  Text(0.3580483145509714, 0.6014992971294385, '22.7%'),
  Text(-0.6999543232630907, 0.007996583352197684, '44.0%'),
  Text(0.26880165128577943, -0.6463324781148153, '18.9%'),
  Text(0.6705076581421987, -0.20104596582041712, '9.3%')])

image

除了适合大多数出行者会选择的经济实惠的低价酒店外,高端奢华型酒店的投入比例在新开酒店中也有明显的提高,结合前面对新开酒店的词云分析,越来越多的酒店从业者投入了高端酒店的建设,以别墅型度假酒店为主要体现,体现出人们对品质和更加舒适的出行体验的的追求。

价格上,也有一些比较有趣的结果:

df2 = df_new_hotel.groupby('HotelLabel')['HotelPrice'].mean().reset_index()
df1=df_in_ana.groupby('HotelLabel')['HotelPrice'].mean().reset_index()
price_change_percent = (df2['HotelPrice'] -  df1['HotelPrice'])/df1['HotelPrice'] * 100
plt.title('新开各档次酒店均价变化')
plt.bar(df1['HotelLabel'] ,price_change_percent, width = 0.35)
plt.ylim(-18, 18)
for x, y in enumerate(price_change_percent):
    if y < 0:
        plt.text(x, y, '{:.1f}%'.format(y), ha='center', fontsize=12, va='top')
    else:
        plt.text(x, y, '{:.1f}%'.format(y), ha='center', fontsize=12, va='bottom')

image

新开酒店相对于已有评价的老牌酒店来说,均价的变化表现在:

  1. 奢华和廉价型酒店的均价均有下降
  2. 中间型酒店,包括经济型, 舒适性和高端型酒店,均价有所上涨

两个极端等级的酒店均以“降低身价”的方式获得关注度来博取入住率,以获得长足的发展, 而中间型酒店,以改变经营理念,顺应时代潮流等方式获得涨价的资本,只是其最终的发展效果仍取决于旅客对其的认同。

总结

本次实验以大连地区的酒店作为分析数据,挖掘了包括价格情况、区域分布情况等信息,提供了已有评价的酒店的“种草清单”和“防踩雷清单”(妈妈再也不用担心有朋友来大连烦恼定酒店的问题啦!),进行酒店店名的词云分析,挖掘了店名和酒店档次的相关性,并建立分类模型,预测新开的、没有评价的酒店的店名是否与其定价标准相适宜,同时挖掘了新开酒店的区域分布和档次分布情况,对比了其与已有评价酒店的均价变化,侧面了解了一些大连旅游事业发展的情况的思路。由于数据量少,且酒店店名的命名方式与区域、时代环境等有较强的相关性,建模预测部分的效果并不好,但学习了这些内容,将其应用在不同的方面来加深对其的认识也是一件有趣的事情。

知乎专栏同步:https://zhuanlan.zhihu.com/p/85909205

查看原文

赞 0 收藏 0 评论 0

xiaoxiaozi 发布了文章 · 2019-10-09

8 个 Python 实用脚本,赶紧收藏备用!

脚本写的好,下班下得早!程序员的日常工作除了编写程序代码,还不可避免地需要处理相关的测试和验证工作。

例如,访问某个网站一直不通,需要确定此地址是否可访问,服务器返回什么,进而确定问题在于什么。完成这个任务,如果一味希望采用编译型语言来编写这样的代码,实践中的时间和精力是不够的,这个时候就需要发挥脚本的神奇作用!

好不夸张的说,能否写出高效实用的脚本代码,直接影响着一个程序员的幸福生活[下班时间]。下面整理 8 个实用的 Python 脚本,需要的时候改改直接用,建议收藏!

1.解决 linux 下 unzip 乱码的问题。

import os
import sys
import zipfile
import argparse

s = '\x1b[%d;%dm%s\x1b[0m'       

def unzip(path):

    file = zipfile.ZipFile(path,"r")
    if args.secret:
        file.setpassword(args.secret)

    for name in file.namelist():
        try:
            utf8name=name.decode('gbk')
            pathname = os.path.dirname(utf8name)
        except:
            utf8name=name
            pathname = os.path.dirname(utf8name)

        #print s % (1, 92, '  >> extracting:'), utf8name
        #pathname = os.path.dirname(utf8name)
        if not os.path.exists(pathname) and pathname != "":
            os.makedirs(pathname)
        data = file.read(name)
        if not os.path.exists(utf8name):
            try:
                fo = open(utf8name, "w")
                fo.write(data)
                fo.close
            except:
                pass
    file.close()

def main(argv):
    ######################################################
    # for argparse
    p = argparse.ArgumentParser(description='解决unzip乱码')
    p.add_argument('xxx', type=str, nargs='*', \
        help='命令对象.')
    p.add_argument('-s', '--secret', action='store', \
        default=None, help='密码')
    global args
    args = p.parse_args(argv[1:])
    xxx = args.xxx

    for path in xxx:
        if path.endswith('.zip'):
            if os.path.exists(path):
                print s % (1, 97, '  ++ unzip:'), path
                unzip(path)
            else:
                print s % (1, 91, '  !! file doesn\'t exist.'), path
        else:
            print s % (1, 91, '  !! file isn\'t a zip file.'), path

if __name__ == '__main__':
    argv = sys.argv
    main(argv)

2.统计当前根目录代码行数。

# coding=utf-8
import os
import time
# 设定根目录
basedir = './'
filelists = []
# 指定想要统计的文件类型
whitelist = ['cpp', 'h']
#遍历文件, 递归遍历文件夹中的所有
def getFile(basedir):
    global filelists
    for parent,dirnames,filenames in os.walk(basedir):
        for filename in filenames:
            ext = filename.split('.')[-1]
            #只统计指定的文件类型,略过一些log和cache文件
            if ext in whitelist:
                filelists.append(os.path.join(parent,filename))
#统计一个的行数
def countLine(fname):
    count = 0
    # 把文件做二进制看待,read.
    for file_line in open(fname, 'rb').readlines():
        if file_line != '' and file_line != '\n': #过滤掉空行
            count += 1
    print (fname + '----' , count)
    return count
if __name__ == '__main__' :
    startTime = time.clock()
    getFile(basedir)
    totalline = 0
    for filelist in filelists:
        totalline = totalline + countLine(filelist)
    print ('total lines:',totalline)
    print ('Done! Cost Time: %0.2f second' % (time.clock() - startTime))

3.扫描当前目录和所有子目录并显示大小。

import os
import sys      
try:
    directory = sys.argv[1]   
except IndexError:
    sys.exit("Must provide an argument.")

dir_size = 0   
fsizedicr = {'Bytes': 1,
             'Kilobytes': float(1) / 1024,
             'Megabytes': float(1) / (1024 * 1024),
             'Gigabytes': float(1) / (1024 * 1024 * 1024)}
for (path, dirs, files) in os.walk(directory):      
    for file in files:                              
        filename = os.path.join(path, file)
        dir_size += os.path.getsize(filename)       

fsizeList = [str(round(fsizedicr[key] * dir_size, 2)) + " " + key for key in fsizedicr] 

if dir_size == 0: print ("File Empty") 
else:
  for units in sorted(fsizeList)[::-1]: 
      print ("Folder Size: " + units)

4.将源目录240天以上的所有文件移动到目标目录。

import shutil
import sys
import time
import os
import argparse

usage = 'python move_files_over_x_days.py -src [SRC] -dst [DST] -days [DAYS]'
description = 'Move files from src to dst if they are older than a certain number of days.  Default is 240 days'

args_parser = argparse.ArgumentParser(usage=usage, description=description)
args_parser.add_argument('-src', '--src', type=str, nargs='?', default='.', help='(OPTIONAL) Directory where files will be moved from. Defaults to current directory')
args_parser.add_argument('-dst', '--dst', type=str, nargs='?', required=True, help='(REQUIRED) Directory where files will be moved to.')
args_parser.add_argument('-days', '--days', type=int, nargs='?', default=240, help='(OPTIONAL) Days value specifies the minimum age of files to be moved. Default is 240.')
args = args_parser.parse_args()

if args.days < 0:
    args.days = 0

src = args.src  # 设置源目录
dst = args.dst  # 设置目标目录
days = args.days # 设置天数
now = time.time()  # 获得当前时间

if not os.path.exists(dst):
    os.mkdir(dst)

for f in os.listdir(src):  # 遍历源目录所有文件
    if os.stat(f).st_mtime < now - days * 86400:  # 判断是否超过240天
        if os.path.isfile(f):  # 检查是否是文件
            shutil.move(f, dst)  # 移动文件

5.扫描脚本目录,并给出不同类型脚本的计数。

import os                                                                    
import shutil                                                                
from time import strftime                                                

logsdir="c:\logs\puttylogs"                                            
zipdir="c:\logs\puttylogs\zipped_logs"                            
zip_program="zip.exe"                                                

for files in os.listdir(logsdir):                                        
    if files.endswith(".log"):                                        
        files1=files+"."+strftime("%Y-%m-%d")+".zip"        
        os.chdir(logsdir)                                                 
        os.system(zip_program + " " +  files1 +" "+ files)    
        shutil.move(files1, zipdir)                                     
        os.remove(files)                                                    

6.下载Leetcode的算法题。

import sys
import re
import os
import argparse
import requests
from lxml import html as lxml_html

try:
    import html
except ImportError:
    import HTMLParser
    html = HTMLParser.HTMLParser()

try:
    import cPickle as pk
except ImportError:
    import pickle as pk

class LeetcodeProblems(object):
    def get_problems_info(self):
        leetcode_url = 'https://leetcode.com/problemset/algorithms'
        res = requests.get(leetcode_url)
        if not res.ok:
            print('request error')
            sys.exit()
        cm = res.text
        cmt = cm.split('tbody>')[-2]
        indexs = re.findall(r'<td>(\d+)</td>', cmt)
        problem_urls = ['https://leetcode.com' + url \
                        for url in re.findall(
                            r'<a href="(/problems/.+?)"', cmt)]
        levels = re.findall(r"<td value='\d*'>(.+?)</td>", cmt)
        tinfos = zip(indexs, levels, problem_urls)
        assert (len(indexs) == len(problem_urls) == len(levels))
        infos = []
        for info in tinfos:
            res = requests.get(info[-1])
            if not res.ok:
                print('request error')
                sys.exit()
            tree = lxml_html.fromstring(res.text)
            title = tree.xpath('//meta[@property="og:title"]/@content')[0]
            description = tree.xpath('//meta[@property="description"]/@content')
            if not description:
                description = tree.xpath('//meta[@property="og:description"]/@content')[0]
            else:
                description = description[0]
            description = html.unescape(description.strip())
            tags = tree.xpath('//div[@id="tags"]/following::a[@class="btn btn-xs btn-primary"]/text()')
            infos.append(
                {
                    'title': title,
                    'level': info[1],
                    'index': int(info[0]),
                    'description': description,
                    'tags': tags
                }
            )

        with open('leecode_problems.pk', 'wb') as g:
            pk.dump(infos, g)
        return infos

    def to_text(self, pm_infos):
        if self.args.index:
            key = 'index'
        elif self.args.title:
            key = 'title'
        elif self.args.tag:
            key = 'tags'
        elif self.args.level:
            key = 'level'
        else:
            key = 'index'

        infos = sorted(pm_infos, key=lambda i: i[key])

        text_template = '## {index} - {title}\n' \
            '~{level}~  {tags}\n' \
            '{description}\n' + '\n' * self.args.line
        text = ''
        for info in infos:
            if self.args.rm_blank:
                info['description'] = re.sub(r'[\n\r]+', r'\n', info['description'])
            text += text_template.format(**info)

        with open('leecode problems.txt', 'w') as g:
            g.write(text)

    def run(self):
        if os.path.exists('leecode_problems.pk') and not self.args.redownload:
            with open('leecode_problems.pk', 'rb') as f:
                pm_infos = pk.load(f)
        else:
            pm_infos = self.get_problems_info()

        print('find %s problems.' % len(pm_infos))
        self.to_text(pm_infos)

def handle_args(argv):
    p = argparse.ArgumentParser(description='extract all leecode problems to location')
    p.add_argument('--index', action='store_true', help='sort by index')
    p.add_argument('--level', action='store_true', help='sort by level')
    p.add_argument('--tag', action='store_true', help='sort by tag')
    p.add_argument('--title', action='store_true', help='sort by title')
    p.add_argument('--rm_blank', action='store_true', help='remove blank')
    p.add_argument('--line', action='store', type=int, default=10, help='blank of two problems')
    p.add_argument('-r', '--redownload', action='store_true', help='redownload data')
    args = p.parse_args(argv[1:])
    return args

def main(argv):
    args = handle_args(argv)
    x = LeetcodeProblems()
    x.args = args
    x.run()

if __name__ == '__main__':
    argv = sys.argv
    main(argv)

7.将 Markdown 转换为 HTML。

import sys
import os

from bs4 import BeautifulSoup
import markdown

class MarkdownToHtml:

    headTag = '<head><meta charset="utf-8" /></head>'

    def __init__(self,cssFilePath = None):
        if cssFilePath != None:
            self.genStyle(cssFilePath)

    def genStyle(self,cssFilePath):
        with open(cssFilePath,'r') as f:
            cssString = f.read()
        self.headTag = self.headTag[:-7] + '<style type="text/css">{}</style>'.format(cssString) + self.headTag[-7:]

    def markdownToHtml(self, sourceFilePath, destinationDirectory = None, outputFileName = None):
        if not destinationDirectory:
            # 未定义输出目录则将源文件目录(注意要转换为绝对路径)作为输出目录
            destinationDirectory = os.path.dirname(os.path.abspath(sourceFilePath))
        if not outputFileName:
            # 未定义输出文件名则沿用输入文件名
            outputFileName = os.path.splitext(os.path.basename(sourceFilePath))[0] + '.html'
        if destinationDirectory[-1] != '/':
            destinationDirectory += '/'
        with open(sourceFilePath,'r', encoding='utf8') as f:
            markdownText = f.read()
        # 编译出原始 HTML 文本
        rawHtml = self.headTag + markdown.markdown(markdownText,output_format='html5')
        # 格式化 HTML 文本为可读性更强的格式
        beautifyHtml = BeautifulSoup(rawHtml,'html5lib').prettify()
        with open(destinationDirectory + outputFileName, 'w', encoding='utf8') as f:
            f.write(beautifyHtml)

if __name__ == "__main__":
    mth = MarkdownToHtml()
    # 做一个命令行参数列表的浅拷贝,不包含脚本文件名
    argv = sys.argv[1:]
    # 目前列表 argv 可能包含源文件路径之外的元素(即选项信息)
    # 程序最后遍历列表 argv 进行编译 markdown 时,列表中的元素必须全部是源文件路径
    outputDirectory = None
    if '-s' in argv:
        cssArgIndex = argv.index('-s') +1
        cssFilePath = argv[cssArgIndex]
        # 检测样式表文件路径是否有效
        if not os.path.isfile(cssFilePath):
            print('Invalid Path: '+cssFilePath)
            sys.exit()
        mth.genStyle(cssFilePath)
        # pop 顺序不能随意变化
        argv.pop(cssArgIndex)
        argv.pop(cssArgIndex-1)
    if '-o' in argv:
        dirArgIndex = argv.index('-o') +1
        outputDirectory = argv[dirArgIndex]
        # 检测输出目录是否有效
        if not os.path.isdir(outputDirectory):
            print('Invalid Directory: ' + outputDirectory)
            sys.exit()
        # pop 顺序不能随意变化
        argv.pop(dirArgIndex)
        argv.pop(dirArgIndex-1)
    # 至此,列表 argv 中的元素均是源文件路径
    # 遍历所有源文件路径
    for filePath in argv:
        # 判断文件路径是否有效
        if os.path.isfile(filePath):
            mth.markdownToHtml(filePath, outputDirectory)
        else:
            print('Invalid Path: ' + filePath)

8.文本文件编码检测与转换。

import sys
import os
import argparse
from chardet.universaldetector import UniversalDetector

parser = argparse.ArgumentParser(description = '文本文件编码检测与转换')
parser.add_argument('filePaths', nargs = '+',
                   help = '检测或转换的文件路径')
parser.add_argument('-e', '--encoding', nargs = '?', const = 'UTF-8',
                   help = '''
目标编码。支持的编码有:
ASCII, (Default) UTF-8 (with or without a BOM), UTF-16 (with a BOM),
UTF-32 (with a BOM), Big5, GB2312/GB18030, EUC-TW, HZ-GB-2312, ISO-2022-CN, EUC-JP, SHIFT_JIS, ISO-2022-JP,
ISO-2022-KR, KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251, ISO-8859-2, windows-1250, EUC-KR,
ISO-8859-5, windows-1251, ISO-8859-1, windows-1252, ISO-8859-7, windows-1253, ISO-8859-8, windows-1255, TIS-620
''')
parser.add_argument('-o', '--output',
                   help = '输出目录')
# 解析参数,得到一个 Namespace 对象
args = parser.parse_args()
# 输出目录不为空即视为开启转换, 若未指定转换编码,则默认为 UTF-8
if args.output != None:
    if not args.encoding:
        # 默认使用编码 UTF-8
        args.encoding = 'UTF-8'
    # 检测用户提供的输出目录是否有效
    if not os.path.isdir(args.output):
        print('Invalid Directory: ' + args.output)
        sys.exit()
    else:
        if args.output[-1] != '/':
            args.output += '/'
# 实例化一个通用检测器
detector = UniversalDetector()
print()
print('Encoding (Confidence)',':','File path')
for filePath in args.filePaths:
    # 检测文件路径是否有效,无效则跳过
    if not os.path.isfile(filePath):
        print('Invalid Path: ' + filePath)
        continue
    # 重置检测器
    detector.reset()
    # 以二进制模式读取文件
    for each in open(filePath, 'rb'):
        # 检测器读取数据
        detector.feed(each)
        # 若检测完成则跳出循环
        if detector.done:
            break
    # 关闭检测器
    detector.close()
    # 读取结果
    charEncoding = detector.result['encoding']
    confidence = detector.result['confidence']
    # 打印信息
    if charEncoding is None:
        charEncoding = 'Unknown'
        confidence = 0.99
    print('{} {:>12} : {}'.format(charEncoding.rjust(8),
        '('+str(confidence*100)+'%)', filePath))
    if args.encoding and charEncoding != 'Unknown' and confidence > 0.6:
        # 若未设置输出目录则覆盖源文件
        outputPath = args.output + os.path.basename(filePath) if args.output else filePath
        with open(filePath, 'r', encoding = charEncoding, errors = 'replace') as f:
            temp = f.read()
        with open(outputPath, 'w', encoding = args.encoding, errors = 'replace') as f:
            f.write(temp)

最后两个脚本内容选至实验楼的课程《使用 Python3 编写系列实用脚本》,课程对这两个脚本有详细的实现过程讲解,感兴趣的同学可以直接前往实验楼进行学习!

知乎专栏同步:https://zhuanlan.zhihu.com/p/...

查看原文

赞 1 收藏 0 评论 1

xiaoxiaozi 分享了头条 · 2019-09-26

一睹历史上诸位编程大神的头发,意外发现学习 Python 才能保卫发际线。

赞 0 收藏 0 评论 0

xiaoxiaozi 发布了文章 · 2019-09-25

Github 上 36 个最实用的 Vue 开源库

任何一个开发者,都是十分喜欢使用开源软件包的。因为它使开发工作变得更快速、高效、容易。如果没有开源软件包,开发工作将变得疲惫不堪,不断的重复造轮子!
下面整理了 Github 上 36 个实用的 Vue 开源库,建议收藏!

1.Bootstrap-Vue |star 10014

具有超过40个插件和超过75个自定义组件,为Vue.js提供了最全面的Bootstrap v4组件和网格系统实现。
Github:https://github.com/bootstrap-...

2.Vue.Draggable |star 9177

Vue.js 组件,基于 Sortable.js 进行同步的拖放排序。
Github:https://github.com/SortableJS...

3.Vue Native |star 6471

基于 React Native 实现,允许你使用 JavaScript 来构建跨平台的原生移动应用程序。
Github:https://github.com/GeekyAnts/...

4.Vue Quill Editor |star 4628

Vue.js 的 Quill 编辑器,支持 SPA 和 SSR。
Github:https://github.com/surmon-chi...

5.Vuelidate |star 4361

进行基于模型的验证,实现表单验证现在变得轻而易举。
Github:https://github.com/vuelidate/...

6.NativeScript Vue | Star 4176

可以帮助你使用 NativeScript 和 Vue.js 构建原生移动应用程序。
Github:https://github.com/nativescri...

7.Vetur |star 3674

VS Code 的 Vue 工具,习惯使用 VS Code 的朋友值得尝试!
Github:https://github.com/vuejs/vetur

8.Epic Spinners |star 3028

20 个易于使用的 css 调节器。
Github:https://github.com/epicmaxco/...

9.Vue Virtual Scroller |star 3020

用于 Vue.js 应用程序的快速无限制滚动。
Github:https://github.com/Akryum/vue...

10.Vue.js Datepicker |star 2113

一个简单的 Vue.js 日期选择器组件。
Github :https://github.com/charliekas...

11.Vuetable-2 |star 1792

Vue.js 的数据表组件。
Github:https://github.com/ratiw/vuet...

12.Vue Color |star 1624

来自 Sketch、Photoshop、Chrom 的 Vue.js 颜色选择器。
Github:https://github.com/xiaokaike/...

13.Vue Notification | star 1522

用在 Vue.js 应用程序中的成功、警告和错误通知。可以放在右侧、左侧、底部、顶部或中间,任何你想要的地方。
Github:https://github.com/euvl/vue-n...

14.Vue Slider Component |star 1495

这里面的 10 种滑块组件都使用 Vue.js 开发。
Github:https://github.com/NightCatSa...

15.Vue Moment |star 1048

在 Vue.js 应用程序中使用 Moment.js。
Github :https://github.com/brockpetri...

16.Vue Content Placeholders |star 1070

在获取真实内容时,可以使用这些可组合组件渲染虚假的渐进式内容。
Github:https://github.com/michalsnik...

17.Vue Draggable Resizable |star 1026

Vue.js 组件,用于可调整大小和可拖动的元素,没有外部依赖。
Github:https://github.com/mauricius/...

18.Vue Clipboard |star 961

一个简单的 Vue.js 包,允许用户将文本复制到基于clipboard.js的剪贴板。
Github:https://github.com/Inndy/vue-...

19.Vue Trend |star 929

最优雅的趋势图组件。
Github:https://github.com/QingWei-Li...

20. Vue Dark Mode |star 889

一个极简主义的黑暗设计系统,提供基础组件,用于构建失眠者最喜欢的深色洁面。
Github:https://github.com/LeCoupa/vu...

21.Vue-Vscode-Snippets |star 826

这些片段很棒,尽可能无缝地增强工作流程。新手值得推荐!
Github:https://github.com/sdras/vue-...

22.Avoriaz |star 774

VueJS测试实用工具库。
Github:https://github.com/eddyerburg...

23.Vue Clickaway |star 622

一种可重复使用的点击指令,可检测并响应元素外部的点击动作。当我们需要关闭模态窗口或隐藏下拉列表时会非常方便。
Github:https://github.com/simplesmil...

24.Emoji Mart Vue |star 424

从 React 的 emoji-mart fork 出来的,用于 Vue.js 的 Slack 风格的可定制表情符号选择器组件。
Github:https://github.com/jm-david/e...

25.Vue Stripe Checkout |star 365

用于 Stripe 结帐的 Vue.js 插件。
Github:https://github.com/jofftiquez...

26.Vue No SSR |star 353

用于包装对 SSR 不友好的组件。
Github:https://github.com/egoist/vue...

27.Vue Autosuggest |star 340

一个很棒的 Vue.js 自动提示组件。
Github:https://github.com/Educents/v...

28.Vue YouTube Embed |star 301

基于 Angular YouTube Embed,允许你使用 YouTube iframe API。
Github:https://github.com/kaorun343/...

29.Vue Numeric |star 295

Vue.js 输入字段组件,用于显示格式化的货币值。
Github:https://github.com/kevinongko...

30.Vue Popper |star 256

一个基于 popper.js 的 Vue.js 弹出窗口组件。
Github:https://github.com/RobinCK/vu...

31.Vue Waypoint |star 232

基于 CountUp.js,可用于创建显示数字数据的动画。
Github:https://github.com/xlsdg/vue-...

32.Vue Waypoint |star 223

Vue.js 的 v-waypoint 指令,用于在滚动时触发函数。当你想要在滚动时触发动画,它就可以派上用场。
Github:https://github.com/scaccogatt...

33.Vue Cleave Component |star 222

Cleave.js 的 Vue.js 组件,用于在输入时格式化输入内容(信用卡格式、日期等)。
Github:https://github.com/ankurk91/v...

34.Vue Swing |star 152

它是Swing的 vue.js 包装器,一个卡片形式的界面(swipe-left 对应是,swipe-right 对应否)。
Github:https://github.com/goweiwen/v...

35.Vue Chartist |star 132

基于 Chartist.js 的响应式图表。
Github:https://github.com/Yopadd/vue...

36.Vue Slideout |star 131

Slideout.js 的 Vue.js 实现。
Github:https://github.com/vouill/vue...

相关推荐

查看原文

赞 1 收藏 1 评论 0

xiaoxiaozi 发布了文章 · 2019-09-20

21个入门练手项目,让你轻松玩转C语言

整理了 21 个 C 语言练手项目,从基础语法开始,逐步深入,通过一个个练手项目,让你轻松驰骋在 C 语言的快车道。不走弯路就是捷径!
图片描述

1.《C语言入门教程》:引入大量的 C 语言程序案例,把算法和语法结合起来,通过引导大家由浅入深地编写 C 程序,让大家掌握 C 语言。将从中学会 C 语言语法、数组、模块化程序设计指针、文件的输入与输出等。

2.《C语言实现文件类型统计程序》:使用C语言实现一个文件类型统计程序。

3.《C 语言实现多线程排序》:使用 C 语言多线程模型实现了排序算法。

4.《3个C语言实例带你掌握递归方法论》:通过 3 个 C 语言编程实例,让你在利用递归解决实际问题的过程中学习递归并掌握其核心思想。

5.《C语言实现LRU缓存》:使用 C 语言实现 LRU 缓存,从中学习 LRU 缓存的基本概念、C 语言相关编程技巧,双向链表的 C 语言实现以及哈希表的 C 语言实现。
图片描述

6.《C语言实现通讯录》:使用 C 语言完成一个简单的通讯录。会涉及到结构体、数组、链表等重要概念。

7.《C 语言制作简单计算器》:用 C 语言做一个简单的计算器,进行加、减、乘、除操作。学习 C 语言的基本语法,与输入与输出。

8.《C语言实现大数计算器(加减乘除)》通过 C 语言实现一个简易计算器,用于解决任意长度的有符号整数的加、减、乘、除运算。将利用全新的数据结构来表示大数,并将新数据结构存储的大数转化为字符用于显示。以及基于大数新的数据结构完成加、减、乘、除的计算算法设计。

9.《C 语言实现聊天室软件》:使用 C 语言实现聊天室软件,学习并实践基本的 Linux socket 通信的相关技术,加深对 TCP/IP 协议栈的理解。

10.《C 语言实现 web 服务器》:使用 C 语言实现一个Web服务器。将会学习 C 语言网络开发,epoll IO 复用机制,熟悉Linux下的C语言程序编译方法,Makefile编写等技能。
图片描述

11.《C语言实现Linux pwd命令》:通过实现 linux pwd 命令,以理解 linux 文件系统的基本概念及内部实现,并熟悉linux系统与文件系统相关的系统调用接口。

12.《C语言实现 FTP 服务器》:更加深入的理解套接字编程模型,并且了解应用层协议(FTP)如何在套接字基础上定义。本项目实现了支持 list,get <filename>,quit 等命令的 FTP 服务器。

13.《C 语言实现Linux who命令》:通过 C 语言实现Linux who命令 项目的学习,可以掌握 Linux 操作系统为上层提供的访问系统数据文件的接口。更好的理解 Linux 操作系统工作的原理。

14.《C 语言实现Linux cp 命令》:通过完成C 语言实现Linux cp 命令项目的学习,可以掌握Linux操作系统中的文件IO相关的系统函数和目录相关操作的系统函数,比如open, write, opendir, readir。深入了解Linux环境系统编程。

15.《C语言实现Linux ls命令》:本课程学习 linux 目录与文件属性,使用C语言实现 Linux ls 命令。其中涉及到 ls 的原理,如何获取获取文件的属性,掩码的相关知识。认识linux系统函数opendir(),readdir()等的调用方法。

16.《C语言实现Linux touch命令》:通过完成一个C语言实现Linux touch命令项目,学习基于LINUX环境的系统编程技术,尤其 Linux 文件 IO 操作相关技术。
图片描述

17.《C语言实现ping程序》:带领你学习用C语言实现 ping 命令。通过本项目中你可以更深入地理解 TCP/IP 协议,套接字编程,掌握C语言进行网络编程的技巧方法。

18.《C语言版 Flappy Bird》:使用 C 语言来实现一个字符版 Flappy Bird,感受不一样的风采。本课程学习后将会熟悉C语言,以及绘图库ncurses的使用。本课程适合有C语言基础,想做练手项目的同学,可以有效的学习ncurses绘图库的使用,做一些有趣的事情。
图片描述

19.《C 语言实现贪吃蛇》:将在Linux平台使用C语言编程,在终端界面上玩贪吃蛇。本课程分为三个实验,实验一介绍了图像库,实验二绘制游戏图像界面,实验三实现贪吃蛇。逐步为同学们讲解一个游戏的制作过程。

20.《C 语言快速实现五子棋》:用最简单的代码来实现五子棋游戏,帮助大家复习基础知识,学习了如何设计并实现一个五子棋游戏,巩固大家的基础知识。涉及到C语言的基础逻辑判断,程序设计与编写。

21.《C 语言制作 2048》:2048是之前十分火爆的一款益智游戏。将使用 C 语言完成一个2048游戏。适合对C语言有一定基础,想做项目练手的同学,本课程学习后将会了解C语言,以及绘图库ncurses的实用。
图片描述

​​​​​

查看原文

赞 10 收藏 9 评论 0

认证与成就

  • 获得 826 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2015-09-06
个人主页被 943 人浏览