王子子的成长之路

王子子


  • 首页

  • 历程

  • 学习

  • 随笔

  • 关于
王子子的成长之路

改善 Python 程序的 91 个建议读书笔记 1

发表于 2017-05-15 | 分类于 学习

第 1 章 引论

建议 1:理解 Pythonic 概念

Pythonic
当你输入 import this 就会显示 zen of python

美丽胜于丑陋。
显式优于隐式。
简单比复杂好。
复合胜于复杂。
平面比嵌套好。
稀疏比密集好。
可读性是重要的。
特殊情况不足以打破规则。
虽然实用性胜过纯粹。
除了显示错误,错误永远不应该沉默。

代码风格
充分体现python动态语言的特色,类似于

# 变量交换  
a, b = b, a  
# 上下文管理  
with open(path, 'r') as f:  
    do_sth_with(f)  
# 不应当过分地追求奇技淫巧  
a = [1, 2, 3, 4]   
a[::-1] # 不推荐。好吧,自从学了切片我一直用的这个  
list(reversed(a))   # 推荐  

然后表扬了 Flask 框架,提到了 generator 之类的特性尤为 Pythonic,有个包和模块的约束:

  • 包和模块的命名采用小写、单数形式,而且短小
  • 包通常仅作为命名空间,如只含空的__init__.py文件

建议 2:编写 Pythonic 代码

避免劣化代码

  • 避免只用大小写区分不同的对象
  • 避免使用容易引起混淆的名称
  • 不要害怕过长的变量名

深入认识python有助于编写pythonic代码

  • 全面掌握 python 提供的特性,包括语言和库
  • 随着时间推移,要不断更新知识
  • 深入学习业界公认的 pythoni 代码
  • 编写符合 pep8 的代码规范(就是让你使用pycharm)

建议 3:理解 Python 与 C 语言的不同之处

  • Python 使用代码缩进的方式来分割代码块,不要混用 Tab 键和空格
  • Python 中单、双引号的效果相同(个人建议使用单引号,在面对其他语言的双引号源码时不必再转义)
  • 三元操作符:x if bool else y(原因是作者认为应该用可读性更好的方式表达)
  • 用其他方法替代 switch-case

建议 4:在代码中适当添加注释

  • 块和行注释仅仅注释复杂的操作、算法等
  • 注释和代码隔开一段距离
  • 给外部可访问的函数和方法添加文档注释
  • 推荐在文件头中包含 copyright 申明、模块描述等

另外,编写代码应该朝代码即文档的方向进行,但仍应该注重注释的使用

建议 5:通过适当添加空行使代码布局更为优雅、合理

  • 表达完一个完整思路后,应该用空白行间隔,尽量不要在一段代码中说明几件事。
  • 尽量保持上下文的易理解性,比如调用者在上,被调用者在下
  • 避免过长的代码行,超过80个字符应该使用行连接换行(还是让你使用pycharm)
  • 水平对齐毫无意义,不要用多余空格保持对齐
  • 空格的使用要能够在需要使用时强调警示读者(符合PEP8规范)

建议 6:编写函数的 4 个原则

  1. 函数设计要尽量短小,嵌套层次不宜过深
  2. 函数申明应该做到合理、简单、易于使用
  3. 函数参数设计应该考虑向下兼容
  4. 一个函数只做一件事,尽量保证函数语句粒度的一致性

Python 中函数设计的好习惯还包括:不要在函数中定义可变对象作为默认值,使用异常替换返回错误,保证通过单元测试等。

# 关于函数设计的向下兼容  
def readfile(filename):         # 第一版本  
    pass  
def readfile(filename, log):    # 第二版本  
    pass  
def readfile(filename, logger=logger.info):     # 合理的设计  
    pass  

最后还有个函数可读性良好的例子:

def GetContent(ServerAdr, PagePath):  
    http = httplib.HTTP(ServerAdr)  
    http.putrequest('GET', PagePath)  
    http.putheader('Accept', 'text/html')  
    http.putheader('Accept', 'text/plain')  
    http.endheaders()  
    httpcode, httpmsg, headers = http.getreply()  
    if httpcode != 200:  
        raise "Could not get document: Check URL and Path."  
    doc = http.getfile()  
    data = doc.read()       # 此处是不是应该使用 with ?  
    doc.close  
    return data  
  
