LambdaRank算法原理

LambdaRank算法原理

之前总结的一个pdf

正文


0 Comments

报表经验

报表经验

大概做了一个监控线上业务的小任务,根据日志,统计分析数据,生成报表,每天以邮件发出

关键词: hadoop streaming mrjob、 linux shell、 python matplotlib、 html、 php send mail

mrjob

mrjob lets you write MapReduce jobs in Python 2.6+/3.3+ and run them on several platforms.

参考文档:mrjob v0.5.10 documentation

hadoop with python

github-mrjob/examples

一些例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# MRWordCount.py
from mrjob.job import MRJob
from mrjob.step import MRStep
class MRWordCount(MRJob):
def mapper_parse(self, _, line):
for word in line.split():
yield(word, 1)
def reducer_count(self, word, counts):
yield(word, sum(counts))
def steps(self):
return [
MRStep(mapper=self.mapper_parse,
reducer=self.reducer_count,
)
]
if __name__ == '__main__':
MRWordCount.run()

运行命令:

1
2
3
4
python MRWordCount.py <in.txt >out.txt
python MRWordCount.py -r local <in.txt >out.txt
python MRWordCount.py in.txt -o out_dir
python MRWordCount.py -r hadoop in1.txt in2.txt -o out_dir

以上几种运行命令均可,-r指定运行环境,默认本地,-o指定输出路径
local模式不需要装hadoop,mrjob会自己模拟

mrjob整个job逻辑流程,除了mapper()、reducer(),还有
combiner()
mapper_init()
combiner_init()
reducer_init()
mapper_final()
combiner_final()
reducer_final()
mapper_cmd()
combiner_cmd()
reducer_cmd()
mapper_pre_filter()
combiner_pre_filter()
reducer_pre_filter()
这些可自定义的函数,大大增高了mrjob的灵活性。具体可参考 mrjob v0.5.10 documentation 使用

MRStep可将自己定义的函数对应到mapper,reducer等,如果自定义名称与官方定义一致,可不写MRStep指定。

1
2
3
4
5
6
7
8
9
10
11
12
from mrjob.job import MRJob
from mrjob.step import MRStep
class MRWordCount(MRJob):
def mapper(self, _, line):
for word in line.split():
yield(word, 1)
def reducer(self, word, counts):
yield(word, sum(counts))
if __name__ == '__main__':
MRWordCount.run()

MRStep的用途在于它可将多个map-reduce流程连接在一个.py里,上一个map-reduce的输出即为下一个map-reduce的输入,但当第二个任务还需要输入其他数据源时,就受到了限制,不知道有无解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Multi-step jobs example
from mrjob.job import MRJob
from mrjob.step import MRStep
import re
WORD_RE = re.compile(r"[\w']+")
class MRMostUsedWord(MRJob):
def mapper_get_words(self, _, line):
# yield each word in the line
for word in WORD_RE.findall(line):
yield (word.lower(), 1)
def combiner_count_words(self, word, counts):
# sum the words we've seen so far
yield (word, sum(counts))
def reducer_count_words(self, word, counts):
# send all (num_occurrences, word) pairs to the same reducer.
# num_occurrences is so we can easily use Python's max() function.
yield None, (sum(counts), word)
# discard the key; it is just None
def reducer_find_max_word(self, _, word_count_pairs):
# each item of word_count_pairs is (count, word),
# so yielding one results in key=counts, value=word
yield max(word_count_pairs)
def steps(self):
return [
MRStep(mapper=self.mapper_get_words,
combiner=self.combiner_count_words,
reducer=self.reducer_count_words),
MRStep(reducer=self.reducer_find_max_word)
]
if __name__ == '__main__':
MRMostUsedWord.run()

外部传入自定义参数

方法一

mrjob v0.5.10 documentation/ defining-command-line-options

方法二

1
os.environ.get('xxx')

需求: 有2个文件A和B,求文件A中出现了,B中未出现的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# MRDiffer.py
from mrjob.job import MRJob
from mrjob.step import MRStep
import os
class MRDiffer(MRJob):
def mapper(self, _, line):
filepath = os.environ["mapreduce_map_input_file"]
if filepath.find(os.environ.get('doc_B_dir')) >= 0:
yield line, 1
else:
yield line, 0
def reducer(self, key, values):
product = 1
for value in values:
product *= (int)(value)
if product == 1:
yield key, None
if __name__ == '__main__':
MRDiffer.run()

运行命令

1
python MRDiffer.py -r hadoop doc_A.txt doc_B.txt --cmdenv "doc_b_dir"="doc_B" -o differ_out_dir

