首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

在Python中实现遗传算法:使用适应度对列表进行排序

遗传算法是一种模拟生物进化过程的优化算法,它通过模拟自然选择、交叉和变异等操作来搜索最优解。在Python中,我们可以使用遗传算法来解决各种优化问题。

实现遗传算法的步骤如下:

  1. 初始化种群:创建一个包含多个个体的种群,每个个体都是一个候选解。可以使用列表或数组来表示种群。
  2. 评估适应度:根据问题的特定要求,为每个个体计算适应度值。适应度值表示个体对问题的解决程度,可以是一个数值或者一个评估函数。
  3. 选择操作:根据适应度值,选择一些个体作为父代,用于产生下一代个体。常见的选择操作有轮盘赌选择、锦标赛选择等。
  4. 交叉操作:从父代个体中选择两个或多个个体,通过交叉操作生成新的个体。交叉操作可以使用单点交叉、多点交叉、均匀交叉等方法。
  5. 变异操作:对新生成的个体进行变异操作,引入新的基因变化。变异操作可以是随机改变个体中的某些基因值,或者交换、删除、插入某些基因。
  6. 更新种群:将新生成的个体加入到种群中,替换掉一部分旧的个体。
  7. 终止条件判断:根据问题的要求,判断是否满足终止条件,如达到最大迭代次数或找到满意的解。
  8. 返回最优解:根据评估函数或适应度值,选择最优的个体作为最终的解。

在Python中,可以使用numpy库来进行数组操作,实现遗传算法的各个步骤。同时,也可以使用其他相关库来加速计算,如pandas、matplotlib等。

以下是一个简单的示例代码,演示如何在Python中实现遗传算法来对列表进行排序:

代码语言:python
复制
import numpy as np

# 定义适应度函数,计算列表的逆序数
def fitness_function(individual):
    fitness = 0
    for i in range(len(individual)):
        for j in range(i+1, len(individual)):
            if individual[i] > individual[j]:
                fitness += 1
    return fitness

# 初始化种群
def initialize_population(population_size, individual_size):
    population = []
    for _ in range(population_size):
        individual = np.random.permutation(individual_size)
        population.append(individual)
    return population

# 选择操作,使用轮盘赌选择
def selection(population, fitness_values, num_parents):
    parents = []
    fitness_sum = np.sum(fitness_values)
    probabilities = fitness_values / fitness_sum
    for _ in range(num_parents):
        parent_index = np.random.choice(len(population), p=probabilities)
        parents.append(population[parent_index])
    return parents

# 交叉操作,使用单点交叉
def crossover(parents, offspring_size):
    offspring = []
    for _ in range(offspring_size):
        parent1, parent2 = np.random.choice(parents, size=2, replace=False)
        crossover_point = np.random.randint(1, len(parent1))
        child = np.concatenate((parent1[:crossover_point], parent2[crossover_point:]))
        offspring.append(child)
    return offspring

# 变异操作,随机交换两个位置的基因
def mutation(offspring):
    for i in range(len(offspring)):
        if np.random.random() < mutation_rate:
            mutation_point1, mutation_point2 = np.random.choice(len(offspring[i]), size=2, replace=False)
            offspring[i][mutation_point1], offspring[i][mutation_point2] = offspring[i][mutation_point2], offspring[i][mutation_point1]
    return offspring

# 更新种群,使用精英保留策略
def update_population(population, offspring):
    population.extend(offspring)
    population.sort(key=lambda x: fitness_function(x))
    population = population[:population_size]
    return population

# 遗传算法主函数
def genetic_algorithm(population_size, individual_size, num_generations):
    population = initialize_population(population_size, individual_size)
    for _ in range(num_generations):
        fitness_values = np.array([fitness_function(individual) for individual in population])
        parents = selection(population, fitness_values, num_parents)
        offspring = crossover(parents, population_size - num_parents)
        offspring = mutation(offspring)
        population = update_population(population, offspring)
    best_individual = population[0]
    return best_individual

# 参数设置
population_size = 100
individual_size = 10
num_parents = 20
mutation_rate = 0.01
num_generations = 100

# 运行遗传算法
best_individual = genetic_algorithm(population_size, individual_size, num_generations)

# 输出结果
print("Best individual:", best_individual)