def ExtractData(inputstring, start_line, end_line):  
    lstr = inputstring.splitlines()             # split  
    j = 0  
    for i in lstr:  
        j += 1  
        if i.strip() == start_line: slice_start = j  
        elif i.strip() == end_line: slice_end = j  
    return lstr[slice_start:slice_end]  
  
def SendEmail(sender, receiver, smtpserver, username, password, content):  
    subject = "Contented get from the web"  
    msg = MIMEText(content, 'plain', 'utf-8')  
    msg['Subject'] = Header(subject, 'utf-8')  
    smtp = smtplib.SMTP()  
    smtp.connect(smtpserver)  
    smtp.login(username, password)  
    smtp.sendmail(sender, receiver, msg.as_string())  
    smtp.quit()  
  

建议 7:将常量集中到一个文件

在Python中应当如何使用常量:

  • 常量名全部大写
  • 将存放常量的文件命名为constant.py

示例为:

class _const:  
    class ConstError(TypeError): pass  
    class ConstCaseError(ConstError): pass  
  
    def __setattr__(self, name, value):  
        if self.__dict__.has_key(name):  
            raise self.ConstError, "Can't change const.%s" % name  
        if not name.isupper():  
            raise self.ConstCaseError, \  
                    'const name "%s" is not all uppercase' % name  
        self.__dict__[name] = value  
  
import sys  
sys.modules[__name__] = _const()  
import const  
const.MY_CONSTANT = 1  
const.MY_SECOND_CONSTANT = 2  
const.MY_THIRD_CONSTANT = 'a'  
const.MY_FORTH_CONSTANT = 'b'  
  

其他模块中引用这些常量时,按照如下方式进行即可:

from constant import const  
print(const.MY_CONSTANT)  

第 2 章 编程惯用法

建议 8:利用 assert 语句来发现问题

断言的判断会对性能有所影响,因此要分清断言的使用场合:

  • 断言应使用在正常逻辑无法到达的地方或总是为真的场合
  • python本身异常处理能解决的问题不需要用断言
  • 不要使用断言检查用户输入,而使用条件判断
  • 在函数调用后,当需要确认返回值是否合理时使用断言
  • 当条件是业务的先决条件时可以使用断言

代码示例:

>>> y = 2  
>>> assert x == y, "not equals"  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
AssertionError: not equals  
>>> x = 1  
>>> y = 2  
# 以上代码相当于  
>>> if __debug__ and not x == y:  
...     raise AssertionError("not equals")  
...   
Traceback (most recent call last):  
  File "<stdin>", line 2, in <module>  
AssertionError: not equals  
  

运行是加入-O参数可以禁用断言。

建议 9:数据交换的时候不推荐使用中间变量

>>> Timer('temp = x; x = y; y = temp;', 'x = 2; y = 3').timeit()  
0.059251302998745814  
>>> Timer('x, y = y, x', 'x = 2; y = 3').timeit()  
0.05007316499904846  

对于表达式x, y = y, x,在内存中执行的顺序如下:
1. 先计算右边的表达式y, x,因此先在内存中创建元组(y, x),其标识符和值分别为y, x及其对应的值,其中y和x是在初始化已经存在于内存中的对象。
2. 计算表达式左边的值并进行赋值,元组被依次分配给左边的标识符,通过解压缩,元组第一标识符y分配给左边第一个元素x,元组第二标识符x分配给左边第一个元素y,从而达到交换的目的。

(简单来说,直接交换符合pythonic且性能最佳,这么做就对了)

建议 10:充分利用 Lazy evaluation 的特性

(就是生成器)
Lazy evaluation常被译为延迟计算,体现在用 yield 替换 return 使函数成为生成器,好处主要有两方面:

  1. 避免不必要的计算,带来性能提升
  2. 节省空间,使无限循环的数据结构成为可能
def fib():  
    a, b = 0, 1  
    while True:  
        yield a  
        a, b = b, a + b  

建议 11:理解枚举替代实现的缺陷

使用 flufl.enum 实现枚举

建议 12:不推荐使用 type 来进行类型检查

使用 isinstance 来进行类型检查(注意上下包含关系就行)

建议 13:尽量转换为浮点类型后再做除法

py2.x:转换浮点类型后再做除法

