学海无涯

机器学习速查笔记-Numpy篇

numpy

np.unique(A)

对于一维数组或者列表,unique函数去除其中重复的元素,并按元素由大到小返回一个新的无元素重复的元组或者列表

A = [1,1,2,3,4,4,5,5,6]
a = np.unique(A)
print(a)   # [1 2 3 4 5 6]

np.random.rand(x…)

生成随机的指定维度的列表

a=np.random.rand(4)
for var in range(10):
    print(a)
    a = np.random.rand(4)

结果:

[0.21849839 0.06253395 0.10794774 0.88207845]
[0.38262448 0.93590044 0.01358229 0.67018295]
[0.52202392 0.55000451 0.8633613  0.64067578]
[0.3782018  0.74330012 0.33034715 0.74607596]
[0.07583301 0.71505934 0.66028763 0.54293845]

np.random.uniform(low,high,size)

参考原文

从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high.

  • low: 采样下界,float类型,默认值为0;
  • high: 采样上界,float类型,默认值为1;
  • size: 输出样本数目,为int或元组(tuple)类型,例如,size=(m,n,k), 则输出mnk个样本,缺省时输出1个值。
  • 返回值:ndarray类型,其形状和参数size中描述一致。

类似uniform,还有以下随机数产生函数: a. randint: 原型:numpy.random.randint(low, high=None, size=None, dtype='l'),产生随机整数; b. random_integers: 原型: numpy.random.random_integers(low, high=None, size=None),在闭区间上产生随机整数; c. random_sample: 原型: numpy.random.random_sample(size=None),在[0.0,1.0)上随机采样; d. random: 原型: numpy.random.random(size=None),和random_sample一样,是random_sample的别名; e. rand: 原型: numpy.random.rand(d0, d1, ..., dn),产生d0 - d1 - … - dn形状的在[0,1)上均匀分布的float型数。 f. randn: 原型:numpy.random.randn(d0,d1,...,dn),产生d0 - d1 - … - dn形状的标准正态分布的float型数。

用Cython加密打包python项目

使用

将下述代码保存为setup.py至需打包项目根目录,安装cython后执行python setup.py即可打包。

import sys, os, shutil, time
from distutils.core import setup
from Cython.Build import cythonize

start_time = time.time()
curr_dir = os.path.abspath('.')
parent_path = sys.argv[1] if len(sys.argv) > 1 else ""
setup_file = __file__.replace('/', '\\')
build_dir = "build"
build_tmp_dir = build_dir + "/temp"

s = "# cython: language_level=3"


def get_py(base_path=os.path.abspath('.'), parent_path='', name = '', excepts=(), copyOther=False, delC = False):
    """
    获取py文件的路径
    :param base_path: 根路径
    :param parent_path: 父路径
    :param excepts: 排除文件
    :return: py文件的迭代器
    """
    full_path = os.path.join(base_path, parent_path, name)
    for filename in os.listdir(full_path):
        full_filename = os.path.join(full_path, filename)
        if os.path.isdir(full_filename) and filename != build_dir and not filename.startswith('.'):
            for f in get_py(base_path, os.path.join(parent_path, name), filename, excepts, copyOther, delC):
                yield f
        elif os.path.isfile(full_filename):
            ext = os.path.splitext(filename)[1]
            if ext == ".c":
                if delC and os.stat(full_filename).st_mtime > start_time:
                    os.remove(full_filename)
            elif full_filename not in excepts and os.path.splitext(filename)[1] not in ('.pyc', '.pyx'):
                if os.path.splitext(filename)[1] in ('.py', '.pyx') and not filename.startswith('__'):
                    path = os.path.join(parent_path, name, filename)
                    yield path
        else:
            pass