在这个示例代码中,我们定义了一个适应度函数fitness_function,用于计算列表的逆序数。然后,我们实现了初始化种群、选择操作、交叉操作、变异操作、更新种群等函数。最后,我们调用genetic_algorithm函数来运行遗传算法,并输出最优的个体。

这只是一个简单的示例,实际应用中可能需要根据具体问题进行适当的修改和优化。同时,还可以结合其他技术和工具,如并行计算、进化策略、遗传编程等,来进一步改进遗传算法的性能和效果。

腾讯云提供了多种云计算相关的产品和服务,如云服务器、云数据库、云存储等。具体的产品和介绍可以参考腾讯云官方网站:https://cloud.tencent.com/

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

使用 Python 波形的数组进行排序

本文中,我们将学习一个 python 程序来波形的数组进行排序。 假设我们采用了一个未排序的输入数组。我们现在将对波形的输入数组进行排序。...− 创建一个函数,通过接受输入数组和数组长度作为参数来波形的数组进行排序使用 sort() 函数(按升序/降序列表进行排序)按升序输入数组进行排序。...例 以下程序使用 python 内置 sort() 函数波形的输入数组进行排序 − # creating a function to sort the array in waveform by accepting...在这里,给定的数组是使用排序函数排序的,该函数通常具有 O(NlogN) 时间复杂。 如果应用了 O(nLogn) 排序算法,如合并排序、堆排序等,则上述方法具有 O(nLogn) 时间复杂。...结论 本文中,我们学习了如何使用两种不同的方法给定的波形阵列进行排序。与第一种方法相比,O(log N)时间复杂降低的新逻辑是我们用来降低时间复杂的逻辑。

6.8K50

Python使用 pyecharts 模块绘制动态时间线柱状图 ① ( 列表排序 | 使用 sorted 函数容器进行排序 | 使用 list.sort 函数列表进行排序 | 设置排序函数 )

一、列表排序 1、使用 sorted 函数容器进行排序 之前的博客 【Python】数据容器总结 ② ( 数据容器元素排序 | 字符串大小比较 | 字符大小比较 | 长短一样的字符串大小比较 | 长短不一样的字符串大小比较...) , 介绍了使用 sorted 函数 容器的元素进行排序 ; sorted 函数语法如下 : sorted(iterable, key=None, reverse=False) iterable..., 2, 1, 1] ['Joe', 'Tom', 'Trump', 'Jerry'] Process finished with exit code 0 2、使用 list.sort 函数列表进行排序...在数据处理 , 经常需要对 列表 进行排序 ; 如果在排序的同时 , 还要指定排序规则 , 那么 就不能使用 sorted 函数 了 , 该函数无法指定排序规则 ; 这里引入 list.sort 方法...Process finished with exit code 0 3、使用 list.sort 函数列表进行排序 - 设置排序函数 list.sort 函数 的 key 参数 , 需要传入一个排序函数

26210

遗传算法框架GAFT优化小记

直到放假前github有个使用gaft做SVM参数优化的童鞋开了个issue说道gaft优化的过程中会大量调用适应函数,这才使我国庆放假期间gaft进行了profiling找到程序瓶颈并针对性的优化...正文 GAFT进行性能分析(Profiling) 关于如何Python程序进行性能分析生成分析报告并可视化分析报告,我之前的一篇博客里《Python优化第一步: 性能分析实践》进行了详细的介绍,...fitness进行了多余的调用,因为遗传算法,每一代的population的个体是不会发生变化的我们只需要在每一次迭代的一开始调用fitnessn次就好了(n为种群大小),每一代再次需要用到适应值的地方直接获取...这样需要我们种群的个体进行惰性求值,也就是所有的fitness的值进行缓存。这种操作我优化自己的催化动力学程序的时候也使用过,叫做函数返回值缓存....1、列表整体是否发生了变化(赋值操作) 2、列表的元素是否发生变化(列表的元素赋值操作,列表的append, extend操作等) 好了我们要具体怎么实现呢?

69680

Python 使用列表的sort()进行多级排序实例演示,list的sort()排序方法使用详解,python3sort()的cmp自定义排序方法,sort()的逆序、倒叙排序方法