建议 14:警惕 eval() 的安全漏洞

eval具有安全漏洞,建议使用安全性更好的ast.literal_eval。

建议 15:使用 enumerate() 获取序列迭代的索引和值

>>> li = ['a', 'b', 'c', 'd', 'e']  
>>> for i, e in enumerate(li):  
...     print('index: ', i, 'element: ', e)  
...   
index:  0 element:  a  
index:  1 element:  b  
index:  2 element:  c  
index:  3 element:  d  
index:  4 element:  e  
# enumerate(squence, start=0) 内部实现  
def enumerate(squence, start=0):  
    n = start  
    for elem in sequence:  
        yield n, elem   # 666  
        n += 1  
# 明白了原理我们自己也来实现一个反序的  
def reversed_enumerate(squence):  
    n = -1  
    for elem in reversed(sequence):  
        yield len(sequence) + n, elem  
        n -= 1  
  

(此方式相比从列表里放索引取值更加优雅)

建议 16:分清 == 与 is 的适用场景

比较有趣的:

>>> s1 = 'hello world'  
>>> s2 = 'hello world'  
>>> s1 == s2  
True  
>>> s1 is s2  
False  
>>> s1.__eq__(s2)  
True  
>>> a = 'Hi'  
>>> b = 'Hi'  
>>> a == b  
True  
>>> a is b  
True  
  

为了提高系统性能,对于较小的字符串会保留其值的一个副本,当创建新的字符串时直接指向该副本,所以a和b的 id 值是一样的,同样对于小整数[-5, 257)也是如此:

注意is不相当于 ==, is 是对 id 方法做的 == 。

建议 17:考虑兼容性,尽可能使用 Unicode

python2.x 这是无敌深坑,需要刻苦学习掌握(python3偶尔也会碰到这种问题,但避免了大多数这种可能)

建议 18:构建合理的包层次来管理 module

(__init__是对包的头文件定制) 本质上每一个 Python 文件都是一个模块,使用模块可以增强代码的可维护性和可重用性,在较大的项目中,我们需要合理地组织项目层次来管理模块,这就是包(Package)的作用。

一句话说包:一个包含__init__.py 文件的目录。包中的模块可以通过.进行访问,即包名.模块名。那么这init.py文件有什么用呢?最明显的作用就是它区分了包和普通目录,在该文件中申明模块级别的 import 语句从而变成了包级别可见,另外在该文件中定义__all__变量,可以控制需要导入的子包或模块。

这里给出一个较为合理的包组织方式,是FlaskWeb 开发:基于Python的Web应用开发实战一书中推荐而来的:

|-flasky  
    |-app/                      # Flask 程序  
        |-templates/            # 存放模板  
        |-static/               # 静态文件资源  
        |-main/  
            |-__init__.py  
            |-errors.py         # 蓝本中的错误处理程序  
            |-forms.py          # 表单对象  
            |-views.py          # 蓝本中定义的程序路由  
        |-__init__.py  
        |-email.py              # 电子邮件支持  
        |-models.py             # 数据库模型  
    |-migrations/               # 数据库迁移脚本  
    |-tests/                    # 单元测试  
        |-__init__.py  
        |-test*.py  
    |-venv/                     # 虚拟环境  
    |-requirements/  
        |-dev.txt               # 开发过程中的依赖包  
        |-prod.txt              # 生产过程中的依赖包  
    |-config.py                 # 储存程序配置  
    |-manage.py                 # 启动程序以及其他的程序任务  
  

第 3 章:基础语法

建议 19:有节制地使用 from…import 语句

Python 提供三种方式来引入外部模块:import语句、from…import语句以及__import__函数,其中__import__函数显式地将模块的名称作为字符串传递并赋值给命名空间的变量。

使用import需要注意以下几点:

  • 优先使用import a的形式
  • 有节制地使用from a import A
  • 尽量避免使用from a import *

为什么呢?我们来看看 Python 的 import 机制,Python 在初始化运行环境的时候会预先加载一批内建模块到内存中,同时将相关信息存放在sys.modules中,我们可以通过 sys.modules.items() 查看预加载的模块信息,当加载一个模块时,解释器实际上完成了如下动作:

  1. 在 sys.modules 中搜索该模块是否存在,如果存在就导入到当前局部命名空间,如果不存在就为其创建一个字典对象,插入到 sys.modules 中。
  2. 加载前确认是否需要对模块对应的文件进行编译,如果需要则先进行编译。
  3. 执行动态加载,在当前命名空间中执行编译后的字节码,并将其中所有的对象放入模块对应的字典中。