!此外,需注意获取输入文件路径的方式,集群环境下hadoop2.x用os.environ[“mapreduce_map_input_file”]正常,在hadoop 2.x 之前需改成os.environ[“map_input_file”]。 我在local模式测试,用os.environ[“map_input_file”]正常。


linux shell

linux、windows换行符问题

参考资料: linux、windows换行符问题-作者wzb56

查看是否有换行符问题

1
cat -v file_name

出现^M,说明是\r\n。 如果会用到readlines()可能会出错,或者shell脚本运行时出现 shell “syntax error near unexpected token ‘$’\r’’”

解决办法

1
dos2unix file_name

linux 字符替换

sed

linux命令大全-sed

1
sed 's/book/books/' file

vim

CSDNBLOG-作者v1v1wang

1
:%s/book/books/g

%每一行 g当前行所以匹配到的 不加g只替换第一个匹配项

shell 命令

日期打印

1
2
3
4
5
function EchoWithTime()
{
now=`date -d 2hours +"%Y-%m-%d %H:%M:%S"`
echo "[$now] $*"
}

文件时间打印

1
filedatestr=`date +%Y%m%d -r ./xxx.png`

目录存在判断

CSDNBLOG-作者阳光岛主

1
2
3
4
if [ ! -d $conf_local_ret_path ]
then
mkdir -p $conf_local_ret_path
fi

存在返回0, 不存在返回1
-e判断文件是否存在
mkdir -p表示创建多层路径,若$conf_local_ret_path中有不存在的路径均会被创建

vim 复制多行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#复制一行
yy
p
#剪切一行
dd
p
#复制/剪切多行
ma # 移到需要复制的第一行前打ma
mb # 移到需要复制的最后一行前打mb
mc # 移到需要复制到的那行前一行前打mc
# 然后输命令
:'a, 'b co 'c #表示复制
:'a, 'b m 'c #表示剪切
#文件跳行
gg # 跳转到文件头
Shift+g # 跳转到文件末尾
:n # 跳转到第n行

linux中文乱码问题

linux里默认的字符集编码方式是utf-8

查看系统对中文的支持

1
locale -a | grep zh_CN

检测文件流编码

1
2
import chardet
chardet.detect(data)

解决方案一:

1
2
for line in f:
print(line.decode('gb2312').encode('utf-8'))

‘gb2312’是上面检测出的格式

解决方案二:

icov-linux命令大全

1
iconv file1 -f GB2312 -t UTF-8 -o file2 -c

matplotlib-3Dplot