def pack_pyd():
    # 获取py列表
    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,)))
    try:
        setup(
            ext_modules=cythonize(module_list, compiler_directives={'language_level': "3"}),
            script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir],
        )
    except Exception as ex:
        print("error! ", str(ex))
    else:
        module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), copyOther=True))

    module_list = list(get_py(base_path=curr_dir, parent_path=parent_path, excepts=(setup_file,), delC=True))
    if os.path.exists(build_tmp_dir):
        shutil.rmtree(build_tmp_dir)

    print("complate! time:", time.time() - start_time, 's')


def delete_c(path='.', excepts=(setup_file,)):
    '''
    删除编译过程中生成的.c文件
    :param path:
    :param excepts:
    :return:
    '''
    dirs = os.listdir(path)
    for dir in dirs:
        new_dir = os.path.join(path, dir)
        if os.path.isfile(new_dir):
            ext = os.path.splitext(new_dir)[1]
            if ext == '.c':
                os.remove(new_dir)
        elif os.path.isdir(new_dir):
            delete_c(new_dir)


if __name__ == '__main__':
    try:
        pack_pyd()
    except Exception as e:
        print(str(e))
    finally:
        delete_c()

常见问题

  1. 出现Unable to find vcvarsall.bat错误

Pandas笔记-进阶篇

汇总和计算描述统计

panda对象拥有一组常用的数学和统计方法,他们大部分都属于简约统计,NA值会自动被排除,除非通过skipna=False禁用

In [78]: df
Out[78]:
    one  two
a  1.40  NaN
b  7.10 -4.5
c   NaN  NaN
d  0.75 -1.3

In [79]: df.sum()
Out[79]:
one    9.25
two   -5.80
dtype: float64

In [80]: df.sum(axis=1)
Out[80]:
a    1.40
b    2.60
c    0.00
d   -0.55
dtype: float64

In [81]: df.sum(skipna=False, axis=1)
Out[81]:
a     NaN
b    2.60
c     NaN
d   -0.55
dtype: float64

简约方法选项

选项 说明
axis 简约的轴
skipna 排除缺失值,默认True
level 如果轴是层次化索引的,则根据level分组简约

描述和汇总统计

方法 说明
count 非NA值的数量
describe 针对Series或各DataFrame列计算汇总统计
min、max 计算最小值和最大值
argmin、argmax 计算能够获取到最小值和最大值的索引位置(整数)
idxmin、idxmax 计算能够获取到最小值和最大值的索引值
quantile 计算样本的分位数(0到1)
sum 值的总和
mean 值的平均数
median 值的算术中位数(50%分位数)
mad 根据平均值计算平均绝对离差
var 样本值的方差
std 样本值的标准差
skew 样本值的偏度(三阶矩)
kurt 样本值的峰度(四阶矩)
cumsum 样本值的累计和
cummin、cummax 样本值的累计最大值和累计最小值
cumprod 样本值的累计积
diff 计算一阶差分(对时间序列很有用)
pct_change 计算百分数变化

相关系数与协方差

corr方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。cov方法用于计算协方差。

Pandas笔记-基础篇

Series

Series是一种类似一维数组的对象,由一组数据和一组与之相关的数据索引组成

In [9]: obj = Series([4,7,-5,3])

In [10]: obj.index
Out[10]: RangeIndex(start=0, stop=4, step=1)

In [11]: obj.values
Out[11]: array([ 4,  7, -5,  3], dtype=int64)

In [12]: obj2 = Series([4,7,-5,3], index=['d','b','c','a'])

In [13]: obj2.index
Out[13]: Index(['d', 'b', 'c', 'a'], dtype='object')

In [14]: obj2['a']
Out[14]: 3

In [15]: obj2[['c','b','a']]
Out[15]:
c   -5
b    7
a    3
dtype: int64

Numpy 数组运算都会保留索引和值之间的链接,但这些操作并不会改变原Series本身(与ndarray的选区操作相对)

In [19]: obj2[obj2>0]
Out[19]:
d    4
b    7
a    3
dtype: int64

In [20]: obj2 * 2
Out[20]:
d     8
b    14
c   -10
a     6
dtype: int64

