机器学习基础Q&A

这是我个人整理和总结的基础概念和疑难点, 用Q&A的形式展示出来, 特别适合初学者和准备面试的童鞋~

逻辑回归, Lasco回归, Ridge回归和ElasticNet

  • Q: 逻辑回归比线性回归好吗? 为什么?
  • A: 并不能说在任意场景下, 逻辑回归一定会比线性回归好. 由NFL定理可知, 如果存在使用LR比使用线性回归表现更好的场景, 就一定存在使用线性回归比使用LR表现更好的场景.
  • Q: 介绍一下Lasco回归, Ridge回归和ElasticNet和它们之间的异同
  • A: Lasco 回归使用L1正则化, 岭回归使用L2正则化, ElasticNet使用L1和L2的加权. L1正则化的好处是可以压缩系数, 能把系数压缩到0. L2正则化因为可导, 计算更方便, 表现更加平滑和稳定. L1和L2的加权实际上是一种折中. 在一个特征和另外一个特征相关时, Lasco通常只选择一个, ElasticNet往往会两个都选择. 同时也集成了Ridge回归的稳定性.
  • Q: 为什么L1能够压缩系数? 为什么L2做不到?
  • A: 我们可以从损失函数, 优化, 以及对数似然等角度去理解.
    • 我们可以从损失函数L与某个参数w之间的关系与理解. 在没有正则化前, 参数对于损失函数的极值点可能是w0. 因为正则化项都是在w=0处为0的非负偶函数. 加入正则化项以后, 无论w0大于0还是小于0, 新的极值点都会往0更靠近. 然而如果是加入L1正则项, 在系数大的时候, 损失函数可能就变成了尖峰状. 若损失函数在w=0处本来就为0, 并且有|L(w0)|<|w0|. 那么加了L1正则项后极小值点就是0点了. 这也是系数能被压缩至0的条件. 对于L2正则化来讲, 0点附近的值是很小的, 一般|L(w0)|>|w0|^2, 所以很难把极小值点拖到0点处.
    • 从优化的角度上看, 在加了正则项后, 我们需要满足损失函数最小, 同时参数要在正则项构成的区域内. 有正则项的表达式我们能看到L1是有角的, L2 是个球. 对于L1交点常在坐标轴上, 自然就把一些系数压缩成0了.
    • 如果从分布的角度讲. L1和L2实际上是代表了的先验知识. 如果我们认为数据是服从某种分布, 应该在损失函数中加入对数似然, L1和L2就分别对应了Laplace分布和高斯分布
  • Q: 为什么L2会更平滑
  • A: 跟上面解释一样, 加了L2正则后, 极值点倾向靠近0的小数值, 所以会更平滑.
  • Q: L1正则化不可导, 问题如何求解?
  • A: 近端梯度下降(Proximal Gradient Descent, PGD)

贝叶斯

  • Q: 介绍下朴素贝叶斯的原理?
  • A: 首先, 我们可以定义分类错误的损失, 然后根据样本分类的后验概率得到对样本分类的期望损失, 也就是条件风险. 这样, 我们的分类任何就是要找到一个映射, 来最小化风险. 这样我们就有一个贝叶斯判定准则: 为最小化总体风险, 只要在每个样本选择那个能使条件风险最小的类别标记即可. 对应的分类器就称为贝叶斯最优分类器. 我们可以根据分类的
  • Q: 朴素贝叶斯的"朴素"有什么意义?
  • A: 因为它假定样本的各个属性是相互独立的. 这样就可以避免直接估计所有属性的联合分布了.
  • Q: 举个例子描述朴素贝叶斯?
  • A: 以单词纠正来讲, 我们知道错误的单词w, 想要知道最可能的正确的单词c, 也就是要求P(c|w)最大. 按照贝叶斯定理, 我们可以通过正确单词的分布P(c)和给定正确单词c后错误单词w的分布P(w|c)来计算.
  • Q: 在朴素贝叶斯中, 如果重复了一个特征, 最发生什么事?
  • A: 预测的精度会降低. 因为联合概率变小了.

kNN

  • Q: 简单介绍下kNN?
  • A: kNN就是根据给定测试样本, 基于某种距离度量找出训练集中k个与它最近的邻居, 然后基于这k个邻居的类别对该样本的类别进行判断.
  • Q: kNN有哪些要素?
  • A: 主要有K值的选择, 距离度量和分类决策规则三个要素
    • K值选择: 若K值大, 偏差小, 但方差大; 若K值大, 方差小, 但偏差大. 一般我们通过交叉验证来选取.
    • 距离度量: 距离度量一般有欧式距离, 曼哈顿距离, 和特征中最大值. kNN的结果对距离十分敏感, 特征一定要归一化.
    • 分类决策规则: 一般有投票法和加权投票法.
    • 另外, 样本的输入顺序, 类初始中心的选取, 也会影响分类结果.
  • Q: 使用kNN有什么需要注意的?
  • A: K值和距离度量很重要, 特征一定要归一化
  • Q: kNN的搜索过程很慢, 如何优化?

  • A: 可以使用KD树. KD树通过特征中位数和对维度取模实现划分. 每次划分取方差大的. KD树是主存数据结构, 用的时候要整个加载进内存

  • Q: 如何寻找kNN的全局最优解?

  • A: 可以尝试不同的质心初始化, 可以调整迭代次数, 可以去找K最佳大小.

  • Q: 介绍下kNN中的距离度量?
  • A: 一般有闵氏距离, 马氏距离(Mahalanobis Distance), 巴氏距离(Bhattacharyya Distance), 相关系数, 等等.
    • 闵氏距离包括欧氏距离, 曼哈顿距离, 切比雪夫距离
    • 马氏距离有不受量纲影响, 尺度变换不变性, 基于卡方分布, 可以用于检测离群点

决策树

  • Q: 简单介绍下决策树?
  • A: 决策树是基于树结构来进行决策的, 叶节点对应决策侧结果, 非叶节点则对应一个属性测试. 从根节点到每个叶节点就构成了一个判定序列. 决策树学习的目的是找到一棵泛化能力强的决策树.
    • 决策树的学习过程的核心思想是选取最优的划分属性对节点进行划分. 是这样的: 对于一个节点, 上面有训练集D和属性集A. 1. 如果当前节点都属于都属于一类样本, 那就不需要划分. 2. 如果当前属性集A为空, 或者
    • 最优属性的选择方法是决策树学习的关键, 目标是令分支节点尽可能属于同一个类别, 度量方法的不同形成了不同的学习算法. ID3学习算法是基于信息增益, C4.5学习算法则是基于增益率, CART学习算法基于基尼系数.
      • 信息增益是计算划分前和划分后的信息熵的差. 新节点会用样本数量进行一个加权. 若子节点的熵越小, 增益就越大, 所以这个算法会倾向选择特征值较多的特征进行划分.
      • 增益率它没有直接使用信息增益, 而是先用信息增益除以一个划分的本征值, 这个本征值可以理解为样本属于哪个子节点的熵. 不过很显然它会倾向于子节点样本大的划分, 因为对应的本质值小. 也就是说这个算法倾向选择特征值较少的特质进行划分.
      • 基尼系数. 基尼系数计算两个样本不属于一个类别的概率. 计算更加简单.
  • Q: 决策树如何处理连续值的属性?
  • A: 我们可以通过样本中这个属性的取值, 得到一个划分集合. 在划分树的节点时, 考察这个属性时, 可以考察这些划分点. 在子节点还可以使用该属性进行划分.
  • Q: 决策树的损失函数是什么?
  • A: 结构风险一般用节点个数. 经验风险主要有熵和基尼系数两种
    • ID3, C4.5 决策树的经验风险项是节点的熵, 权重是样本个数.
    • CART数用基尼系数经验风险项. 回归树使用均方差.
  • Q: 介绍一下决策树的前剪枝和后剪枝?

  • A:

    • 前剪枝在决策树构造时进行. 后剪枝在决策树构造后进行.
    • 剪枝方法有很多种. 剪枝时可以使用带正则项的损失函数进行判断. CART算法不需要预先指定正则项系数.
  • Q: 简单介绍CART树?

  • A: CART叫分类与回归树, 可以用于分类和回归. 它的一个特点是在划分节点时, 它将数据划分为两个集合, 而不是想ID3, C4.5那样, 按照所选择的属性的取值进行划分.

    • CART用于分类树时, 划分依据是基尼系数
    • CART用于回归树时, 划分依据是和方差