推荐 gallery-matplotlib.org

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 以下代码没有写数据,放代码主要是说明每个函数的含义
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.font_manager as fontm
# linux下一般没有装显示相关的包,所以选择不显示
plt.switch_backend('agg')
# linux plt打印中文乱码或显示方框
# 有其他解决办法,此处选择自己下载中文字体ttc,后面使用matplotlib.font_manager指定中文字体
# 其他方法参考 [简书-作者懵琪琪7](https://www.jianshu.com/p/7b7a3e73ef21)
# [在linux中安装/卸载字体-作者wentong](http://blog.wentong.me/2014/05/add-fonts-to-your-linux/)
MicrosoftYaHei = fontm.FontProperties(fname='./Microsoft-YaHei-Light.ttc')
# dpi决定保存的图像的像素点数
fig = plt.figure(figsize=(15,6),dpi=300)
# 当你想打印多个子图在一幅图中时,分别传入位置参数121,122即可一起打印2张子图,更多张同理
ax = fig.add_subplot(111, projection='3d')
xedges = np.arange(x_len+1)
yedges = np.arange(y_len+1)
# data是个二维数据
hist = data
# xpos,ypos,zpos表示打印直方图柱子的位置
xpos, ypos = np.meshgrid(xedges[:-1]+0.25, yedges[:-1]+0.25)
xpos = xpos.flatten('F')
ypos = ypos.flatten('F')
zpos = np.zeros_like(xpos)
# dx,dy表示柱子的长宽,dz表示高度
dx = 0.5*np.ones_like(zpos)
dy = dx.copy()
dz = hist.flatten()
# color表示柱子的颜色,可传入一个颜色,也可传入与柱子数相同大小的颜色数组
# [颜色代码表](https://htmlcolorcodes.com/zh/yanse-biao/)
color = ["#F1C40F"]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=color,zsort='average')
# 加标题
ax.set_title("total: %d"% total)
# 在图中打印x,y坐标轴的label,x_labels,y_labels可自行指定
# 这里label里包含了中文,所以用fontproperties指定字体
# rotation代表标签角度
ax.set_xticks(xedges[:-1])
ax.set_xticklabels(x_labels, fontproperties=MicrosoftYaHei)
ax.set_yticks(yedges[:-1])
ax.set_yticklabels(y_labels,fontproperties=MicrosoftYaHei,rotation=15)
# 指定z轴的最小值和最大值
ax.set_zlim3d(0,max_z)
# 指定3d图的视角
ax.view_init(57,34)
# 自行指定一些文本显示在图中,ax.text(a,b,c,d) (a,b,c)表示文本位置, d表示文本内容
# 可通过其他参数设置其他属性,如fontsize设置文本字体。
for i in range(xpos.shape[0]):
if dz[i] > 0:
ax.text(xpos[i], ypos[i], dz[i], dz[i], fontsize=7.5)
for i in range(x_len):
ax.text(xedges[i+1], yedges[y_len], 0, xlabels, fontsize=6)
for i in range(y_len):
ax.text(xedges[x_len], yedges[i+1], 0, ylabels, fontsize=6)
#保存图片,bbox_inches='tight'表示去掉图片周围空白
plt.savefig("result.png,bbox_inches='tight')

python

np操作

np.narray切片

1
2
# list这样不可以
arr[:,:,0]

np 求分位数

1
np.percentile(arr, 95) #95%分位数

np.arange

1
np.arange(0,10,1)

map、filter

1
2
3
a = [1,2,3,4,5]
b = map(lambda x: x+1, a)
c = filter(lambda x: x>2, a)

np拼接数组

1
2
3
4
# 横向拼接
c = np.hstack((a,b))
# 纵向拼接
d = np.vstack((a,b))

多条件排序

1
2
3
arr = [(12, 12), (34, 13), (32, 15), (12, 24), (32, 64), (32, 11)]
arr.sort(key=lambda x: (x[0], -x[1]))
print(arr)

python error

TypeError: ufunc ‘add’ did not contain a loop with signature matching types dtype(‘S32’)

解决办法:

1
2
3
4
a = np.array(["曝光","点击", 1, 3])
print(a[2:].dtype)
b = a[2:].astype(np.int)
print(b.dtype)

python 传参

python传参三种方式-作者Daniel2333

sys.argv方式

1
2
3
import sys
file = sys.argv[0]
print(file)

argparse方式

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser(description='manual to this script')
parser.add_argument('--file', type=str, default = None)
args = parser.parse_args()
print args.file

更喜欢argparse方式,python xxx.py -h即可看到参数列表及含义


html

推荐 w3scool-html

表格

以下代码比较乱也懒得改一下了,主要是注释不同代码的功能,忽略其中强加进去的#的注释
另外,下面是用python写的部分html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sys.stdout.write('''<br />
# border=1 代表有边框, width=95% 根据页面自适应确定表格大小
# border-collapse:collapse;设置合并边框,即不是二条线夹起来的框
<table width="95%" border="1" align="center" cellpadding="2" cellspacing="0" style="border-collapse:collapse;border-color:#a8a4a4">
<tr bgcolor="#453e47">
#<p style指定各种属性
<th><font size="5"><p style="font-family:Microsoft YaHei;color:white;text-align:left;margin-left:0.2cm"> Withdrawn 图文' CTR </th>
</tr>
#表的行中嵌套表
<tr> <th>
<table width=92% border="1" align="center" cellpadding="0" cellspacing="0" style = "border-collapse:collapse;border-color:#a8a4a4;">
<tr bgcolor="#f9f7f9"><caption><font size="1"> </caption>
</tr>
<tr bgcolor="#f9f7f9"><caption><font size="5"><p style="font-family:Microsoft YaHei;text-align:center;"> 撤回图文 CTR统计 <font size="2"; color="#605f60";p style="font-family:Microsoft YaHei"> 数据时间: {0} </caption></tr>
<tr bgcolor="#f9f7f9"><caption><font size="1"> </caption></tr>
<tr bgcolor="#f9f7f9"><caption><font size="3"><p style="font-family:Microsoft YaHei;text-align:left;"> 总撤回条数:{1}</caption>
</tr>
#增加了一行空白行
<tr style="border-bottom:white;bgcolor=white"> <td> <font size="3"><p style="color:white;"> === </td> </tr>
<tr> <td style="border-bottom:white;bgcolor=white"> <font size="3"><p style="font-family: Microsoft YaHei;text-align:center;"> <U> 点击-曝光-点击率</U> 分位数分级表 </td> </tr>
<tr style="border-bottom:white;border-top:white;bgcolor=white"> <td> <font size="3"><p style="color:white;"> === </td> </tr>
#指定图片高度和宽度
<tr> <td style="border-bottom:white;bgcolor=white"> <img src="cid:flag1.png" border="0" align="middle" width="1200" height="193"/> </td> </tr>
<tr style="border-top:white;border-bottom:white;bgcolor=white"> <td> <font size="3"><p style="color:white;"> === </td> </tr>
'''.format(cur_hour, withdrawn_doc_count))
sys.stdout.write('''</table>
</td>
</tr>
</table>
<br />''')

图片

1
<img src="/i/eg_cute.png" align="middle" />

超链接

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<body>
<p>
<a href="#C4">|表格2|</a>
</p>
<h2><a name="C4">表格2</a></h2>
<p>This chapter explains ba bla bla</p>
</body>
</html>

send mail

任务用了公司内部的webservice服务。没参考价值

附sendmail服务发邮件的方法 腾讯云-作者用户1207996


End

0 Comments

理解GBDT

GBDT

GBDT的其他细节后续会写进来,以下先写上公式的推导,思考残差和负梯度,为什么用树模型去拟合负梯度

新更新

更新两篇参考资料
GBDT原理详解 - ScorpioLu - 博客园

GBDT的小结(来自论文greedy function approximation: a gradient boosting machine) - CSDN博客


0 Comments

求解L1正则化问题

求解L1正则化问题

Sub-Gradient

次梯度定义了一个新的梯度,使得不可微的点也有梯度。左导数 <= 次梯度 <= 右导数
为了避免负次梯度不是下降的方向,采用了保留当前最优点的更新方法。

参考资料 很详细

次梯度法 - 维基百科,自由的百科全书

SubGradient_百度文库

OWLQN

阅读 理解机器学习中常用优化方法 | Oath2yangmen’s Blog 中的OWL-QN部分

OWLQN说明

Proximal Gradient Descent

回顾 lipschitz 条件 及它的含义 lipschitz条件_百度百科

参考 ISTA算法求解L1正则化问题 - CSDN博客

参考 Proximal Gradient Descent

参考 Proximal Algorithm 入门 - CSDN博客

lipschitz条件限定了函数的导数存在一个上界。

PGD推导-1

PGD推导-2

所以其实Proximal Gradient Descent是将优化复杂的函数 f (x) 的问题等价转化为优化f (x)的上界问题。

Spark里L1正则问题的求解方法

以spark里线性回归求解方法为例

优化器选择支持3个选项:

a. normal : normal equation 得到解析解

b. l-bfgs

c. auto 按照后面的条件自行选择

1. 低维数据且L2正则化  -> WeightedLeastSquares via normal equation
 For low dimensional data, WeightedLeastSquares is more efficiently since the training algorithm only requires one pass through the data.(SPARK-10668)

2. 无正则项或L2正则化 -> l-bfgs

3. 其他 -> OWLQN

之前Spark还提供SGD梯度下降求解,使用L1正则时用Proximal Gradient Descent方法。

Spark PGD实现-1

Spark PGD实现-1

现在Spark 2.0.0之后建议 “ Use ml.regression.LinearRegression or LBFGS”,即前面说三个选项。

其他Spark优化器的细节可阅读 optimization-of-linear-methods-developer - Spark 2.2.1 Documentation

0 Comments

理解SVD

SVD

奇异值分解(Singular Value Decomposition,简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域,是很多机器学习算法的基石。

参考

强大的矩阵奇异值分解(SVD)及其应用

机器学习(29)之奇异值分解SVD原理与应用详解

PCA、SVD实现

Lanczos迭代就是一种解对称方阵部分特征值的方法。Spark mllib 封装了ARPACK、LAPACK库,来进行求解,使用的就是Lanczos方法。

BLAS/ARPACK/LAPACK - CSDN博客

Spark里用LAPACK求解full-svd,用ARPACK求解本地或分布式svd

矩阵求特征值和特征向量用arpack和lapack哪个好些_百度知道

不同情况下采用的实现方法及各种代价

下面这段摘自spark源码注释

  • We assume n is smaller than m, though this is not strictly required.
    • The singular values and the right singular vectors are derived
    • from the eigenvalues and the eigenvectors of the Gramian matrix A’ * A. U, the matrix
    • storing the right singular vectors, is computed via matrix multiplication as
    • U = A (V S^-1^), if requested by user. The actual method to use is determined
    • automatically based on the cost:
      • If n is small (n < 100) or k is large compared with n (k > n / 2), we compute
    • the Gramian matrix first and then compute its top eigenvalues and eigenvectors locally
    • on the driver. This requires a single pass with O(n^2^) storage on each executor and
    • on the driver, and O(n^2^ k) time on the driver.
      • Otherwise, we compute (A’ A) v in a distributive way and send it to ARPACK’s DSAUPD to
    • compute (A’ * A)’s top eigenvalues and eigenvectors on the driver node. This requires O(k)
    • passes, O(n) storage on each executor, and O(n k) storage on the driver.

最后用spark进行PCA、SVD降维实践可参考 利用PCA、SVD进行数据降维 | Oath2yangmen’s Blog


0 Comments