Python 列表 sort 排序方法使用详解 第一章:常规功能 ① sort() 的默认排序 ② sort() 的多级排序实例演示 ③ sort() 的逆序、倒叙排序 ④ sort() 方法的源码 第二章...② sort() 的多级排序实例演示 通过 key 参数可以设定哪一位进行排序。...) 元素一排序的基础上再进行元素二的排序,然后再进行元素三的排序。...None 第二章:扩展功能 ① sort() 的 cmp 自定义排序方法 python2 中有 cmp 参数,python3 已经给取消了,如果使用会报 TypeError: 'cmp' is an...python3 的使用方法如下: y[1]-x[1] 指的是用第二列进行逆序排序

2.1K10

深入解析多目标优化技术:理论、实践与优化

核心概念: 非支配排序(Non-dominated Sorting):根据解的支配关系种群进行分层排序。 拥挤比较(Crowding Distance):衡量解目标空间中的分布密集程度。...算法流程: 初始化种群,并进行非支配排序和拥挤计算。 选择父代,进行交叉和变异产生子代。 将父代和子代合并,并按非支配排序和拥挤进行选择,形成新一代种群。 重复步骤2和3直到满足终止条件。...我们将使用遗传算法来同时处理这两个目标。 2.遗传算法实现 算法概述: 初始化:随机生成一组候选解(参数集)作为初始种群。 适应评估:评估每个候选解的性能,考虑两个目标:准确和资源消耗。...代码包含了模型评估、适应计算、种群初始化、选择、交叉和变异等关键步骤。 六、应用遗传算法优化机器学习模型参数 在前面的代码实现,我们模拟了遗传算法的基本框架。...高级技巧与实践建议 多目标优化: 机器学习,我们经常需要同时考虑多个目标,如准确、模型复杂、运行时间等。 遗传算法可以通过非支配排序(如NSGA-II)来优化多个目标。

2.5K11

遗传算法系列之四:遗传算法的变种

当种群各个个体适应趋于一致或者趋于局部最优时,使pc和pm增加;当群体适应比较分散时,使pc和pm减少。甚至于不同个体也应该有不同的pc和pm。...对于适应高的个体,我们应该减少pc和pm以保护他进入下一代;反之适应低的个体,我们应该增加pc和pm让他探索新的天地。...受此启发,人们提出了混合遗传算法,将遗传算法和这些算法结合起来。混合遗传算法的框架是遗传算法的,只是生成新一代种群之后,每个个体使用局部搜索算法寻找个体周围的局部最优点。...混合遗传算法是很常见的策略。比如遗传算法应用于排序问题,生成新一代种群之后,将个体相邻两个元素交换次序,如果新的个体适应更高则保留。这种贪心的变种往往能大幅度提高遗传算法的收敛速率。...排序问题的变异操作随机选取个体的两个基因进行交换。我们随机选择个体I=[1 3 5 4 2]两个基因位,假设选择的基因位是1和3,变异结果I=[5 3 1 4 2]。 排序交叉操作。

3.5K100

数学建模篇——遗传算法

遗传算法的编码和解码过程宏观上可以对应生物的基因型和表现型,微观上可以对应基因的转录和翻译。 3、交配 “交配运算”是使用单点或多点进行交叉的算子。...4、突变 “突变运算”是使用基本的位运算进行基因突变。为了避免算法迭代过程种群过早收敛,对于二进制的基因编码组成的个体种群,实行基因码的小几率翻转。...5、个体适应评估 进化论适应,是表示某一个体环境的适应能力,也表示该个体繁殖后代的能力。...遗传算法适应函数也叫评价函数,是用来判断群体的个体的优劣程度的指标,它是根据所求问题的目标函数来进行评估的。...由于遗传算法适应函数要比较排序并在此基础上计算选择该利率,所以适应函数的值要取正值。

1.5K20

NSGA-II入门

多目标遗传算法遗传算法的区别-选择的方法不同 多目标遗传算法遗传算法的联系-交叉变异的方法相同 遗传算法中和多目标遗传算法中最大的不同在于 选择 的过程,遗传算法通过适应函数进行种群个体的选择...,而多目标遗传算法根据 非支配的Rank值和拥挤进行排序 选择保留的个体。...其算法最主要的思想是 将所有的个体进行分层,并且每个个体都设置个体虚拟适应值同一层的每个个体虚拟适应值相同,层级数越低,其适应值越高,遗传到下一代的概率也就越大。...采用非支配排序遗传算法多目标优化得到了广泛应用,但是,随着其使用越广泛,其算法也暴露出了一些缺陷。...NSGA-II算法流程-算法收敛停止 创造一个初始父代种群 使用交叉和变异操作产生子代种群 h和 组成的整体 进行非支配排序,构造所有不同等级的非支配解集 对分好等级的非支配解集进行拥挤距离排序

