学的时候顺便想拿点东西练练手,顺便也可以看看seaborn到底有什么用处。正好Checkee.info上面有足够多的签证数据,就扒拉下来看看。
取数据,洗数据
checkee.info上的数据格式其实非常友好。高手直接爬虫就能很方便的爬下来。可是我还不会,就直接一口气复制下来。
-
新建一个csv文档,前面的update和后面的details可以很方便的用查找替换直接删去。
- 初步处理好文件之后先保存。准备写代码。
import numpy as np
import pandas as pd
from scipy import stats, integrate
import matplotlib.pyplot as plt
checker = pd.read_csv('fullchecklist.csv',sep = ' ') #读取csv
del checker['ID']
del checker['Major']
checker.to_csv('fullchecklist_filter.csv',index = None) #保存csv
- 先用pandas库对csv进行读取。使用pd.read_csv这个函数。因为我们复制下来的分隔符是“ ”而csv数据间默认的分隔符是英文逗号。所以需要声明sep = ' '。
- 第二三步 del checker['ID']、del checker['Major'],即将数据中名为“ID”和“Major”列删除。用不上ID所以删了。对于Major,因为checkee上没有提供标准的专业选择,所以不少相同专业的人填入的内容可能也不太一样。而且有人还输入了各种符号,给我们后来的操作造成障碍,所以删了。
- 最后用to_csv函数保存新的csv文件,顺便传入index = None,不然输出的csv文件中会增加一列用来计数。注意,保存后的csv文件里已经将分隔符换为了标准的英文逗号。
到这里,粗糙的处理就已经完成了。其实已经可以开始绘图了,但是还有一些小地方可以做的更好。
- 第一,注意到US Consulate(即面签使馆)列不仅包括了国内的使馆,也有国外的使馆。在分使馆绘图时会造成项目过杂的情况。这里我们通过一个正则替换将所有非国内使馆替换为“Overseas”
import pandas as pd
import re #导入正则库
try:
datas = open('fullchecklist_filter.csv','r')
#读取文件
ss = open('newchekee.txt','w')
#以写入方式打开一个新的txt文件
l = 1
while True: #读取文件循环
line = datas.readline()
if l == 1: #第一行,因为这行是表头
ss.write(line)
l += 1
continue #继续下一个循环
if line: #如果读取成功
l += 1
m = re.match(r'([A-Z][0-9],[0-9a-zA-Z]+,)([0-9a-zA-Z]+)([0-9a-zA-Z &,-.]+)',line)
#正则读取
if m:
plcstr = str(m.group(2))
#按照正则规则读取的第二组字符串,即US Consulate
if plcstr == 'BeiJing'or plcstr == 'ShangHai'or plcstr == 'GuangZhou'or plcstr == 'ShenYang'or plcstr == 'ChengDu'or plcstr == 'HongKong':
#若是国内的,直接原样写入
ss.write(m.group(0))
ss.write('\n')
else:
#若是国外的,将第二组替换为Overseas再写入
ss.write(m.group(1))
ss.write('Overseas')
ss.write(m.group(3))
ss.write('\n')
else:
break
finally: #关闭文件
if datas:
datas.close()
if ss:
ss.close()
- 第二,注意到时间为YYYY-MM-DD格式,直接将所有的“-”替换为“,”。在表头添加一下就行:
Check_Year, Check_Month, Check_Day, Complete_Year, Complete_Month, Complete_Day,
这样就能保证表头的数目和数据数目一致了。之后也可以用前面的del语句删除无用的列。
del checker['Check_Year']
del checker['Complete_Year']
del checker['Complete_Month']
del checker['Complete_Day']
到这里,数据就处理完成了。
开始画图
导入各种库
import numpy as np
import pandas as pd
from scipy import stats, integrate
import matplotlib.pyplot as plt
from matplotlib import gridspec
import re
import seaborn as sns
然后读取csv文件,并生成一些我们需要的子表。这里使用了pandas的.query语句。随后我们将checker的info打印出来看看分别都是些什么东西:
checker = pd.read_csv('checkeefil2.csv')
F1 = checker.query("Visa_Type == 'F1'")
#将checker里Visa_Type为F1的数据行取出
J1 = checker.query("Visa_Type == 'J1'")
Clear_Case = checker.query("Status == 'Clear'")
FJ1 = pd.concat([F1,J1])
#将表F1和J1合并
打印一下
checker.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3762 entries, 0 to 3761
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Visa_Type 3762 non-null object
1 Visa_Entry 3762 non-null object
2 US_Consulate 3762 non-null object
3 Status 3762 non-null object
4 Check_Month 3762 non-null int64
5 Check_Day 3762 non-null int64
6 Waiting Days 3762 non-null float64
dtypes: float64(1), int64(2), object(4)
其实剩下的东西也不多了。就用这些东西来做可视化吧。
- 首先定好画布大小和分栏,这里我们决定画2个图。
sns.set(font='Helvetica',font_scale=1) #使用seaborn风格,字体设置为Helvetica,默认缩放
plt.figure(figsize=(12,8)) #画布大小1200*800
gs = gridspec.GridSpec(1, 2, width_ratios=[2, 1])#定义2x2个子图,宽度比为2:1。使位于左边的图更宽一些。
cmap = sns.cubehelix_palette(3,start = .8, rot = -1.2, light = .6)#定义一个好看的配色方案
# Figure 1
ax0 = plt.subplot(gs[0])
sns.stripplot(x="US_Consulate", y="Waiting Days",hue="Status",
order=['BeiJing','ShangHai','GuangZhou','ShenYang','ChengDu','HongKong','Overseas'],
data=checker,palette=cmap,jitter=.35,dodge=True,size=3,alpha=.8,ax=ax0)
ax0.set_xlabel('Consulate Location',fontsize=12)
ax0.set_ylabel('Waiting Days',fontsize=15)
plt.legend(loc=1,fontsize=10)
ax0.tick_params(axis='y',labelsize=13)
ax0.tick_params(axis='x',labelsize=10)
plt.ylim(-60, 480)
# Figure 2
ax1 = plt.subplot(gs[1])
sns.stripplot(x="Status", y="Waiting Days",hue="Visa_Type",
order= ['Pending','Clear','Reject'],
data=FJ1,palette=cmap,
#jitter=.2,
dodge=True,size=2.5,alpha=.8,ax=ax1)
plt.legend(loc=1,fontsize=10)
plt.ylim(-60, 480)
ax1.set_xlabel('F1 & J1 Visa Cases',fontsize=12)
ax1.set_ylabel('Waiting Days',fontsize=15)
ax1.tick_params(axis='y',labelsize=13)
ax1.tick_params(axis='x',labelsize=10)
参考
- Pandas库数据操作:
- Seaborn的画图类型,参数调整和色彩搭配:
- 签证数据: