golang ide环境配置

January 20th, 2018 by JasonLe's Tech 1,327 views

最近golang和区块链火起来了,觉得自己有必要也跟一次风了。

golang的背景啊,优缺点啊就不讲了,网上大把资料,只要有C/C++的基础,这个golang程序猿就可以快速胜任。我就说一下配置过程和调试过程中的坑。golang的安装非常简单,只需要将其解压到制定目录,设置好GOROOT和GOPATH即可,GOROOT是golang的可执行文件,而GOPATH从我理解就是Go Project的所在目录,我们平时go get所下载的工程都会放到$GOPATH/src中。

由于刚开始接触,我手动设置了go编程环境,也使用go run 运行了hello world,但是一直无法调试go程序,在网上找了半天debugger,发现delver可以用来调试go程序,我习惯使用git+make install安装程序,安装完毕之后,我将其安装到go所在目录,方便直接命令行调用。

spider@ubuntu:/usr/lib/go-1.9.2$ ls
api  AUTHORS  bin  blog  CONTRIBUTING.md  CONTRIBUTORS  doc  favicon.ico  lib  LICENSE  misc  PATENTS  pkg  README.md  robots.txt  src  test  VERSION
spider@ubuntu:/usr/lib/go-1.9.2$ cd bin/
spider@ubuntu:/usr/lib/go-1.9.2/bin$ ls
dlv  go  godoc  gofmt

只要用过gdb的童靴,这个就非常简单了,比如break,continue,print 等,如下所示:

spider@ubuntu:/tmp$ dlv debug test.go
Type 'help' for list of commands.
(dlv) l
> _rt0_amd64_linux() /usr/lib/go-1.9.2/src/runtime/rt0_linux_amd64.s:8 (PC: 0x4571b0)
Warning: debugging optimized function
     3:	// license that can be found in the LICENSE file.
     4:	
     5:	#include "textflag.h"
     6:	
     7:	TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
=>   8:		LEAQ	8(SP), SI // argv
     9:		MOVQ	0(SP), DI // argc
    10:		MOVQ	$main(SB), AX
    11:		JMP	AX
    12:	
    13:	// When building with -buildmode=c-shared, this symbol is called when the shared
(dlv) b main.main
Breakpoint 1 set at 0x4a08d8 for main.main() ./test.go:12
(dlv) c
> main.main() ./test.go:12 (hits goroutine(1):1 total:1) (PC: 0x4a08d8)
Warning: debugging optimized function
     7:	   return n
     8:	  }
     9:	  return fibonacci(n-2) + fibonacci(n-1)
    10:	}
    11:	
=>  12:	func main() {
    13:	    var i int
    14:	    for i = 0; i < 10; i++ { 15: fmt.Printf("%d\t", fibonacci(i)) 16: } 17: } (dlv) n > main.main() ./test.go:13 (PC: 0x4a08ef)
Warning: debugging optimized function
     8:	  }
     9:	  return fibonacci(n-2) + fibonacci(n-1)
    10:	}
    11:	
    12:	func main() {
=>  13:	    var i int
    14:	    for i = 0; i < 10; i++ { 15: fmt.Printf("%d\t", fibonacci(i)) 16: } 17: } (dlv) > main.main() ./test.go:14 (PC: 0x4a08f8)
Warning: debugging optimized function
     9:	  return fibonacci(n-2) + fibonacci(n-1)
    10:	}
    11:	
    12:	func main() {
    13:	    var i int
=>  14:	    for i = 0; i < 10; i++ { 15: fmt.Printf("%d\t", fibonacci(i)) 16: } 17: } (dlv) > main.main() ./test.go:15 (PC: 0x4a0913)
Warning: debugging optimized function
    10:	}
    11:	
    12:	func main() {
    13:	    var i int
    14:	    for i = 0; i < 10; i++ { =>  15:	       fmt.Printf("%d\t", fibonacci(i))
    16:	    }
    17:	}
(dlv) p i
0
(dlv) n
0	> main.main() ./test.go:14 (PC: 0x4a0a02)
Warning: debugging optimized function
     9:	  return fibonacci(n-2) + fibonacci(n-1)
    10:	}
    11:	
    12:	func main() {
    13:	    var i int
=>  14:	    for i = 0; i < 10; i++ { 15: fmt.Printf("%d\t", fibonacci(i)) 16: } 17: } (dlv) > main.main() ./test.go:15 (PC: 0x4a0913)
Warning: debugging optimized function
    10:	}
    11:	
    12:	func main() {
    13:	    var i int
    14:	    for i = 0; i < 10; i++ { =>  15:	       fmt.Printf("%d\t", fibonacci(i))
    16:	    }
    17:	}
(dlv) p i
1

另外我们也可以使用dlv attach pid的方式进行调试,当然我们必须开启/proc/sys/kernel/yama/ptrace_scope to 0。然而我gdb、dlv再怎么强大,还是没有IDE方便,尤其是断点调试,经过调研VSCode、Gogland、Atom满足我们需求,由于之前我一直是用JetBrain系产品进行开发,毫无疑问,我是用Gogland作为IDE。我着重说一下他的调试,当debug某个程序时候,Gogland会打印信息:

GOROOT=/usr/lib/go-1.9.2 #gosetup
GOPATH=/home/spider/go #gosetup
/usr/lib/go-1.9.2/bin/go build -o /tmp/___go_build_main_go -gcflags "-N -l" -a /home/spider/go/src/awesomeProject/main.go #gosetup
/opt/GoLand/plugins/intellij-go-plugin/lib/dlv/linux/dlv --listen=localhost:41151 --headless=true --api-version=2 --backend=default exec /tmp/___go_build_main_go -- #gosetup

可以看到第一行、第二行是打印GOROOT和GOPATH,第三行是打印进行编译,添加-gcflags “-N -l”,是为了去掉编译优化,方便调试,这行执行完毕会把程序放到/tmp/___go_build_main_go中,第四行就是使用gogland中的dlv插件的debug server,后端就是我们编译的/tmp/___go_build_main_go程序。

 

参考

https://golang.org/doc/editors.html

Python 包管理工具总结

December 4th, 2017 by JasonLe's Tech 1,293 views

最近一直使用elasticsearch-py 操作数据库,最开始我是clone的他的官方仓库,然后使用python setup.py install方式安装的,虽然也可以使用,调用他的包没有什么问题,但是在pycharm中一直出现红色下划线,当遇到参数错误的时候,也没有办法跳入接口,看内部实现,比较抓狂。。。。。

考虑到之前配置python包遇到很多小问题,这次一次性把技术债还了。

通过查资料,大致可以理出来distutils、setuptools、distribute、disutils2、distlib、pip这几个工具的出现先后:

  1. 首先出现的安装工具是distutils,distutils 是 python 标准库的一部分,我们在python工程中的setup.py就是利用distutils完成的,他的工作原理很简单,但是功能有限。
  2. 为了完善distutils工具,产生了setuptools,它包含了 easy_install 这个工具;其中 ez_setup.py 是 setuptools 的安装工具,ez 就是 easy 的缩写。我们可以是使用
    easy_install http://example.com/Package-1.2.3.tgz  .egg 方式安装。
  3. distribute 是 setuptools 的一个分支版本,目前distribute 又合并回了 setuptools 中。本质上是同一个东西。如果查看一下 easy_install 的版本,它本质上就是 distribute 。
  4. distutils2是一个新的distutils库,作为distutils代码库的一个分支。
  5. distlib是distutils2的一部分
  6. pip是目前 python 包管理的事实标准,2008年发布。用来替换 easy_install,但是它仍有大量的功能建立在 setuptools 组件之上。

以上工具中distutils、setuptools、distribute、pip是主流包管理器,disutils2、distlib还需要观察。

eggs Vs whl 

Eggs 格式是 setuptools 引入的一种文件格式,它使用 .egg 扩展名,用于 Python 模块的安装。而setuptools 可以识别这种格式。并解析安装它。

wheel 本质上是一个 zip 包格式,它使用 .whl 扩展名,用于 python 模块的安装,它的出现是为了替代 Eggs。

eggs和whl本质上都是压缩包,我们都可以通过修改后缀名,解压提取内容!但是在pip中不太推荐egg的安装方式,因为egg安装后,只是把这个egg安装包放到dist-package中,而whl本质是一种源码安装,安装后在dist-package中存在源码和同名的info文件来描述这个安装包,因此我们可以在调用的时候,查看接口,而egg在编译器看来就是一堆二进制数据。

拿elasticsearch-py源码包举例,从github上clone最新的源码到本地,我们可以使用python setup.py install 直接将egg安装到/usr/local/lib/python2.7/dist-package中,而源码放在elasticsearch-py源码中的build中,所以可以使用python setup.py sdist 将其压缩为egg,然后使用pip安装该egg。另外也可以将源码打成rpm : python setup.py bdist_rpm   exe: python setup.py bdist_wininst

但是还是推荐打成whl格式的安装包,python setup.py bdist_wheel 。这个会将源码安装到dist-package中。

依赖安装:setup.py和requirements.txt的对比 这篇文章主要参数了两种安装文件的异同,归纳起来就是setup.py无法灵活限定软件版本,而requirements.txt可以限定具体软件包的版本,可以配合setup.py实现。

requirements.txt:

--index https://pypi.python.org/simple/
-e https://github.com/foo/bar.git#egg=bar
-e .

比如 pip install -r requirements.txt 可以照常工作,它会先安装requirements路径下的bar包,然后继续开始解析抽象依赖,结合 –index 选项后转换为具体依赖然后再安装她们。

这个办法可以让我们解决一种类似这样的情形:比如有两个或两个以上的包在一起开发但是是分开发行的,或者说有一个尚未发布的包并把它分成了几个部分。如果顶层的包 依然仅仅按照“名字”来依赖的话,我们依然可以使用requirements.txt 来安装开发版本的依赖包。

 

参考

https://docs.python.org/3/distutils/introduction.html?highlight=distutils#a-simple-example

http://blog.csdn.net/lynn_kong/article/details/17540207

https://stackoverflow.com/questions/6344076/differences-between-distribute-distutils-setuptools-and-distutils2/14753678#14753678

elasticsearch 配置遇到的问题

October 7th, 2017 by JasonLe's Tech 1,279 views

为了存储海量数据,以便进一步进行数据分析,调研了一段时间,elasticsearch是个不错的选择。
elasticsearch 是一个用于搜索领域的分布式数据库,基于jdk为jdk1.8.0_73以上。不同于mysql之类的关系型数据库,elasticsearch基于RESTful web接口 需要使用POST/GET/DELETE/PUT来处理数据。我采用elasticsearch-py接口对数据库进行CRUD。不过在启动的时候,发现如下问题:

[2017-12-27T21:07:13,695][INFO ][o.e.t.TransportService   ] [node-1] publish_address {192.168.228.134:9300}, bound_addresses {[::]:9300}
[2017-12-27T21:07:14,005][INFO ][o.e.b.BootstrapChecks    ] [node-1] bound or publishing to a non-loopback or non-link-local address, enforcing bootstrap checks
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
[2017-12-27T21:07:14,155][INFO ][o.e.n.Node               ] [node-1] stopping ...
[2017-12-27T21:07:14,468][INFO ][o.e.n.Node               ] [node-1] stopped
[2017-12-27T21:07:14,482][INFO ][o.e.n.Node               ] [node-1] closing ...
[2017-12-27T21:07:14,764][INFO ][o.e.n.Node               ] [node-1] closed

这个时候需要扩大虚拟内存堆:sysctl -w vm.max_map_count=262144

另外安装elasticsearch-head在5.x版本后需要借助nodejs服务,这一块配置安装比较繁琐,先要配置nodejs/npm/grunt。

npm安装:

curl https://npmjs.org/install.sh | sh
sh install.sh

如果出现 npm cannot be installed without Node.js. Install Node.js first, and then try again. 则需要 安装Node.js

apt-get install nodejs 如果node.js版本过低,则需要升级

# 第一步:首先安装 n 模块:
npm install -g n
# 第二步:升级node.js到最新稳定版
n stable

node 环境安装完毕后安装 elasticsearch-head 所需模块:

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start

配置完 elasticsearch-head,要在./config/elasticsearch.yml中打开注释,然后重新启动es。

http.port: 9200
# 跨域
http.cors.enabled: true
http.cors.allow-origin: "*"

 

参考:

https://my.oschina.net/kittyMan/blog/387512?p=1
http://orchome.com/489

basemap 尝鲜

September 28th, 2017 by JasonLe's Tech 1,240 views

去年做毕业论文的时候做统计的时候用过gnuplot,最近做数据挖掘和可视化,又发现matplotlib是一个比较活跃的绘图python库。通过matplotlib可以绘制散点图,柱状图,折线图。这些配合sklearn可以进行经典的数据挖掘。

最近老板给我一些gis方面的数据,先摸索一下数据分布,为以后的聚类做准备。开始我直接将GIS的经纬度scatter到二维坐标系中,发现没有地图做配合,看分布非常抽象。忽闻basemap作为matplotlib的一个子插件可以胜任该工作。

首先basemap可以绘制不同的地理信息图,包括blue marble 球状的、饼状的、二维地图等不同形式。我这里主要绘制折线图,所以使用plot就可以了。

import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from datetime import datetime

map = Basemap(projection='mill',lon_0=180)
map.drawcoastlines()
map.drawparallels(np.arange(-90,90,30),labels=[1,0,0,0])
map.drawmeridians(np.arange(map.lonmin,map.lonmax+30,60),labels=[0,0,0,1])
map.drawmapboundary(fill_color='aqua')
map.fillcontinents(color='coral',lake_color='aqua')

只需要声明Basemap方法,声明投影方式即可,对于投影方式我挺懵逼的,不过我们把basemap下载下来,里面有examples,可以直接运行run_all.py,观察自己想要的投影方式,当然了最基本的经纬度概念还是要有,否则就无法选择我们想要的固定区域。merc就是绘制其中一部分地图的投影方式

m = Basemap(llcrnrlon=-100.,llcrnrlat=20.,urcrnrlon=20.,urcrnrlat=60.,\
            rsphere=(6378137.00,6356752.3142),\
            resolution='l',projection='merc',\
            lat_0=40.,lon_0=-20.,lat_ts=20.)

其中llcrnrlon,llcrnrlat代表left down的经度,纬度;urcrnrlon,urcrnrlat代表upper right的经度,纬度。以对角坐标值就可以确定一个唯一的视口大小。

附我做的航路图:

使用matplotlib只要记住绘制散点(scatter),折线(plot)基本就可以满足我们的需要了。

参考

http://matplotlib.org/basemap/users/examples.html

sklearn 典型的回归模型

September 14th, 2017 by JasonLe's Tech 1,620 views

回归模型中线性回归是最最基本的模型,也是在数据处理中运用最多的模型。sklearn提供了一套完备的工具集,可以对数据进行拟合和预测。

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression,RidgeCV,LassoCV,ElaticNetCV
from sklearn.preprocessing.PolynomialFeatures import PolynomialFeatures
models = [Pipeline([  
        ('poly', PolynomialFeatures()),  
        ('linear', LinearRegression(fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', RidgeCV(alphas=np.logspace(-3, 2, 50), fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', LassoCV(alphas=np.logspace(-3, 2, 50), fit_intercept=False))]),  
        Pipeline([  
            ('poly', PolynomialFeatures()),  
            ('linear', ElasticNetCV(alphas=np.logspace(-3, 2, 50), l1_ratio=[.1, .5, .7, .9, .95, .99, 1],  
                                    fit_intercept=False))])  
    ]  

模型中的fit_intercept代表是否存在截距,默认是开启的,normalize:标准化开关,默认关闭。

通过上面的头文件就可以看出来除了提供最最基本的LinearRegression以外,还提供带有L1 L2范数的LassoCV和RidgeCV。

LinearRegression的损失函数为J(θ)=1/2(Xθ−Y)T(Xθ−Y) 。优化方法为梯度下降和最小二乘法,scikit中采用最小二乘
。只要数据线性相关,LinearRegression就是首选,如果发现拟合或者预测的不够好,再考虑其他的线性回归库。

LassoCV的损失函数为J(θ)=1/2m(Xθ−Y)T(Xθ−Y)+α||θ|| 。即 线性回归LineaRegression的损失函数+L1(1范式的正则化项α||θ||) ,Lasso回归可以使得一些特征的系数变小,甚至还使一些绝对值较小的系数直接变为0,从而增强模型的泛化能力,因此对于高维的特征数据,尤其是线性关系是稀疏的,就采用Lasso回归,或者是要在一堆特征里面找出主要的特征。

RidgeCV的损失函数为J(θ)=1/2(Xθ−Y)T(Xθ−Y)+1/2(α||θ||^2)。即线性回归LineaRegression的损失函数+L2(2范式的正则化项1/2(α||θ||^2))),其中a为超参数 alphas=np.logspace(-3, 2, 50) 从给定的超参数a中选择一个最优的,logspace用于创建等比数列 本例中 开始点为10的-3次幂,结束点10的2次幂,元素个数为50.并且从这50个数中选择一个最优的超参数。Ridge回归中超参数a和回归系数θ的关系,a越大,正则项惩罚的就越厉害,得到的回归系数θ就越小,最终趋近与0。如果a越小,即正则化项越小,那么回归系数θ就越来越接近于普通的线性回归系数。
#使用场景:只要数据线性相关,用LinearRegression拟合的不是很好,需要正则化,可以考虑使用RidgeCV回归。

ElaticNetCV的损失函数为J(θ)=1/2m(Xθ−Y)T(Xθ−Y)+αρ||θ||1+α(1−ρ)/2||θ||22 其中α为正则化超参数,ρ为范数权重超参数 。乍一看就是Lasso和Ridge损失函数的合体。其中alphas=np.logspace(-3, 2, 50), l1_ratio=[.1, .5, .7, .9, .95, .99, 1] 。ElasticNetCV会从中选出最优的 a和p 。ElasticNetCV类对超参数a和p使用交叉验证,帮助选择合适的a和p,使用场景:ElasticNetCV类在我们发现用Lasso回归太过(太多特征被稀疏为0),而Ridge回归也正则化的不够(回归系数衰减太慢)的时候。

所以综上排名:LinearRegression > LassoCV(稀疏) >  ElaticNetCV  > RidgeCV(稠密) 

model = models[t]  
model.set_params(poly__degree=d) #设置多项式回归的阶
model.fit(x, y.ravel()) 
lin = model.get_params('linear')['linear'] 
if hasattr(lin, 'alpha_'): 
  ...
if hasattr(lin, 'l1_ratio_'): # 根据交叉验证结果,从输入l1_ratio(list)中选择的最优l1_ratio_(float) 
  ...
print output, lin.coef_.ravel(),lin.intercept_ 
y_hat = model.predict(x_hat)  
s = model.score(x, y)  

sklearn中提供了pipeline,只要把模型定义好,就可以直接利用fit对数据进行拟合,拟合完毕后使用predict进行预测。其中通过get_params可以获取某个模型,然后就能访问该回归模型的coef_和intercept_ ,如果模型设置的fit_intercept=false,那么打印出的lin.coef_中第一项就是截距,后面的为各个相关系数,lin.intercept_为0。如果置为true,那么lin.intercept_为截距值。

model.score主要用来衡量模型的拟合程度,Returns the coefficient of determination R^2 of the prediction.

R^2就是1-RSS/TSS,R^2越大,拟合效果越好。如果预测值为样本期望,那么R^2为0。

附sklearn工具类

参数列表 类别 fit方法有用 说明
sklearn.preprocessing StandardScaler 特征 无监督 Y 标准化
sklearn.preprocessing MinMaxScaler 特征 无监督 Y 区间缩放
sklearn.preprocessing Normalizer 特征 无信息 N 归一化
sklearn.preprocessing Binarizer 特征 无信息 N 定量特征二值化
sklearn.preprocessing OneHotEncoder 特征 无监督 Y 定性特征编码
sklearn.preprocessing Imputer 特征 无监督 Y 缺失值计算
sklearn.preprocessing PolynomialFeatures 特征 无信息 N 多项式变换(fit方法仅仅生成了多项式的表达式)
sklearn.preprocessing FunctionTransformer 特征 无信息 N 自定义函数变换(自定义函数在transform方法中调用)
sklearn.feature_selection VarianceThreshold 特征 无监督 Y 方差选择法
sklearn.feature_selection SelectKBest 特征/特征+目标值 无监督/有监督 Y 自定义特征评分选择法
sklearn.feature_selection SelectKBest+chi2 特征+目标值 有监督 Y 卡方检验选择法
sklearn.feature_selection RFE 特征+目标值 有监督 Y 递归特征消除法
sklearn.feature_selection SelectFromModel 特征+目标值 有监督 Y 自定义模型训练选择法
sklearn.decomposition PCA 特征 无监督 Y PCA降维
sklearn.lda LDA 特征+目标值 有监督 Y LDA降维

参考

http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.RidgeCV.html