In [23]: np.exp(obj2)
Out[23]:
d      54.598150
b    1096.633158
c       0.006738
a      20.085537
dtype: float64

还可以将Series看成一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要的字典参数函数中。

Numpy笔记-进阶篇

利用数组进行数据分析

np.where是三元表达式x if condition else y的矢量化版

In [169]: arr
Out[169]:
array([[-2.09280349e-01, -2.08776777e+00,  1.18959772e+00,
        -1.30555812e-01],
       [-1.05658371e+00,  2.66633933e+00,  4.47784003e-01,
         5.22445402e-01],
       [ 9.67780972e-01, -1.00148828e+00, -1.83185363e-03,
         4.53542100e-01],
       [ 1.33135003e+00,  1.33233678e-01, -4.89156202e-01,
         1.16725743e+00]])

# 大于零替换成2,小于零替换成-2
In [170]: np.where(arr>0, 2, -2)
Out[170]:
array([[-2, -2,  2, -2],
       [-2,  2,  2,  2],
       [ 2, -2, -2,  2],
       [ 2,  2, -2,  2]])

# 大于零替换成2,小于零则不变
In [171]: np.where(arr>0, 2, arr)
Out[171]:
array([[-2.09280349e-01, -2.08776777e+00,  2.00000000e+00,
        -1.30555812e-01],
       [-1.05658371e+00,  2.00000000e+00,  2.00000000e+00,
         2.00000000e+00],
       [ 2.00000000e+00, -1.00148828e+00, -1.83185363e-03,
         2.00000000e+00],
       [ 2.00000000e+00,  2.00000000e+00, -4.89156202e-01,
         2.00000000e+00]])

数学和统计方法

以下方法可以在对某个轴向的数据进行统计,(axis=1,纵向;axis=0,横向)

In [24]: arr
Out[24]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19]])

In [25]: arr.sum()
Out[25]: 190

In [26]: arr.sum(axis=1)
Out[26]: array([ 6, 22, 38, 54, 70])

In [27]: arr.sum(axis=0)
Out[27]: array([40, 45, 50, 55])
方法 说明
sum 对数组中所有或者某个轴向的数据进行求和,零长度的数组sum为0
mean 算数平均值,零长度的数组mean为NaN
std、var 标准差、方差
min、max 最小值、最大值
argmin、argmax 最小、最大值索引
cumsum 所有元素的累计和
cumprod 所有元素累计积

用于布尔型数组的方法

用于上面的方法中,布尔值会被强制转换成1和0。因此可以使用sum对布尔型数组的True值进行计数。

Numpy 笔记-基础篇

创建 ndarray

常用方法

array函数可接受一切序列类型对象

In [2]: data1 = [6.1, 5, 4, 3, 1]

In [3]: arr1 = np.array(data1)

In [4]: arr1
Out[4]: array([6.1, 5, 4, 3, 1])

In [5]: data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]

In [6]: arr2 = np.array(data2)

In [7]: arr2
Out[7]:
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

In [8]: arr2.shape
Out[8]: (2, 4)

In [9]: arr2.dtype
Out[9]: dtype('int32')

除非显式说明,np.array会尝试为新建的这个数组判断一个较为合适的数据类型。数据类型保存在特殊的dtype对象中。比如上面的两个例子中。我们有:

In [19]: arr1.dtype
Out[19]: dtype('float64')

In [20]: arr2.dtype
Out[20]: dtype('int32')

其他新建数组方法

函数 说明
asarray 将输入转换为ndarray,如果输入本身就是一个ndarray就不进行复制
arange np.arange(5) → array([0, 1, 2, 3, 4])
ones np.ones((2,2)) → array([[1., 1.], [1., 1.]])
ones_like np.ones_like([1,2,3]) → array([1, 1, 1])
zeros np.zeros((2,2)) → array([[0., 0.], [0., 0.]])
zeros_like np.ones_like([1,2,3]) → array([0, 0, 0])
empty、empty_like np.empty(1) → array([5.06106712e+58])
eys、identity np.eye(2) → array([[1., 0.], [0., 1.]])

X 根据指定的形状和dtype创建一个为X的数组, X_like以另一个数组为参数,并根据其形状和dtype创建一个为X的数组

OSI 模型分层作用及实例

应用层

为应用程序提供服务并规定相关细节,包括文件传输(FTP)、电子邮件(SMTP)、远程登录(ssh、Telnet)等协议。

比如发送电子邮件,从用户输入完内容并点击“发送”的那一刻,就进入应用层协议处理了。协议会在数据首部添加收件人

经典排序算法 Python 实现

选择排序

每一趟遍历把最小的依次放在最前面,时间复杂度O(n²)

from typing import List, Optional

NumsList = Optional[List[int]]


class SelectSort:

    @staticmethod
    def select_sort(nums: NumsList) -> NumsList:

        for i in range(len(nums)):
            min_idx = i
            for j in range(i, len(nums)):
                if nums[j] < nums[min_idx]:
                    min_idx = j
            nums[i], nums[min_idx] = nums[min_idx], nums[i]

        return nums


if __name__ == "__main__":
    nums = [2, 4, 5, 1, 2, 9, 10, 20]
    print(SelectSort().select_sort(nums))

冒泡排序

每一趟遍历把大的放前面,小的放后面,时间复杂度O(n²)

from typing import List, Optional

NumsList = Optional[List[int]]


class BobbleSort:

    @staticmethod
    def bobble_sort(nums: NumsList) -> NumsList:
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):
                if nums[i] > nums[j]:
                    nums[i], nums[j] = nums[j], nums[i]

        return nums


if __name__ == "__main__":
    nums = [2, 4, 5, 1, 2, 9, 10, 20]
    print(BobbleSort().bobble_sort(nums))

插入排序

在操作过程中维护一个排好序的片段,初始只包含一个元素。每次从未排序的片段取出一个元素插入正确的位置。时间复杂度为O(n²)

Python 中的魔术方法

构造与初始化

__new__(self): 创建并返回一个类的实例,而__init__只是将传入的参数来初始化该实例,一般不需要重载__new__方法除非希望控制类的创建。

__init__(self): 可以理解为构造函数,将传入的参数初始化成实例

__del__(self): 可以理解为析构函数

属性访问控制

Python缺少对于类的封装,但人们希望Python能够定义私有属性,然后提供公共可访问的gettersetter。 Python其实可以通过魔术方法来实现封装。

__getattr__(self, name): 该方法定义了你试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向, 或者对一些废弃的属性进行警告。 也可用于访问私有属性

__setattr__(self, name, value): 是实现封装的解决方案,它定义了你对属性进行赋值和修改操作时的行为。 不管对象的某个属性是否存在,它都允许你为该属性进行赋值,因此你可以为属性的值进行自定义操作。有一点需要注意,实现__setattr__时要避免"无限递归"的错误。

def __setattr__(self, name, value):
    self.name = value
    # 每一次属性赋值时, __setattr__都会被调用,因此不断调用自身导致无限递归了。

正确为:

def __setattr__(self, name, value):
    self.__dict__[name] = value

常见设计模式 Python 实现

简单工厂模式

根据不同条件生产不同功能的类

class op(object):
	def get_ans(self):
		pass

class Add(op):
	def get_ans(self):
		return self.a + self.b

class Mul(op):
	def get_ans(self):
		return self.a * self.b

class Undef(op):
	def get_ans(self):
		return "UNDEF!"

class Factory(op):
	operator = dict()
	operator["+"] = Add()
	operator["*"] = Mul()
	def create_operator(self, ch):
		t = self.operator[ch] if ch in self.operator else Undef()
		return t

if __name__ == "__main__":
	a = int(input())
	b = int(input())
	op = input()
	factory = Factory()
	cal = factory.create_operator(op)
	cal.a = a
	cal.b = b
	print(cal.get_ans())

单例模式

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类 “类 (计算机科学)")必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。