集成学习和随机森林

  • Q: 介绍一下目前主要有哪些集成学习方法?
  • A: 集成学习方法大致可分为序列式和并行式, 主要有Boosting和Bagging两种.
    • Boosting注重提高基学习器的准确性, 从而降低整体的偏差. 基本方法是根据上一次学习到的基学习器的表现来对训练样本分布进行调整, 使得先前基学习器预测错误的样本收到更多关注. 重复这个过程直到学习到的基学习器数量达到预定值, 最后把它们加权组合起来.
      • Boosting的代表性算法是Adaboost.
      • Boosting实现对特定分布学习的方法主要有两个: 重赋权和重采样. 重采样可以在错误率大于0.5后进行重启动.
      • Boosting的基学习器之间存在强依赖关系, 必须串行生成.
    • Bagging注重提高基学习器的多样性, 从而降低整体的方差. 基本方法是通过Bootstrap为每个基学习器进行采样.
      • Bagging适用于决策树, 神经网络等易受样本扰动的学习器. 代表性算法是随机森林
      • Bagging的基学习器之间不存在强依赖关系, 可以并行生成.
  • Q: 集成学习得到比基学习器更好的性能的条件是什么?
  • A: 基学习器应该要具备一定的准确性, 并且要有多样性. 理论上如果基学习器的误差相互独立的话, 随着基学习器的增加, 集成的错误率会趋向于0. 不过在现实中是不可能的.
  • Q: 简单介绍一下AdaBoost算法?
  • A: AdaBoost是一种Boosting方法. 核心思想是用上一个基学习器的错误率的对数几率(二分之一)给样本重赋权. 预测正确的样本除以几率, 错误的样本乘以该几率. 然后归一化, 再学习新的基学习器. 基学习器用其错误率的对数几率进行加权.
  • Q: 简单介绍一下随机森林?
  • A: 随机森林的基学习器都是决策树. 它是Bagging的一个拓展, 除了在样本进行bootstrap采样, 在节点划分的属性选择上也引入了随机选择: 先选择一个子集, 然后在子集里再选择最优划分, 子集的大小一般取属性的对数.