>>> dir()  
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']  
>>> import test  
testing module import  
>>> dir()  
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'test']  
>>> import sys  
>>> 'test' in sys.modules.keys()  
True  
>>> id(test)  
140367239464744  
>>> id(sys.modules['test'])  
140367239464744  
>>> dir(test)  
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']  
>>> sys.modules['test'].__dict__.keys()  
dict_keys(['__file__', '__builtins__', '__doc__', '__loader__', '__package__', '__spec__', '__name__', 'b', 'a', '__cached__'])  

从上可以看出,对于用户自定义的模块,import 机制会创建一个新的 module。 将其加入当前的局部命名空间中,同时在 sys.modules 也加入该模块的信息,但本质上是在引用同一个对象,通过test.py所在的目录会多一个字节码文件。

(这节说的是,盲目使用from…import…会带来:
1. 命名空间冲突
2. 循环嵌套导入)

建议 20:优先使用 absolute import 来导入模块

(py3 中 relative import方法已被移除,不用操心)

王子子的成长之路

为什么我不需要仪式感?

发表于 2017-05-08 | 分类于 随笔

正是因为这个世界本就是混乱的、无序的
正是因为这个世界从来不存在什么天理昭昭,善恶有报
我才不想像其他人一样
在漫长幽暗的河流中,用尽全力点亮一座灯塔
告诉别人,这就是我生活的意义,生命的光辉

我的选择不需要仪式感证明
我的梦想不需要仪式感升华

我的力量在于不停的向前蠕动
而不是破茧成蝶

王子子的成长之路

YES!产品经理读书笔记 1

发表于 2017-05-04 | 分类于 学习

1.产品经理是什么

什么是产品经理
依据公司产品战略,对某个线产品担负根本责任的企业管理人员。

产品经理的职责:

  1. 根据公司战略制定所负责产品的战略和目标
  2. 根据产品情况调整产品战略和目标
  3. 根据公司战略优化产品
  4. 根据产品市场反馈为高层提供决策建议
  5. 指定有效的竞争分析和竞争策略
  6. 对现有产品和新产品进行管理

产品经理的任务

  1. 竞争对手分析
  2. 产品组合管理
  3. 产品品牌管理
  4. 市场需求管理
  5. 规划和指定相关的产品策略
  6. 产品所需资源管理
  7. 指定营销策略

2.产品经理应该做什么

知道做什么

  1. 发现问题:找到市场需求
  2. 找到机会:找准市场位置
  3. 创新产品:指定产品发展思路

不认同:
> 做对的方向的乌龟,不做错的方向的兔子

知道怎么做

  1. 规划产品路线:产品目标是什么
  2. 设计产品策略:实现目标的方向
  3. 制定年度计划:如何逐步靠拢

选择做的东西,最直接的指标是盈利能力评估

3.产品经理的战术执行

让别人去做

  1. 方向引导:制定发展规划
  2. 过程管理:控制环节入口和出口,保证实现过程规范化
  3. 工作指导:注重其他细节

4.产品管理职业的级别都有哪些

  • 产品助理:业务执行岗,数据收集和分析
  • 产品经理:对企业发展做出合理判断。战略、规划、执行占2:3:5
  • 高级产品经理:战略层面的规划。战略、规划、执行占2:3:5

5.产品经理的职业发展路线

SM:销售管理
MM:营销管理
BM:商业管理

7.什么样的人适合做产品经理

  1. 有成本意识:能为公司削减成本
  2. 有销售意识:能为公司挣钱
  3. 有团队意识:团队协作
  4. 有全局意识
  5. 不会抱怨:能力未到
  6. 不夸夸其谈
  7. 不喜欢加班
  8. 注重倾听

8.产品经理的人才模型

加分项:

  1. 独立思考能力
  2. 态度上,坚持自己想法

能力和态度二选一时,选择后者

产品经理素养

1.个人素养

  • 个人修养
  • 创新能力
  • 沟通协调能力
  • 自我管理能力
  • 工作压力承受能力

管理知识

  • 战略知识管理
  • 团队管理知识
  • 时间管理知识
  • 项目管理知识

核心能力

  • 产品需求管理
  • 产品项目管理
  • 新产品管理
  • 产品生命周期管理
  • 产品规范管理

9.产品经理的知识结构是什么

图看不清

10.产品经理是“通”才还是“专”才

通的是方法和过程,专的是方向和目的

11.产品助理应该做些什么

  1. 数据整理:收集各类市场、产品、客户、竞争对手有关的数据。
  2. 文档管理:各类文档统一的入口和出口。
  3. 事务性工作:组织部门会议。

12.产品经理应该知道的产品战略图

产品线的规划

  1. 归纳目前产品线
  2. 根据特征对产品分类
  3. 评估生命周期
  4. 评估产品之间的关系
  5. 形成文档,即产品战略图(PST)

产品图不管怎么表现,需要体现四个方面的信息

  1. 产品线信息
  2. 产品生命周期阶段信息
  3. 产品组合信息
  4. 产品信息

13.产品管理有行业特殊性吗

产品管理在不同行业上的共性

  1. 无论哪个行业,根本工作都是给企业规划处有持续盈利能力的产品(目的相同)
  2. 无论哪个行业,都是为企业创造价值(内容相同)
  3. 无论哪个行业,都需要先知道市场要什么,后规划如何满足需求,在用用企业提供的产品去满足我们认为需要满足的需求,实现价值交换。(流程相同)

产品经理要让企业资源增值

没有不做需求分析的企业,没有不做市场细分的企业,没有不做客户定位的企业

很多时候,看到的不一定是真相,共识的不一定是真理,存在也不是我们要坚持的

14.产品经理是否有行业性限制

鲍尔默的商业规则

  1. 一个公司,只有市场份额和现今流最重要
  2. 技术只是竞争优势,不是决胜优势
  3. 一切以客户和消费者作为企业的经营原则
  4. 一切以客户需求开发产品
  5. 找出问题!开动大脑!拿出方案!坚持执行!勇往直前!

产品经理最终要提高的是商业运作能力

(但是商业运作能力本身也是很虚的东西)

15.技术人员如何转型为产品经理

  1. 了解自己是否真的不适合做技术工作
  2. 全面了解产品经理的工作,评估自己是否真的对这个工作有兴趣
  3. 岗位和思维都要转,要从懂产品变成懂业务
  4. 了解公司产品管理体系架构
  5. 从实践中获取第一手的市场业务信息

16.产品管理的工作流程是什么

战略活动

  1. 预测问题
  2. 培育机会
  3. 创新产品
    ### 规划活动
  4. 产品路线
  5. 产品策略
  6. 产品规划
    ### 战术活动
  7. 概念化
  8. 图纸化
  9. 技术化
  10. 商品化
  11. 市场化

PRD:产品需求文档
MRD:市场需求文档

image_1bekb9u1miibsp22co130nt459.png-95.3kB
image_1bekbb1n210s51r7n15qk7t3f61m.png-146.5kB

17.产品管理工作的文档管理

文档作用

  1. 记录介质
  2. 过程推动
  3. 抽象体现

文档类型

  1. 流程类
  2. 控制类
  3. 决策类

文档的规范

  1. 文档模板规范
  2. 文档编号规范
  3. 文档存取规范
  4. 文档撰写规范
  5. 文档级别规范

18.产品经理需要了解的26个文档

image_1bekc88kv19af1fap1mht1g26aro1g.png-363.4kB
image_1bekc92221rdi1c461t38jqffga1t.png-244.3kB
image_1bekca8h21ac61ai716c33fhehc2a.png-208kB

10个必须要写的文档

D3:需求矩阵表
D9:商业方案(必须精通)
D12:产品路线文档
D15:产品策略文档
D18:商业需求文档(必须精通)
D19:市场需求文档(必须精通)
D20:产品需求文档(必须精通)
D21:产品验收文档
D24:产品白皮书
D25:产品总结报告

19.产品管理部归于何处

懂的多只能说明你的知识丰富,爱学习。只有做的好才说明你能力强悍,货真价实。

任何一次变革都是对现有利益的重新分配,这是方法,又是目的。

用户购买一个产品的流程:
1. 发现的过程:知道我们宣传的产品价值是否和他期望的利益一致。
2. 选择的过程:让用户选择我们的产品而不是竞争对手产品
3. 购买的过程:寻找性价比最高的产品
4. 使用的过程:决定是否购买

20.产品部和业务部门的利益之争

不停的妥协和不停的打压都是不可取的

在关系的夹缝中,要做到不偏不倚,实事求是

王子子的成长之路

sklearn学习笔记-3 回归模型

发表于 2017-04-26 | 分类于 学习

回归模型:

线性回归模型

感知器模型

最简单的模型,多层感知器MLP即最简单的深度学习网络。
感知器模型通过循环修正计算误差进行修正,因此没有没有学习率;在学习中,需要指定学习次数(例如学习样本数),否则感知器模型会无休止的进行下去。
基础(单层)感知器模型是非常弱的模型,不会存在过拟合的情况。

sklearn.linera_model.Perceptron(penalty=None, alpha=0.0001, fit_intercept=True, n_iter=5,   shuffle=True, verbose=0, eta0=1.0, n_jobs=1. random_state = 0, class_weight=None,   warm_start=False)  

参数

  • penalty:正则惩罚项,默认为0
  • fit_intercept:截距
  • n_iter:迭代次数
  • shuffle:洗牌
  • verbose:打印日志等级
  • eta0 :学习率
  • n_jobs:启动线程数,-1代表最大

实例

df = pd.read_csv(r'D:\BaiduYunDownload\sklearn\3.0 线性模型\adultTest.csv')  
#将object变量(字符串)制成稀疏矩阵,class是目标变量,不用放入  
dfNew=pd.get_dummies(df,columns=['workclass','education','marital-status','occupation','relationship','race','sex', 'native-country'])  
  
dfNew['target'] = dfNew['class'].apply(lambda x: 1 if x == r' <=50K' else 0)  # 将结果二分为1和0  
xdata = dfNew.drop(['class','target'],axis = 1)  # 测试集  
ydata = dfNew['target']  # 结果集  
  
from sklearn.linear_model import Perceptron  # 调用感应器模型函数  
per = Perceptron(n_iter=20)  # 创建对象并设定迭代次数为20  
per.fit(xdata,ydata)  # 训练模型  
print(per.predict(xdata))  # 对模型进行预测  
print(per.score(xdata,ydata))  # 对模型进行准确率评估  

tips:感知器没有概率值

线性回归模型

sklearn.linear_model.LinearRegression9(fit_intercept = True, normalize = False, copy_X = True, n_jobs = 1)  

fit_intercept:是否计算截距
normalize:是否对整个样本进行数据标准化,线性模型并不依赖于正则,所以此参数无意义。

线性回归模型需要接受一个连续性的变量,以达到预测。

在线性模型中,更复杂的模型会用到alpha惩罚项,简称a,并且会通过数据集的定义方式选择raige函数和lasso函数。

raige和lasso的区别

raige接受l2的正则,lasso接受l1的正则。
raige:(w1)2+(w2)2+(w3)^2…,每个权重平方相加;lasso:|w1|+|w2|+|w3|…,每个权重绝对值相加。
lasso接受的l1范数,所以得到的解可能是稀疏的,导致很多系数的权重都为0;raige接受l2的范数,得到的解不会为0。
从方便的角度考虑,我们更多的使用l2范数的raige。

交叉验证(Cross validation)
交叉验证用于防止模型过于复杂而引起的过拟合。有时亦称循环估计,是一种统计学上将数据样本切割成较小子集的实用方法。于是可以先在一个子集上做分析,而其它子集则用来做后续对此分析的确认及验证。交叉验证是一种评估统计分析、机器学习算法对独立于训练数据的数据集的泛化能力(generalize)。
在sklearn的在线性模型中,为了保证模型值,我们可以使用后续加CV的函数来进行交叉验证:

alpha:接受一个数组,数组内是所有认为有效的a的值,函数会自动选择最优值
cv:接受交叉验证的切分份数
scoring:评估指标,不填写会选择默认指标进行判断,也接受填写最小绝对值误差/最小均方误差,一般不填写
其他同上

在进行CV时,有时可能会遇到被切分的样本内没有1,或者样本不均匀的问题,因此我们调用分层函数进行解决:

from sklearn.cross_validation import StratifiedKFold#调用分层函数  
sf = StratifiedKFold(ydata,n_folds=5)  # 创建对象并选择分为几层,避免发生稀疏矩阵的数据不均匀的问题  

这种情况在分类模型中才会发生,回归模型的y是连续值,因此不必进行分层。

王子子的成长之路

sklearn学习笔记-2 数据处理

发表于 2017-04-17 | 分类于 学习

稀疏和非稀疏

在矩阵中,若数值为0的元素数目远远多于非0元素的数目时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。稀疏被称为L1,非稀疏被称为L2。

2.1 数据标准化

  • 特征决定了模型的上限,算法决定了如何逼近这个上限
  • 对业务了解的越多,提出的特征越好
  • sklearn的数据处理能力现在非常强大,能处理文本、图片或更多的数据
  • 在数据量纲不一样时,需要对数据进行标准化,一般来说,涉及到梯度下降的模型,和涉及到距离的模型,都需要做数据标准化。

定义
标准化1(常用的标准化):减去一列的平均数再除以标准差,使其符合平均数为0标准差为1的高斯分布。
标准化2:压缩数据至0到1
树类模型不需要标准化。
标准化不能在训练集和测试集上分开进行(两个集的平均数和标准差不同),应当在测试集上应用训练集的标准化(减去标准化的平均数,除以标准化的标准差)。
把训练集和测试集放在一起做标准化也不是一种较好的办法,最优的办法是在训练集上做标准化,并transform到测试集中。

scale

用于针对列的数据标准化

函数
sklearn.preprocessing.scale(X,axis=0,with_mean=True,with_std=True,copy=True)
X传入数组,支持pandas数据框,axis=0按列处理,mean=True平均数接近0,std=True标准差接近1
方法
sklearn.preprocessing.StandarScaler(with_mean=True,with_std=True,copy=True)
相比方法,函数很少被用到,因为该方法没有transform接口。
当数据不以时间为顺序时,可以随机划分训练集和测试集。

随机划分数据集

from sklearn.cross_validation import train_test_split#调取切割函数  
X_train, X_test, y_train, y_test = train_test_split(df1,df['area'],train_size=0.7)   # 数据参数,数据结果,切分为测试集的比例  
# X_train是被切分为训练集的比例,X_test是被切分为测试集的比例,y相同  

在一个函数内训练两个集,目的是为了不破坏索引顺序

标准化数据1(正态数据)  
from sklearn.preprocessing import StandardScaler#调取标准化函数  
ss=StandardScaler()#创建标准化对象  
ss.fit(X_train)#以训练集训练标准化对象  
X_train_ss=ss.transform(X_train)#将训练结果应用于训练集  
X_test_ss=ss.transform(X_test)#将训练结果用于与测试集  

此时,返回的结果都是numpy形式的多维数组。
每一组的平均值无限接近于0,标准差无限接近于1。

标准化数据2(压缩数据)  
from sklearn.preprocessing import MinMaxScaler#调取压缩函数  
mms = MinMaxScaler()#创建标准化对象  
mms.fit(X_train)#依然以训练集训练标注化对象  
#...  

以上标准化方法,都是对每一列(每一个特征进行标准化)

normalize

对整个样本进行数据标准化(正则)

函数
sklearn.preprocessing.normalize(X, norm=‘12’, axis=1 ,copy=True, return_norm=False)
方法
sklearn.preprocessing.Normalizer(norm=‘12’, copy=True)

normalize针对样本,但样本间是独立的,因此该方法的transform无意义(整个样本都被转换了,单个使用时就不必transform),只会在papline中有意义。
该方法只会用于计算距离、无监督学习的聚类中使用。默认接受L2 (稠密矩阵)

from sklearn.preprocessing import  Normalizer  # 调用正则函数  
norm = Normalizer()  # 创建初始化对象  
norm.fit((X_train))  # 虽然无意义,仍需要按照标准书写  
norm.transform(X_train)  # 虽然无意义,仍需要按照标准书写  
norm.transform(X_test)  # 虽然无意义,仍需要按照标准书写  

2.2 分类值与缺失值

binarizer

用作数据二分化的分类,将一个连续性变量改为离散变量。

