Contents

帅地

Contents

参考资料

基础面试题

什么是 Python

  • 解释型脚本语言, 通过解释器执行, 速度通常慢于编译型语言
  • 动态类型语言, 变量声明时无需指定类型
  • 支持面向对象编程, 可通过组合与继承定义类
  • 强类型语言, 不兼容的类型操作会引发 TypeError(如 "1" + 2

赋值、浅拷贝、深拷贝

  • 赋值

    Python 中的赋值是简单的 对象引用, 不会创建新对象
    b=a, 则 a 和 b 指向同一片内存空间, 可以使用 id() 查看。所以修改 a, b 会跟着改变

  • 浅拷贝

    三种形式:

    • 切片操作:b = a[:] 或者 b = [x for x in a]
    • 工厂函数:b = list(a)
    • copy 函数:b = copy.copy(a)

    以上操作都会创建新对象, 通过 id() 查看 b 和 a 的内存空间是不同的

    注意:若 a 里面有 嵌套的列表, 它们指向的位置还是一样的
    即对 a 中的列表进行修改, b 对应的也会改变

  • 深拷贝

    b = copy.deepcopy(a)

    b 是全新的对象, 递归复制所有层次, 与 a 没有任何关联
    这意味着时间、空间开销更高

对数字、字符串等不可变对象,copy 通常返回原对象本身,但逻辑上无副作用

变量、对象、引用

  • 变量是访问对象内存空间的符号(指针)
  • 对象是一块内存及其代表的值
  • 引用是从变量到对象的连接

Python 使用变量时不需要提前声明变量及其类型, 为什么?
例如:a = 1, 在给 a 赋值时就创建了它, 步骤是先创建一个对象, 其值为 1;然后创建一个变量 a;再将变量 a 与该对象连接
类型属于对象,变量本身没有类型

生成随机数

1
2
3
4
5
6
7
8
import random
random.random()            # [0.0, 1.0) 浮点数
random.uniform(a, b)       # [a, b] 浮点数
random.randint(a, b)       # [a, b] 整数
random.choice(seq)         # 从序列中随机取一个元素

# 正态分布
random.gauss(mu, sigma)    # 均值为 mu,标准差为 sigma

解释型与编译型

计算机不能直接理解高级语言, 需要 翻译成机器语言

解释型语言在 运行程序 时逐条翻译并执行
编译型语言在执行之前需要一个 专门的编译过程, 把程序编译成机器语言(可执行文件)

Python 的作用域

搜索顺序:

  • Local, 本地作用域
  • Enclosing Local, 当前作用域被嵌入的本地作用域
  • Global, 全局作用域
  • Built-in, 内置作用域

Python 自省

即自我检查能力

dir(obj) – 返回属性名列表
type(obj) – 返回对象类型
getattr(obj, name) – 获取属性值
hasattr(obj, name) – 是否拥有某个属性
isinstance(obj, cls) – 是否为某类型的实例

Python 的代码规范

PEP 8 编码规范,可使用 pycodestyle、flake8 检查

Python 提升性能的手段

CPU 密集型任务使用多进程,避免 GIL
核心代码用 C/C++ 编写并封装

I/O 密集型使用异步(asyncio)或 IO 多路复用

尽量使用内置函数、局部变量

字典的 items() 与 iteritems()

Python 3 中 items() 返回动态视图对象,既节省内存又反映字典变化。如果要获取静态列表,可用 list(d.items())
iteritems(), 类似, 返回的是一个 迭代器

内存不够怎么存储大量数据

  • 通过生成器, 分多次读取

  • 通过 linux 命令将数据进行分割

    • 指定分割后的文件行数

      split -l 300 large_file.txt new_file.txt

    • 指定分割后的文件大小

      split -b 10m large.log small.log

os.path 和 sys.path

os.path 处理文件路径(拼接、拆分、判断是否存在等)
sys.path 是 Python 模块搜索路径的列表

os 模块

文件操作(remove, rename)、目录操作(mkdir, listdir)、路径(path.join, path.abspath)、权限等

字典与 JSON

字典:键(key)必须是可哈希的类型,值可以是任意对象
JSON:文本格式,键必须是双引号字符串

可变、不可变类型

可变, 内存中的值可以改变, 例如:列表、字典、集合【记可变的就可以】 不可变, 内存中的值不能改变, 例如:数字、字符串、元组等等

字典

从 Python 3.7 起字典保持插入顺序。如需按 Key/Value 排序,可使用 sorted(d.items())

反斜杠 \

用途:

  • 转义字符

    \n\t

  • 路径分隔符(Windows)

  • 行连接符:长语句换行

Python 部分常用标准库

os, sys, time, random, threading, multiprocessing, queue, sqlite3, json, re 等

Python 的内存管理

所有 Python 对象(包括整数、字符串、列表、类实例等)和数据结构都存放在一块 私有堆空间(private heap)
开发者无法直接操作这块堆空间,必须通过 Python 的 API 间接访问

  • Python 内存管理器并非单一组件,而是一个 分层结构

    层级 职责
    最底层 操作系统的 malloc/free(C 标准库)
    中间层 pymalloc(Python 专属的内存分配器,针对小块内存优化)
    最上层 面向 Python 对象的分配接口(如 PyObject_Malloc

    其中 pymalloc 是关键,它将大块内存从操作系统申请来,再切分成内存池Arena
    高效地为小对象分配内存,避免频繁调用系统 malloc

  • Python 的垃圾回收 不是单一机制,而是 双机制 配合:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    ┌──────────────────────────────────────────────┐
    │          Python 垃圾回收机制                 │
    ├────────────────────┬─────────────────────────┤
    │  ① 引用计数        │  ② 循环垃圾收集器 (GC)  │
    │  (Reference Count) │  (Cyclic GC)            │
    ├────────────────────┼─────────────────────────┤
    │ • 主要机制         │ • 辅助机制              │
    │ • 实时回收         │ • 定期运行              │
    │ • 引用=0立即释放   │ • 解决循环引用问题      │
    │ • 无法处理循环引用 │ • 分代收集(3代)         │
    └────────────────────┴─────────────────────────┘
    
    • 引用计数

      • 每个对象内部维护一个引用计数器 ob_refcnt
      • 引用增加 → 计数+1;引用减少 → 计数-1
      • 计数归零 → 立即 释放内存
      • 致命缺陷:无法处理循环引用
    • 循环垃圾收集器(辅助机制)

      • 专门解决循环引用问题(如 a.next = b; b.next = a
      • 采用 分代收集 策略(3 代:第 0 代、第 1 代、第 2 代)
      • 新创建的对象放入第 0 代,经过多次回收仍存活则晋升到更老的代
      • 老代对象检查频率更低,提升效率

    回收的内存不一定会还给操作系统
    回收的内存首先回到 Python 内存管理器(pymalloc 的内存池)
    pymalloc 倾向于持有这些内存,供未来的 Python 对象复用
    不一定会立即返还给操作系统(这正是很多 Python 进程内存"只增不减"的原因)

    1
    2
    3
    4
    
    import gc
    
    gc.collect()       # 手动触发循环GC
    gc.get_threshold()  # 查看分代阈值,默认 (700, 10, 5)
    

修改不可变数据的后果

代码不会正常运行, 抛出 TypeError 异常

模块和包是什么?

Python 中 每个代码文件都是模块, 模块可以引用其他模块
包含 __init__.py 的目录,可存放多个模块和子文件夹

什么是正则的贪婪匹配?

.* 贪婪匹配会匹配满足条件的最长的字符串
.*? 非贪婪则尽可能短

面向对象的属性查找顺序

当子类继承多个父类时, 属性查找方式分为:

  • 深度优先:经典类的属性查询方式

  • 广度优先:新式类的属性查询方式

  • Python2.x

    经典类:不由任何内置类型派生出来的类 新式类:不由任何内置类型派生出来的类

  • Python3.x 之后

    均为新式类, 不过也不用广度优先, 而是 C3 线性化算法

怎么实现矩阵乘法?

Python 中可用 numpy.dot(A, B)A @ B,也可用三重循环实现

any() 和 all()

any(iterable):至少一个元素为真返回 True

all(iterable):所有元素为真返回 True

__init__ 方法

类的构造方法,在实例化时自动调用,用于初始化对象属性

apply 和 map 的区别

apply 在 pandas 中可沿 DataFrame 的行或列应用函数(已逐渐被更明确的函数取代)
map 是 Series 的方法,用于元素级映射

数组和列表的区别

数组(array 模块或 numpy.array):元素类型相同,存储紧凑,计算高效
列表:可包含任意类型,灵活但内存开销大

用栈实现一个队列

  • 栈:后进先出。就像 叠盘子,最后放上去的盘子最先被拿走

  • 队列:先进先出。就像 排队买饭,最先排队的最先打到饭

    我们的目标是:用两个“后进先出”的栈,拼出一个“先进先出”的队列。

想象有两个窄口瓶子(栈),瓶口只能进出最上面的球

  1. 你依次把 红、黄、蓝 三个球放进 1 号瓶(入队栈)。
  2. 此时 1 号瓶最上面是蓝球,如果你直接拿,拿到的是蓝球(不符合队列的先进先出,应该拿红球)。
  3. 关键操作来了:你把 1 号瓶里的球,一个一个全倒进 2 号瓶(出队栈)。
  4. 倒的过程中,蓝球先进 2 号瓶,然后黄球,最后红球压在最上面。
  5. 此时 2 号瓶最上面的是红球!你从 2 号瓶拿球,第一个拿到的就是最早进去的红球。这不就是先进先出吗!

进程、线程、协程

进程:资源分配的基本单位,相互独立

线程:CPU 调度的基本单位,共享进程内存,受 GIL 限制

协程:用户态轻量级“线程”,通过 async/await 实现协作式多任务

Python2 与 Python3 的区别

print 变为函数
整数除法返回浮点数
默认字符串为 Unicode
range() 返回 8 而不是列表
移除 iteritems()

进阶面试题

类方法、类实例方法、静态方法

实例方法:def method(self),操作实例属性

类方法:@classmethoddef method(cls),操作类属性

静态方法:@staticmethod,不依赖类或实例,逻辑上归类的函数

内存管理机制、调优手段

引用计数:对象引用数为 0 时释放,循环引用无法回收

垃圾回收:标记清除处理循环引用;分代回收提高效率

内存池:Python 对小对象(≤256 字节)使用私有内存池 pymalloc,减少频繁 malloc/free

内存泄漏

指的是由于疏忽或错误造成的 程序未能释放已经不再使用的内存 的情况
这会导致程序运行 速度减慢, 系统崩溃

如何防止:当一个对象不使用时, del object 来删除它的 引用计数
可以通过 sys.getrefcount(object) 获取对象的引用计数, 并小心循环引用

函数调用时, 参数传递的方式

能不能在“原处”修改?核心要看 这个数据能不能在不改变它内存地址的情况下,修改它里面的内容

  • 可变类型(比如:列表、字典、集合)

    假设你建了一个腾讯文档(列表),把链接发给了别人。别人点开链接,在文档里加了一句话。这时候你打开你的文档,你会发现内容也变了!因为你们看的是同一个文档

    当你把一个可变变量传给函数时,相当于 把存放数据的抽屉的钥匙递给了函数
    函数拿着钥匙打开同一个抽屉,往里面塞东西或者拿东西。你再去开抽屉,看到的就是被函数改动后的样子
    代码表现:引用传递(不拷贝,传地址)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    def change_list(my_list):
        my_list.append(4)  # 函数内部直接在原列表里加了个4
        print(f"函数内的my_list: {my_list}")
    
    b = [1, 2, 3]
    change_list(b)
    print(f"函数外的b: {b}")
    # 输出结果:
    # 函数内的my_list: [1, 2, 3, 4]
    # 函数外的b: [1, 2, 3, 4]   <--- 原件被改了!
    
  • 不可变类型(比如:整数、浮点数、字符串、元组)

    假设你有一块刻着“5”的石头,你把它交给别人。别人想把它变成“6”,他能不能直接在“5”上面刻一笔? 不能,因为石头刻好了就不能改(不可变)。他唯一的办法是 找一块新石头,刻上“6”

    当你把一个不可变变量传给函数时,相当于复印了一份给函数
    函数里无论怎么折腾,改的都是那份复印件,你的原件毫发无损
    代码表现:值传递(拷贝)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    def change_number(num):
        num = 100  # 函数内部试图修改,实际上是创建了一个新的100,把num指向了100
        print(f"函数内的num: {num}")
    
    a = 5
    change_number(a)
    print(f"函数外的a: {a}")
    # 输出结果:
    # 函数内的num: 100
    # 函数外的a: 5   <--- 原件没变!
    
  • 为什么不可变类型要拷贝,可变类型不拷贝呢?

    1. 不可变类型通常很小(一个数字、一个短字符串),拷贝一份成本极低,而且为了安全(防止函数乱改外面的值),拷贝是更好的选择。
    2. 可变类型可能非常大(一个包含 10 万个元素的列表,或者一个庞大的字典)。如果每次调用函数都拷贝一份,内存会瞬间爆炸,程序会卡死。所以 Python 选择不拷贝,直接传地址,大家共享一份数据。

为什么函数名可以当参数用

Python 中函数是一等对象,函数名是引用函数对象的变量,因此可以像其他对象一样传递

  • 一等对象的一些用法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    def greet():
        print("你好!")
    
    # ✅ 1:赋值给变量
    say_hello = greet          # 给同一个函数对象再贴一个标签
    say_hello()                # 输出:你好!
    
    # ✅ 2:作为参数传给函数
    
    # ✅ 3:作为函数的返回值
    def get_greeter():
        return greet           # 返回函数对象本身,不是调用结果
    
    my_func = get_greeter()
    my_func()                  # 输出:你好!
    
    # ✅ 4:存储在数据结构中
    strategies = {
        "加法": add,
        "乘法": multiply
    }
    print(strategies["加法"](3, 4))   # 7
    

整数、字符串、列表……都是一等对象,但关键来了——在 Python 中,函数也是一等对象!
函数和整数、字符串享有完全相同的地位

这可不是所有语言都这样的,比如在 C 语言中,函数就不是一等对象(不能把函数直接传来传去,得用函数指针)

函数名即函数本身?不对。更准确的类比是:
函数名 = 贴在函数上的标签(便利贴)
函数对象 = 真正的代码和数据

1
2
3
4
5
def greet():
    print("你好!")

print(greet)        # <function greet at 0x7f8a1c3e5e50>
print(type(greet))  # <class 'function'>

greet 这个名字,指向的是一个内存地址0x7f8a...),它的类型是 function
所以变量名只是个标签,贴在真正的对象上。

  • 最经典的用法——回调函数

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    # 定义两个"策略"函数
    def add(a, b):
        return a + b
    
    def multiply(a, b):
        return a * b
    
    # calc 是一个通用计算器,具体用什么策略,由你传进来的函数决定
    def calc(a, b, operation):  # operation 就是接收函数名的参数
        result = operation(a, b)  # 调用传进来的函数
        return result
    
    print(calc(3, 4, add))       # 传 add 进去 → 7
    print(calc(3, 4, multiply))  # 传 multiply 进去 → 12
    

    注意看 calc(3, 4, add)——这里 add 没有加括号

    • add → 传递的是函数对象本身(递菜谱)

    • add() → 调用函数,执行它(按菜谱做菜)

      这就是为什么说"函数名是引用函数对象的变量"——你传的是那个标签,接收方拿到标签后,自己去找到真正的函数对象来执行

pass 语句

编写代码时只写框架思路, 先用 pass 占位, 保持语法完整性,程序不会报错

super() 作用

super() 是用在 多继承中避免重复调用父类

单继承的情况下, 直接用 类名调用父类(Base 类)的方法是没问题的
多继承的情况下, 会涉及到 查找顺序(MRO)、重复调用(钻石继承) 的问题

异常处理

1
2
3
4
5
6
7
8
try:
    # 可能出错的代码
except SomeError:
    # 处理异常
else:
    # 无异常时执行
finally:
    # 始终执行(清理资源)

在 try-except 中, 若没有出现问题则 except 不会执行, 那么将会执行 else 中的内容, 总之 except 和 else 二选一

若 try 的异常 没有通过 except 指出, 系统 还是会报错 Traceback, 且终止程序
但是此时若有 finally 语句, 则系统在报错之前还会执行 finally 中的内容
一般 finally 中会时 释放文件句柄、内存空间 等操作

递归函数停止的条件

一般定义在 递归函数的内部, 递归调用之前要做一个 条件判断, 判断结果分为继续调用还是 return

回调函数是如何通信的

回调函数, 把函数的指针作为参数传递给另一个函数。将整个函数作为一个对象, 赋值给调用的函数 简单讲就是 一个函数作为另一个函数的参数被传入, 那么这个函数叫做回调函数

注意不同于程序设计中的回调
在回调机制中,向第三方提供一个用于接收回调的接口或方法,当特定事件发生时,第三方会调用该接口或方法,传递相关参数,从而触发我们的代码执行
用于处理异步操作或事件触发

抽象类、接口类

抽象类(abc.ABC):可以包含具体方法,不能直接实例化 抽象类:毛坯房, 对比普通类来说 约束性更强

接口:仅定义方法签名,Python 可通过抽象基类模拟

方法重载和方法重写

重载:在同一个类里面, 方法名字相同, 参数不同。让类以统一的方式处理不同类型数据

重写:子类继承父类的方法 并进行一定的修改, 又叫方法覆盖

函数装饰器的用途

装饰器本质上是一个 返回函数的函数
作用是让其他函数在 不需要做改动下 增加额外的功能, 减少与函数功能本身无关的雷同代码

用于有切面需求的场景:插入日志、性能测试、事务处理、缓存、权限校验等等

Python 的 functools 模块

可以 基于已有的函数定义新的函数
functools.partial 可固定部分参数,wraps 用于保留被装饰函数的元信息

生成器、迭代器

多线程交互, 访问数据如何避免重读?

可以创建一个已读数据集合, 用于 存储已访问的数据, 并加上 互斥锁(threading.Lock)
多线程交互的时候, 访问数据前先看看这个数据集合, 决定读取还是跳过

Python 的 GIL 锁

Global Interpreter Lock, 全局解释器锁
CPython 的全局解释器锁,导致同一时刻只有一个线程执行 Python 字节码

同一个进程中, 有多个线程在运行
一个线程在运行 Python 程序的时候会生成 GIL, 以此来霸占 Python 解释器, 这使得这个进程内的其他线程无法运行, 只能等待。不过若该线程遇到耗时操作的时候, 会解开 GIL, 让其他线程先执行

因为一个进程里面的资源是共享的, 所以 Python 的多线程 并不是同时进行的
而各个进程的资源是分开的, 所以多进程是可以同时进行的, 不过相比于多线程, 缺点是 系统资源开销大

  • 贴士

    1. 多进程适用于 CPU 密集型操作(例如多数位的 浮点运算
    2. 多线程适用于 IO 密集型操作(例如 数据读写 操作)

is 与 ==

a is b, 判断是否为同一个对象(id 是否相同)
a == b, 这是通过对象的 判断的

面向过程、面向对象

二者是 程序设计方法
面向过程:围绕功能, 以算法为中心
面向对象:围绕数据, 以类和对象为核心。有个很重要的东西叫 , 三大特性是 封装、继承、多态

match 从字符串开头匹配, 匹配不到会返回 none search 在字符串中任意位置匹配

并行、并发

  • 并行:同一 时刻, 两个或者两个以上的事件发生。适用于大量的 逻辑操作 场景

  • 并发:只要求 同一段时间内, 交替执行多个任务

    高并发场景典形的就是双十一购物软件, 一段时间内的用户点击量很大 可以使用的库:线程、进程、协程、threading, 适用于大量的 IO 操作 场景

中文编码处理(Python 3)

Python 3 默认使用 UTF-8,通常直接写中文即可
若需指定编码,在文件头加

1
# -*- coding: utf-8 -*-

文件操作

1
2
3
4
5
import shutil
shutil.copyfile(src, dst)   # 拷贝

import os
os.remove(path)             # 删除

什么是猴子补丁?

运行期间, 动态地修改 类或模块的方法或属性

机器学习面试题

机器学习的概念

让机器从数据中习得一个模型, 这个模型需要符合现实规律
数据是现实生活中一些事务或者规律特征的数字化
学习是通过重复执行一套算法, 萃取 事务的特征
通过使用模型, 更好地 解释世界

机器学习与数据挖掘

数据挖掘受到包括机器学习在内的, 数据库、统计学等领域的影响。 统计学技术通过机器学习, 变成算法然后进入数据挖掘领域 只要和决策有关的都能叫做人工智能(AI), 模式识别(PR)、数据挖掘(DM)、信息检索(IR)算是 AI 的具体应用 它们之间是相通的

过拟合是什么?产生的原因是?如何避免?

模型的复杂度过高, 在训练集表现很好, 但是测试集上误差很大

原因:

  • 抽样方法 错误, 没有正确考虑业务场景或特点。抽出的样本数据不能有效代表业务逻辑和场景
  • 样本中的 噪音过大, 模型学习到了噪音的特性, 忽略了真实的样本特征
  • 模型过于复杂,使用了 太多的输入变量, 没有分析选择合适的变量
  • 训练数据不足
  • 模型假设 有问题, 违背了业务场景

解决:

  • L1、L2 正则化
  • 交叉验证
  • 剪枝
  • 早停
  • 重采样

欠拟合是什么?如何避免?

模型对数据的拟合程度不高, 在训练集上的效果不好

解决:

  • 增加特征数量, 选用更复杂的模型
  • 增加样本数量

有监督和无监督学习

有监督学习:训练集数据是有标签的, 使用了基本事实。目标是学习到一个 输入和输出之间关系的函数 无监督学习:训练集数据是无标签的。目标是 推断数据集中的自然结构

偏差和方差

偏差:模型预测的期望与真实值的差距,高偏差 → 欠拟合
降低高偏差可用 boosting

方差:模型对不同训练集的预测变化程度,高方差 → 过拟合
降低高方差可用 bagging

KNN 与 K-means 聚类

KNN(K 近邻)是有监督学习, 训练数据有标签, 靠最近的 K 个样本投票决定,用于分类 K-means 是无监督学习, 训练数据无标签, 用于聚类, 分为几类自行决定,通过迭代优化簇中心

距离度量通常使用欧氏距离, 为什么不用曼哈顿距离???
曼哈顿距离有 维度的限制, 只能计算 水平或者垂直的距离,在特定场景(如高维稀疏)可能更合适
欧氏距离可以用于计算 空间任意两点间的距离

贝叶斯定理

朴素贝叶斯分类器

假设所有数据集特征都 同等重要且相互独立
计算后验概率进行分类

判别模型、生成模型

判别模型:直接学习决策边界(如逻辑回归、SVM)

生成模型:学习联合概率分布(如朴素贝叶斯、HMM)

参数模型、非参数模型

参数模型:参数数量固定
例如:线性 SVM、线性回归、逻辑回归

非参数模型:参数数量随数据增长,以提供模型的灵活性
例如:KNN、决策树

根据训练集大小选择分类器

小的训练集:不太可能过拟合, 所以选择 高偏差低方差 的模型, 例如朴素贝叶斯 大的训练集:模型复杂一点较好, 所以选择 低偏差高方差 的模型, 例如逻辑回归

ROC 曲线和 AUC

ROC 曲线以假正率(FPR)为横轴,真正率(TPR)为纵轴
越靠近点(0, 1)左上角, 模型越好

AUC 是 ROC 曲线下方的面积, 值越接近 1,分类性能越好

处理缺失值和损坏的数据

用 pandas.isnull() 检测,dropna() 删除,fillna() 填充

若某特征缺失比例极高,可考虑删除该列或将其作为特殊类别

超参数和模型参数

模型参数是 模型内部的变量, 可以从数据中学习得到(如权重)
超参数是 模型外部的变量, 训练前人为设定(如学习率、树的深度)

特征选择

删除高相关特征

Lasso 回归(L1 正则化)

前向选择、后向消除、逐步回归

基于 p 值或特征重要性

混淆矩阵

预测正确(主对角线上) 真正例率:模型预测为正, 结果正确(TP) 真负例率:模型预测为负, 结果正确(TN)

预测错误 假正例率:模型预测为正, 结果错误(FP) 假负例率:模型预测为负, 结果错误(FN)

Confusion Matrix 预测正 预测负
真实为正 TP FN
真实为负 FP TN

TPR = TP/(TP+FN) FPR = FP/(FP+TN)

协方差和相关性

相关性是 协方差标准化 后的格式。因为变量的度量不同, 导致协方差难以做比较
而相关性标准化(减去均值除以标准差)后, 介于-1 到 1 之间, 可以 忽略度量

离散型变量当作连续型变量结果怎么样?
只有在 离散型变量有序 的情况下才能被当作连续变量处理, 例如某个产品的质量等级分为 1、2、3、4 等等, 越大表示质量越好, 这样的离散型变量就可以当作连续型变量处理

缺失值

给定一个数据集, 里面存在缺失值, 这些缺失值分布在 中位数(???) 的 1 个标准偏差的范围内
请问百分之多少的数据 不会受到影响???

大概会有 32%的数据不会受到影响。假设数据服从 正态分布, 根据 3σ 准则, 约有 64%的数据位于 平均值 1 个标准差的范围内
所以剩下还有 32%的数据, 这部分的数据不会收到缺失值的影响

线性分类器、非线性分类器

  • 线性分类器

    模型是参数的线性函数, 并且存在线性分类面。速度快, 但是拟合能力弱于非线性分类器
    例如:贝叶斯分类器、单层感知机、线性回归

  • 非线性分类器

    例如:决策树、RF、GBDT、多层感知机

有些线性分类器可以利用核技巧解决非线性问题, 例如:SVM

余弦距离

度量两个向量的距离, ∈[-1, 1]
-1 表示向量夹角为 180°
0 表示向量夹角为 90°
1 表示向量夹角为 0°

应用:寻找内容相似的文章, 例如先用 TF_IDF 找出两篇文章的 关键词
再分别取出 k 个关键词, 统计这些关键词的 词频, 生成两篇文章的 词频向量
再用 余弦距离计算相似度

数据埋点

记录用户在页面上的行为(访问量、点击事件等),用于后续分析

机器学习项目流程

1、抽象成数学问题。是分类、回归还是聚类…
2、获取数据。数据尽量 全面且不偏斜
3、特征预处理与特征选择。清洗, 归一化、离散化、因子化、缺失值处理、共线性处理等等, 筛选显著特征。。。
4、训练模型与调优。调节参数
5、模型诊断。过拟合与欠拟合判断, 误差分析, 再继续调优
6、模型融合。工程常用, 毕竟直接调参数对于数据量大的情况不友好
7、部署上线运行。

独热编码、标签编码

假设有颜色这一特征, 对应的值有:红、蓝、绿
独热编码表示的话就会形成三列 color_red, color_blue, color_green, 值为 1 就是对应的颜色, 反之为 0

标签编码表示的话就只会有一列 color, 比如红色的值为 0, 蓝色的值为 1, 绿色的值为 2
应该用于二进制变量, 防止值的权重不一