工程trick

  • Q: 什么是过拟合? 发生过拟合有什么解决方法?
  • A: 过拟合是指学习器把样本本身的特性, 譬如噪声, 也当成了潜在样本的普遍规律学习了, 导致泛化性能下降的一种现象. 一般表现为在训练样本中准确率提高, 但是在测试样本中准确率降低. 过拟合是无法完全避免的. 一般可以从模型层面和数据层面去缓解. 模型层面我们可以加入正则化项, dropout, batch normalizatin等惩罚因子去缓解. 从数据层面出发我们可以去改进训练样本, 让其更有代表性, 可以清洗数据来减少噪声, 进行特征筛选, 特征降维等, 在训练层面可以进行早停止等.
  • Q: 样本不平衡有什么解决方案
  • A: 这个得看我们怎么去看待问题. 如果我们把任务作为异常检测, 那我们可以应用一些One-Class SVM等算法去处理. 如果说我们还是把任务看做为分类问题. 一般来说上采样, 下采样和阈值移动的方法. 上采样是指通过增加正例数目使得正反例数目接近. 这个我们可以通过SMOTE算法来进行插值. 下采样是指减少反例数目来使得正反例数目接近. 这个我们可以利用EasyEnsemble算法, 将反例划分为多个与正例数目接近的集合训练多个学习器, 避免直接丢弃反例导致有用信息丢失. 阈值移动则是给正例反例不同的权值. 不过已有的实践中, 觉得如果类别极端不平衡, 还是作为异常检测问题来处理效果比较好.
  • Q: 处理的缺失值的方法
  • A: 这个得视具体情境而定:
    • 首先我们可以看下缺失值的情况. 如果缺失地很厉害, 我们可以考虑直接把这个特征给删掉.
    • 如果只是缺失了一小部分, 直接删掉的话就会丢失很多有用的信息. 这种情况我们可以将缺失值补全. 一个是均值插补或者同类均值插补. 使用均值或众数去填补缺失值. 一个方法是建模预测, 用其它特征值去预测缺失值(可以加快训练速度. 一般缺失特征处于与其它特征完全与直接相关之间的效果比较好). 一个是高维映射, 就是One-hot编码. 这种做法是最精确的(百度CTR). 然而计算量会大大增加, 而且如果样本少会过于稀疏, 效果很差.
    • 除此之外我印象中还有: 多重插值, 压缩感知和矩阵补全. 多重插值和蒙特卡洛有些关系. 压缩感知和奈奎斯特采样定理有关. 矩阵补全跟半正定规划有关. 不过没有实践过, 只是了解一点.
    • 另外, 有些算法是可以直接用有缺失值的样本的, 例如决策树, 这种情况我们可以不加处理.
  • Q: 为什么我们要做数据归一化处理
  • A:
    • 一个是如果特征在数量级上有较大差异, 会使得目标函数仅依赖量级大的特征, 其它特征的信息就丢失了.
    • 一个是会导致迭代收敛速度减慢. 因为每一步梯度负方向会偏离最小点方向.
    • 还有一些依赖样本距离的算法对特征的量级很敏感, 不归一化的话会影响效果.
  • Q: 什么情况下不需要进行归一化处理
  • A: 在一些不关心数据的值, 只是关心变量的分布和变量间的条件概率的模型, 可以不做归一化处理. 例如决策树, 朴素贝叶斯
  • Q: LR和SVM需要进行数据归一化处理吗?
  • A: LR理论上是可以不做归一化处理的, 但是如果损失函数太扁, 在迭代时可能不收敛. SVM必须归一化, 其实本质是由于loss函数不同造成的,SVM用了欧拉距离,如果一个特征的值很大, 会主导了损失函数的变化, 支配了其他的特征。相比之下, LR可以通过权重调整使得损失函数不变。
  • Q: 数据归一化有哪些办法
  • A: 一个是min-max标准化: 直接根据样本的最大最小值把特征缩放到[0,1]之间. 一个是z-score. 通过特征的期望和标准差来把特征缩放到[0,1]之间; 反余切, 对数法
  • Q: 说说常用的包提供了哪些归一化方法
  • A:
    • scikit-learn的preprocessing提供了MinMaxScaler, MaxAbsScaler和StandardScaler.
    • keras的K包
  • Q: 为什么我们要对数据做离散化处理
  • A: 特征的性质我们可以分为 定性, 定序, 定量, 定比. 很多时候, 特征的性质是达不到定量和定比的, 甚至达不到定序. 举个例子一个人喜欢喝50度的热水不意味着他两倍喜欢喝100度的热水. 所以我们要对数据做离散化处理.
    • 另外, 离散化还有不少好处. 例如, 增删方便, 可以进行特征交叉, 计算更快(稀疏矩阵计算快), 能适应异常数据, 引入非线性特性, 可以简化模型等好处
  • Q: 通常什么情况下我们会对数据做正则化. 有哪些包有这个功能?
  • A: 一个比较典型的场景是使用点积或核方法计算样本相似性时, 需要对特征进行这个处理. 做法是对特征的某个范数缩放到1.
    • scikit-learn的preprocess 包有Normalizer可以实现这个功能, 支持L1, L2和Max
  • Q: 数据预处理有哪些步骤?
  • A:
      1. 处理缺失值
      1. 处理连续值, 例如离散化
      1. 二值化和独热编码
      1. 去掉高相关的列, 可以利用皮尔逊系数
  • Q: 机器学习遇到瓶颈, 有什么方法去改善?
  • A: 可以从几个方向去入手.
    • 一是基于数据改善性能
    • 二是基于算法改善性能
    • 三是通过调参改善性能
    • 四是借助集成改善性能
  • Q: 解释一下 BatchNormalization?
  • A: 用于缓解梯度弥散. 对一个batch的输入的结果的每一维进行正则化, 然后再进行缩放平移, 表示与原来是一个表达. (1)加速收敛 (2)控制过拟合,可以少用或不用Dropout和正则 (3)降低网络对初始化权重不敏感 (4)允许使用较大的学习率
    • keras的BatchNormalization, 主要有三组参数, 动态均值和动态方差的, 进行缩放平移的beta和gamma(是否使用, 初始化方法和约束). 杂项, 利用ecliption, 动态均值的动量(滑动平均)等.
  • Q: 高维数据有哪些处理方法?
  • A: 主要有降维技术与特征选择两种方法
  • Q: 为什么我们要对特征进行降维? 特征降维有哪些方法?
  • A: 主要是因为维度灾难. 样本在高维空间稀疏, 计算距离会很困难(除了聚类还有哪些例子?). 主要算法有MDS, 基本思想是让样本在低维空间的距离保持不变. 一个是PCA, 让样本投影到超平面上. 非线性嵌入可以用Kernal PCA. 流型学习, 例如Isomap(等度量运算), 利用曲面距离(测地线)代替直接计算高维空间的距离. 局部线性嵌入的主要思想则是保持样本的线性关系.
    • PCA: scikit-learn的decomposition包提供 PCA, IncrementalPCA, KernalPCA
    • MDS, Isomap: scikit-learn的manifold包
  • Q: PCA的目标维度如何设置.
  • A: 一般来说这个值是直接指定的, 或者是进行交叉验证. 或者设置一个重构阈值, 选取选取维度的特征值之和与所有特征值之和的比超过这个阈值.
  • Q: 为什么要进行特征选择.
  • A: 一是维度灾难. 挑选出重要特征, 后续学习在这小部分特征构建模型能够减轻维数灾难. 二是去掉不相关特征能降低学习任务难度.
  • Q: 如何进行特征筛选
  • A: 特征选择主要有过滤式选择, 包裹式选择, 嵌入式选择这几种.
    • 过滤式选择是先对数据集进行特征选择, 再训练学习器. 代表性算法: Relief. 基本思想是与类别有关的特征, 其样本在这个特征上的分量应该离同类样本差别尽量小, 与异类样本差别尽量大. 我们也可以根据特征的方差来识别. 方差越小,
    • 包裹式选择是把学习器的性能作为特征子集的评价标准. 代表性算法: LVW(Las Vegas Wrapper), 基于随机策略进行子集搜索.
      • 随机森林: 回归问题采用方差或最小二乘, 分类问题采用信息增益或基尼不纯度.
        • 关联特征问题: 是重要的特征有可能得分很低
        • 偏向问题: 是这种方法对特征变量类别多的特征越有利
      • 稳定性选择: (是一种基于二次抽样和选择算法相结合较新的方法,选择算法可以是回归、SVM或其他类似的方法。它的主要思想是在不同的数据子集和特征子集上运行特征选择算法,不断的重复,最终汇总特征选择结果,比如可以统计某个特征被认为是重要特征的频率(被选为重要特征的次数除以它所在的子集被测试的次数)。理想情况下,重要特征的得分会接近100%。稍微弱一点的特征得分会是非0的数,而最无用的特征得分将会接近于0。)
    • 嵌入式选择是在学习器训练过程中自动进行特征选择. 代表性方法: L1正则化.
    • scikit-learn的feature_selectin包提供特征选择类
    • 计算特征向量与响应向量的相关性, 皮尔逊系数和互信息系数
    • 用每个特征预测响应, 通过准确性来选择
    • 训练能够给特征打分的模型, 如随机森林, 然后选择打分高的再训练模型
    • 通过特征组合后再来选择特征:如对用户id和用户特征最组合来获得较大的特征集再来选择特征,这种做法在推荐系统和广告系统中比较常见,这也是所谓亿级甚至十亿级特征的主要来源,原因是用户数据比较稀疏,组合特征能够同时兼顾全局模型和个性化模型,这个问题有机会可以展开讲。
    • 通过深度学习来进行特征选择:目前这种手段正在随着深度学习的流行而成为一种手段,尤其是在计算机视觉领域,原因是深度学习具有自动学习特征的能力,这也是深度学习又叫unsupervised feature learning的原因。从深度学习模型中选择某一神经层的特征后就可以用来进行最终目标模型的训练了。
  • Q: 根据特征数量和样本数量的关系, 如何选择分类器?
  • A: 若特征数量很大, 可以考虑线性分类器, 如LR, SVM和线性核. 因为样本在样本空间稀疏, 很可能是线性可分的. 如果特征数量较少, 可以使用SVM和高斯核, 因为可能不是线性可分的.
  • Q: 什么是多重共线性, 怎么发现多重共线性
  • A: 多个特征间存在线性相关. 可以通过计算皮尔逊系数, 方差膨胀因子来判断
  • Q: 在回归模型中, 存在多重共线性, 你如何解决?
  • A: 可以去掉一个, 或者在LR, SVM中加上惩罚系数(需确认)
  • Q: 什么是鞍点. 如何避免进入鞍点
  • A: 鞍点就是一阶导数为0, 但二阶导数有一个方向不为0的点(需要确认).
  • Q: 什么是ill-condition病态问题?
  • A: 训练完的模型,测试样本稍作修改就会得到差别很大的结果,就是病态问题,模型对未知数据的预测能力很差,即泛化误差大。

(未完待续)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容