2.3K50

学界 | 结合遗传算法与DNN的EDEN:自动搜索神经网络架构与超参数

基于适应函数,我们选择多对较优个体(父母)。适应高的个体更易被选中繁殖,即将较优父母的基因传递到下一代。...一文读懂遗传算法工作原理(附 Python 实现遗传算法的基本概念和实现(附 Java 实现案例) ? 4....遗传算法的每一代,我们需要选择父染色体并进行遗传操作而创造子染色体。父染色体的选择使用的特定的算法,一般父染色体的选择是根据适应排序和竞赛选择(tournament selection)。...下图 2 和 3 展示了模型进化过程适应和学习率变化情况。 ? 图 2: MNIST 数据上,0 到 10 代遗传算法平均适应的展示 ?...图 3: 0 到 10 代遗传算法的平均学习率变化 我们的研究是首次尝试用神经进化算法来创造 1D 卷积网络和优化嵌入层以实现情感分析任务。

2.6K60

GAFT:一个使用Python实现遗传算法框架

gaft 设计原则 由于遗传算法的流程相对固定,我们优化算法基本上也是流程整体框架下编码机制,算子,参数等进行修改,因此写框架的时候,我便想把那些固定的遗传算子,适应函数写成接口,并使用元类、装饰器等方式实现对接口的限制和优化...这样我们便脱离每次都要写遗传算法流程的繁琐,每次只需要像写插件一样实现自己的算子和适应函数便可以将其放入gaft开始算法进行测试或者目标函数进行优化了。...GAFT文件结构 此部分我自己实现的框架的整体结构进行下介绍. ?.../gaft/analysis里面是内置的on-the-fly分析插件,他可以遗传算法迭代的过程迭代过程的变量进行分析,例如我在里面内置了控制台日志信息输出,以及迭代适应值的保存等插件方便进化曲线作图...自定义适应函数 可以通过修饰符的方式将,适应函数注册到引擎。 ? 4. 自定义on-the-fly分析插件 也可以通过修饰符定义的时候直接将插件注册到引擎 ? 5.

1.6K90

作业车间调度JSP与遗传算法GA及其PythonJavaC++实现

公式(4)表示1台机床上不会同时加工1个以上的作业。 遗传算法 ? 随着遗传算法(genetic algorithm (GA))组合优化问题的广泛应用,许多人开始遗传算法进行深度研究。...遗传算法解决作业车间调度问题基本步骤: 1.初始化一定数量的种群(染色体编码) 2.计算个体适应(染色体解码) 3.采用锦标赛法选择染色体并交叉产生新个体 4.个体(染色体)变异 5.达到遗传代数终止算法并从中选取适应最优的个体作为作业车间调度问题的解...,用times来表示 遗传算法实现基本步骤及伪代码: 1....解码及计算适应 将优化目标定义为总加工时间最短,因此适应定义为最短加工时间的倒数,设fitness为对应个体的适应,fulfillTime为最短加工时间,因此...代码实现 ? 原作者编写了Java,Python,C++三个版本的代码,小编仔细阅读了Java代码,在其中加入一些注释并略作修改,分享给大家。

4.7K30

基于Python手把手教你实现一个遗传算法(含具体源码,以及UI演变过程)

目录前言遗传算法概念遗传算法实现详解结束语前言作为程序开发人员来讲,日常开发工作打交道最多的当属逻辑和算法,无论是什么方向的开发者都离不开算法的使用。...可能很多人算法有天生的抵触心理,原因就是繁琐和复杂,难懂,不易使用,但是我个人觉得关于算法的使用其实是由规律可循的,比如在使用算法的时候先去使用流行的、好用的算法,其实同样的算法不同编程语言中的使用原理是一样的...最后,使用Python实现遗传算法可以很简单,因为Python具有简洁而强大的语法和丰富的科学计算库,可以使用Python的位运算功能来处理二进制编码,使用numpy库进行数值计算,以及使用matplotlib...经过上文关于遗传算法使用分享,结合Python的简洁和强大的语法,你可以很轻松地实现一个简单的遗传算法,希望这个手把手的教程你理解和实现遗传算法有所帮助。...当然,遗传算法的应用地方远不止于此,它可以用于解决各种复杂的优化问题。最后,期待你能够进一步探索和拓展这个有趣而强大的算法领域,祝你使用遗传算法的世界取得成功!

1.7K52

遗传算法系列之五:多目标遗传算法和遗传编程

遗传算法出现之后,有人提出了各种方法将遗传算法应用于多目标优化。多目标遗传算法按照选择方法可以分为两种类型:基于线性加权和基于Pareto排序。...如果有K个目标,VEGA 会随机地将种群分为K个同等大小子种群,不同的子种群按照不同的目标函数设定目标值,然后再进行选择操作。VEGA 实质上是基于线性加权的多目标遗传算法。...基于 Pareto 排序的多目标遗传算法首先要解决的是适应函数设计问题。MOGA 采用的适应函数 ? ,其中nq(x)表示被个体 ? 支配的个体数量。...上面两种适应函数都能够挖掘种群 Pareto 支配关系,效果如下图所示(左边的图表示 NSGA 和 NAGA-II 的适应函数,右边的图是 MOGA 的适应函数)。 ?...一篇 2006 年综述十几年来的研究成果进行总结,算是给多目标遗传算法的研究画上了一句号。潮起了十几年又潮落了。 ? 2. 遗传编程 遗传编程是遗传算法另一个重要的后续工作。

5.6K60

遗传算法_aforge遗传算法

这样进化N代后就很有可能会进化出适应函数值很高的个体。 2.1.编码 将问题的解编码称字符串形式才能使用遗传算法。最简单的一种编码是二进制编码,即将问题的解编码成二进制位数组的形式。...常见的编码方式有: 二进制编码,基因用0或1表示,常用于解决0-1背包问题 互换编码,用于解决排序问题 树形编码,用于遗传规划的演化变成或者表示 2.2.适应函数: 用于评价某个染色体的适应...四、遗传算法实例: 利用遗传算法求解二元函数的最大值 1.种群和个体: 首先生成了200个随机的(x,y),将(x,y)坐标带入要求解的函数F(x,y),根据适者生存,我们定义使得函数值F(x,y...3.适应和选择: 需要在种群根据适者生存保存优秀的个体,淘汰掉不适应环境的个体。本例求最大值的问题中可以直接用每个个体对应的函数值来评估,函数值越大越有可能被保留。...选择则是根据新个体的适应进行,但同时不意味着完全以适应高低为导向,单纯选择适应高低为导向可能会导致算法快速收敛到局部最优解而非全局最优解。

82211

详解R语言中的遗传算法

遗传算法的操作使用适者生存的原则,潜在的种群逐次产生一个近似最优解的方案,每一代,根据个体问题域中的适应值和从自然遗传学借鉴来的再造方法进行个体选择,产生一个新的近似解。...首先要创建种群,算法随机生成一定数量的个体,有时候也可以人工干预这个过程进行,以提高初始种群的质量。每一代,每一个个体都被评价,并通过计算适应函数得到一个适应度数值。...种群的个体被按照适应排序适应高的在前面。 接下来,是产生下一代个体的种群,通过选择过程和繁殖过程完成。...R语言中,有一些现成的第三方包已经实现遗传算法,我们可以直接进行使用。 mcga包,多变量的遗传算法,用于求解多维函数的最小值。 genalg包,多变量的遗传算法,用于求解多维函数的最小值。...所以,实际的使用过程,需要根据一定的经验调整这几个参数。 3.2 genalg包 我们使用genalg包的rbga()函数,也可以实现多变量的遗传算法

2.7K100

遗传算法求解函数

从图上可以看出,[0,9]区间内,最大值为(7.857,24.855)。现在,用遗传算法找到这个点。选择使用Python语言。 基本概念:基因、染色体和种群 一系列个体组成的集合叫种群。...*math.sin(5*x) + 7*math.cos(4*x) 自然选择 """ 选择 先适应从大到小排序,选出存活的染色体 再进行随机选择,选出适应虽然小,但是幸存下来的个体 """ def...selection(self, retain_rate, random_select_rate): # 适应从大到小进行排序 graded = [(self.fitness(chromosome...math.cos(4*x) def selection(self, retain_rate, random_select_rate): """ 选择 先适应从大到小排序...,选出存活的染色体 再进行随机选择,选出适应虽然小,但是幸存下来的个体 """ # 适应从大到小进行排序 graded = [(self.fitness

1.3K50

遗传算法工具箱约束怎么输入_遗传算法怎么添加约束条件

遗传算法基本算子: 三.完整实现遗传算法: 四.后记: 前言 网上有很多博客讲解遗传算法,但是大都只是“点到即止”,虽然给了一些代码实现,但也是“浅尝辄止”,没能很好地帮助大家进行扩展应用,抑或是进行深入的研究...__version__) 下面切入主题: 自然界生物周而复始的繁衍,基因的重组、变异等,使其不断具有新的性状,以适应复杂多变的环境,从而实现进化。...5.适应值: 适应值通俗来说就是种群个体的”生存能力的评价“。...这个选择过程对应的是生物学的” 自然选择”。它可以是显性地根据适应(再次注意:适应并不等价于目标函数值)来进行选择的,也可以是隐性地根据适应(即不刻意去计算个体适应)来选择。...遗传算法模板里,我们根据遗传算法的“套路”,进行:初始化种群、目标函数值计算、适应评价、选择、重组、变异、记录各代最优个体等操作。

1.4K11

独家 | 基于Python遗传算法特征约简(附代码)

建立并使用遗传算法神经网络参数进行优化,以提高分类精度。...其次通过使用NumPy和Sklearnpython实现这些步骤。...选择双亲的标准是与每个解决方案(即染色体)相关联的适应值。适合度越高,解决方案越好。使用适应函数计算适应值。那么,我们的问题中,最适合使用的功能是什么?...接下来是用Python实现它们。注意,我以前写过一篇题为“Python遗传算法实现”的教程,用于Python实现遗传算法,我将修改它的代码来解决我们的问题。最好读一下。...准备好特性、类标签和算法参数之后,我们可以根据下一个代码算法进行迭代。首先,通过调用GA文件定义的名为cal_pop_fitness()的适应函数来计算所有解决方案的适应值。

2.1K51

干货 | 进化策略入门:最优化问题的另一种视角

构造适应 上面提到的大部分算法通常都会与构造适应的方法结合起来,例如接下来我要讨论「基于排序适应构造方法」。适应的构造可以让我们避免之前提到的种群的离群点对于近似梯度计算的控制。...我们在这里不使用适应函数的真实值,转而使用一个与解在种群排序成正比的增强适应函数结果进行排序。下图是分别使用原始的适应和基于排序适应函数的效果对比图: ?...如图所示,假如我们有一个包含 101 个样本的种群,我们会估计种群每个个体的真实适应函数值,并且根据他们的适应将解排序。...他的 CMA-ES 的 python 实现版本使我之前接触到了循环训练借口。...我将这些实现放在了一个小的名为 es.py 的 python 文件,并且将原始的 CMA-ES 算法库也打包了进来。

2K50

R语言中的遗传算法详细解析

遗传算法的操作使用适者生存的原则,潜在的种群逐次产生一个近似最优解的方案,每一代,根据个体问题域中的适应值和从自然遗传学借鉴来的再造方法进行个体选择,产生一个新的近似解。...首先要创建种群,算法随机生成一定数量的个体,有时候也可以人工干预这个过程进行,以提高初始种群的质量。每一代,每一个个体都被评价,并通过计算适应函数得到一个适应度数值。...种群的个体被按照适应排序适应高的在前面。 接下来,是产生下一代个体的种群,通过选择过程和繁殖过程完成。...R语言中,有一些现成的第三方包已经实现遗传算法,我们可以直接进行使用。 mcga包,多变量的遗传算法,用于求解多维函数的最小值。 genalg包,多变量的遗传算法,用于求解多维函数的最小值。...所以,实际的使用过程,需要根据一定的经验调整这几个参数。 3.2 genalg包 我们使用genalg包的rbga()函数,也可以实现多变量的遗传算法

1.2K70
领券