数据离散化的好处:数据存储空间小,并且因为0不参与运算(相加为原值,相乘为0)使运算速度非常快。
离散化也能较好的处理缺失值,可以将缺失值单独的形成一个特征,出现缺失值的行为1.
逻辑回归非常偏好离散化完成的数据

from sklearn.preprocessing import Binarizer#调取二分数据函数  
bi = Binarizer(548)#创建对象定义分类标准,大于该值会被分为1,小于为0  
DC_bi=bi.fit_transform(df['DC'])#调用对象进行分类  

当使用一列表示象征性的分类时,不要使用数字,因为程序sklearn会认为该特征的大小和顺序是有意义的,正确的做法是对少量参数进行稀释矩阵。
构建稀疏矩阵:skleran的OneHotEncoder非常不好用还容易报错,因此我们使用pandas的get_dummies()。

pd.get_dummies(data=df, columns=['month','day','DC_bi'])  

缺失值

缺失值有时是真实存在的,缺失是存在意义的,并且当数据不够大时,删除缺失值只会浪费样本。
因此,更好的方式是填充缺失值,填充方式尽量通过业务的理解来进行填充。

from sklearn.preprocessing import Imputer#调用填充缺失值函数,该函数默认填充平均值  
im=Imputer()#创建对象  
dfna=im.fit_transform(df['DC_na'])#选出需要填充的列并输出列  

Tips:
1. 这里有错误,训练出来的列长度并不等于原来的长度,因此还是寄希望于pandas来处理
2. sklearn有些函数不支持缺失值或无限大、无限小的数据,因此通过pandas将此类数据设为缺失值,并且一次性的处理它。
3. 缺失值可以使用-999代替。

2.3 变量选择

特征选取

共线性特征,只保留一个就可以,可以用皮尔逊共线测试一下。
当特征过多时,只保留重要特征,删除掉不重要的参数也可以提高准确率。

针对稀疏矩阵判断特征的两种方式:
1. 使用lasso来选择特征

from sklearn.linear_model import Lasso  # 从线性模型这种调取能判断参数重要性的函数lasso()  
lasso = Lasso()  # 创建对象  
lasso.fit(xdata,ydata)  #   fit不接受缺失值,使用前记得填充缺失值为-999。第一个参数为参数df,第二个参数为结果df  
print(lasso.coef_)  # 打印特征重要程度,可以删除无限接近于0的特征  

所有的稀疏矩阵类型,都可以放入此函数进行判断。

  1. 使用featureselect来选择特征:

    from sklearn.feature_selection import SelectFromModel  # 调用参数选择模型  
    model = SelectFromModel(lasso)  # 创建对象并直接传入模型,相当于省略了fit步骤  
    model.fit_transform()  # 无意义,为了是一个popline,另外sklearn不接受异常值,这里因为极大和极小值的存在,会报错。  

支持LR回归,简单线性回归
当特征是连续性,我们希望方差越大越好

特诊判断

基于树形模型对特征进行判断:

from sklearn.ensemble import RandomForestRegressor#从随机森林库中调取树类特征选择函数  
rf = RandomForestRegressor()#创建对象  
rf.fit(xdata,ydata)#训练模型,第一个参数为参数df,第二个参数为结果df  
print(rf.feature_importances_)#打印特征重要程度,数值越接近于0,意义越小  

提到的pandas相关操作

.head():读取前五行数据
df.loc[ : ,x:y]:索引选取x到y列的数据
df[0, : ]维度转换
pd.cut(df[‘’],n):将padans中的一列均匀的切分成n份,返回的值是一个字符串。
pd.get_dummies(data, prefix = None, prefix_sep = ’_’, dummy_na = False, columns=None, sparse = False, drop_first = False):函数接受一个df表格以及使用columns选取的列,函数会删除原来的列并对其进行稀疏化矩阵的扩充,使其变为0/1形式,返回一个重新构建好的df表格。
df.loc[df[‘DC’]>=600,‘DC_na’] = np.nan :对df行中的DF列大于等于600的,新建一列设为NaN。
df.replace(np.inf,np.nan):替换过大值为NaN

1234
王子子

王子子

天生极客

18 日志
4 分类
GitHub 知乎
Friends
  • andrewwang
© 2017 王子子
由 Hexo 强力驱动
主题 - NexT.Pisces