Decision Tree

①Aggregation Model

回顧上一篇文章講到的聚合模型袄友,三個(gè)臭皮匠頂一個(gè)諸葛亮。于是出現(xiàn)了blending磁滚,bagging逼庞,boost,stacking闺鲸。blending有uniform和non-uniform筋讨,stacking是屬于條件類(lèi)的,而boost里面的Adaboost是邊學(xué)習(xí)邊做linear翠拣,bagging也是屬于邊學(xué)習(xí)邊做uniform的版仔。Decision Tree就是屬于邊做學(xué)習(xí)然后按照條件分的一種。如下圖误墓,aggregation model就是是補(bǔ)全了:


②Decision Tree Hypothesis

決策樹(shù)是一種很傳統(tǒng)的算法蛮粮,出現(xiàn)的很早,例如下面谜慌,按照下班時(shí)間然想,是否約會(huì),提交截止時(shí)間進(jìn)行判斷欣范,和人的處理方式很像:


上面的菱形就像是很簡(jiǎn)單的分割平面变泄,而箭頭就是判斷過(guò)程令哟,其實(shí)就是學(xué)習(xí)過(guò)程,最后的Y和N就是分出來(lái)的結(jié)果妨蛹∑粮唬可以對(duì)應(yīng)到下面的式子:

最后那些小小的Y,N就是g(x)蛙卤,和之前的SVM他們都不太一樣狠半,這里的g(x)通常就是一個(gè)常數(shù)了,也叫base hypothesis颤难;箭頭就是q(x)判斷條件神年,紅色就是找到了最好split method的地方。
從另一個(gè)方面來(lái)看決策樹(shù):

和上面理解是一樣的行嗤。

Strengths and Weaknesses
優(yōu)點(diǎn):
模型直觀已日,便于理解,應(yīng)用很廣泛
簡(jiǎn)單栅屏,容易實(shí)現(xiàn)飘千。
訓(xùn)練和預(yù)測(cè)的時(shí)候,時(shí)間短預(yù)測(cè)準(zhǔn)確率高
缺點(diǎn)
缺少足夠的理論支持栈雳,后面給出的VC dimension沒(méi)有什么太完備的道理占婉。
對(duì)于找到合適的樹(shù)要花額外的時(shí)間。
決策樹(shù)代表性的演算法比較少

③Decision Tree Algorithm

根據(jù)上面的公式甫恩,基本算法:

base algorithm

按照決策樹(shù)執(zhí)行流程,可以分成四個(gè)部分:

首先學(xué)習(xí)設(shè)定劃分不同分支的標(biāo)準(zhǔn)和條件是什么酌予;接著將整體數(shù)據(jù)集D根據(jù)分支個(gè)數(shù)C和條件磺箕,劃為不同分支下的子集Dc;然后對(duì)每個(gè)分支下的Dc進(jìn)行訓(xùn)練抛虫,得到相應(yīng)的機(jī)器學(xué)習(xí)模型Gc松靡;最后將所有分支下的Gc合并到一起,組成大矩G(x)建椰。但值得注意的是雕欺,這種遞歸的形式需要終止條件,否則程序?qū)⒁恢边M(jìn)行下去棉姐。當(dāng)滿(mǎn)足遞歸的終止條件之后屠列,將會(huì)返回基本的hypothesis gt(x)。
所以伞矩,包含了四個(gè)基本算法選擇:
分支個(gè)數(shù)
分支條件
終止條件
基本算法

常用決策樹(shù)算法模型——CART

CART算法對(duì)決策樹(shù)算法追加了一些限制:
①c = 2笛洛,分支的個(gè)數(shù)要等于2,和二叉樹(shù)有點(diǎn)想乃坤。
②本著g(x)simplify的原則苛让,g(x)規(guī)定他就是一個(gè)常數(shù)沟蔑,也就是類(lèi)別。
③按照Ein最小化的原則每一次選擇condition狱杰。


其實(shí)決策樹(shù)的分類(lèi)有點(diǎn)像Adaboost的stump分類(lèi)瘦材。但是Adaboost的stump僅僅是按照準(zhǔn)確率來(lái)了,而decision tree的標(biāo)準(zhǔn)是purity仿畸,純凈度食棕。意思就是熵了。purifying的核心思想就是每次切割都盡可能讓左子樹(shù)和右子樹(shù)中同類(lèi)樣本占得比例最大或者yn都很接近(regression)颁湖,即錯(cuò)誤率最小宣蠕。比如說(shuō)classifiacation問(wèn)題中,如果左子樹(shù)全是正樣本甥捺,右子樹(shù)全是負(fù)樣本抢蚀,那么它的純凈度就很大,說(shuō)明該分支效果很好镰禾。

所以主要問(wèn)題就變成了如何尋找純凈度最好的問(wèn)題了皿曲。

④purifying

純凈度其實(shí)就是熵了。熵是代表混亂程度的吴侦。幾個(gè)比較常見(jiàn)的算法:ID3屋休,ID4.5,gini系數(shù)备韧。

ID3

以信息論為基礎(chǔ)劫樟,以信息熵和信息增益為衡量標(biāo)準(zhǔn),從而實(shí)現(xiàn)對(duì)數(shù)據(jù)的歸納分類(lèi)织堂。



信息增益叠艳,就是指split前后熵的變化,選擇最好的一個(gè)易阳,也就是說(shuō)由于使用這個(gè)屬性分割樣例而導(dǎo)致的期望熵降低附较。信息增益就是原有信息熵與屬性劃分后信息熵(需要對(duì)劃分后的信息熵取期望值)的差值。
但是他的缺點(diǎn)也很明顯:
1.沒(méi)有剪枝過(guò)程潦俺,為了去除過(guò)渡數(shù)據(jù)匹配的問(wèn)題拒课,可通過(guò)裁剪合并相鄰的無(wú)法產(chǎn)生大量信息增益的葉子節(jié)點(diǎn)。因?yàn)檫x擇的已經(jīng)是最好的了事示,如果合并了肯定不夠之前的好早像。
2.信息增益的方法偏向選擇具有大量值的屬性,也就是說(shuō)某個(gè)屬性特征索取的不同值越多肖爵,那么越有可能作為分裂屬性扎酷,這樣是不合理的。比如前面的ID編號(hào)遏匆,1/N再來(lái)個(gè)log很小的法挨。
3.只可以處理離散分布的數(shù)據(jù)特征谁榜。這個(gè)很明顯了,如果是連續(xù)型數(shù)據(jù)凡纳,很難分的窃植。

基于以上缺點(diǎn)又改進(jìn)了一下。

ID4.5

改進(jìn)就是ID4.5了荐糜,這個(gè)就不是信息增益了巷怜,是信息增益率。

第c個(gè)子集的信息熵

信息增益率

信息增益率是信息增益與信息熵的比例
這樣的改進(jìn)其實(shí)就是使得離散化可以連續(xù)化而已暴氏,二分就好了延塑。
優(yōu)點(diǎn):
1.面對(duì)數(shù)據(jù)遺漏和輸入字段很多的問(wèn)題時(shí)非常穩(wěn)健。
2.通常不需要很長(zhǎng)的訓(xùn)練次數(shù)進(jìn)行估計(jì)答渔。工作原理是基于產(chǎn)生最大信息增益的字段逐級(jí)分割樣本关带。
3.比一些其他類(lèi)型的模型易于理解,模型推出的規(guī)則有非常直觀的解釋沼撕。
4.允許進(jìn)行多次多于兩個(gè)子組的分割宋雏。目標(biāo)字段必須為分類(lèi)字段。

CART

Cart算法里面用的是gini系數(shù)务豺,但是還是有必要說(shuō)一下decision tree做擬合的時(shí)候Ein要怎么optimal磨总。

regression

對(duì)于regression問(wèn)題,首先想到的肯定是均方差了:


均方差

y桿就是yn的平均笼沥。

classification

對(duì)于分類(lèi):


y表示類(lèi)別最多的蚪燕。

以上都是借鑒前面algorithm的思想推導(dǎo)的,現(xiàn)在回到純度奔浅。想要purity最小邻薯,那么就是y
要多了,最好全部都是了乘凸,所以classification error:
classification error

上面的只是考慮了分支最大的,我們需要把所有的都考慮進(jìn)去累榜,于是:

gini系數(shù)就出來(lái)了:
Gini


可以看到gini系數(shù)和熵差不了多少营勤,一定程度上可以代表熵。

對(duì)于CART的Teminal condition壹罚,自然就是兩個(gè)條件:1.首先是yn只有一個(gè)種類(lèi)葛作,分不了了。2.其次就是Xn都是一樣的不能再分猖凛。

⑤Decision Tree Heuristics in CART

基本流程:



可以看到CART算法在處理binary classification和regression問(wèn)題時(shí)非常簡(jiǎn)單實(shí)用赂蠢,而且,處理muti-class classification問(wèn)題也十分容易辨泳。
但是要注意一個(gè)問(wèn)題虱岂,既然有錯(cuò)誤就分玖院,那么到最后肯定是一個(gè)二分完全樹(shù),Ein一定是0第岖,這樣是有過(guò)擬合的难菌。對(duì)于overfit,要引入的就是過(guò)擬合:


regularization

既然是過(guò)擬合了蔑滓,這棵樹(shù)不要這么大就行了郊酒,于是進(jìn)行修剪,pruning键袱,剪枝操作燎窘。比如,總共是10片葉子蹄咖,我們?nèi)〉?片褐健,剩下9片,9種情況比藻,我們比較這9種情況哪種好铝量。

這里其實(shí)就是剛剛說(shuō)的decision tree理論不是特別的完善,事實(shí)上NumberOfLeaves ≈ Ω其實(shí)我們?cè)趯?shí)踐中得到的银亲。因?yàn)槿~子越多復(fù)雜度越大慢叨。所以就直接把葉子數(shù)量當(dāng)做是復(fù)雜度Ω了。

在決策樹(shù)中預(yù)測(cè)中务蝠,還會(huì)遇到一種問(wèn)題拍谐,就是當(dāng)某些特征缺失的時(shí)候,沒(méi)有辦法進(jìn)行切割和分支選擇馏段。一種常用的方法就是surrogate branch轩拨,即尋找與該特征相似的替代feature。如何確定是相似的feature呢院喜?做法是在決策樹(shù)訓(xùn)練的時(shí)候亡蓉,找出與該特征相似的feature,如果替代的feature與原feature切割的方式和結(jié)果是類(lèi)似的喷舀,那么就表明二者是相似的砍濒,就把該替代的feature也存儲(chǔ)下來(lái)。當(dāng)預(yù)測(cè)時(shí)遇到原feature缺失的情況硫麻,就用替代feature進(jìn)行分支判斷和選擇爸邢。

⑥D(zhuǎn)ecision Tree in action




貌似和Adaboost很像啊拿愧!


最后在總結(jié)一下:


⑦代碼實(shí)現(xiàn)Decision Tree

包括創(chuàng)建樹(shù)杠河,預(yù)測(cè),可視化樹(shù),這篇東西內(nèi)容不多券敌,代碼講解多唾戚。
首先引入一個(gè)計(jì)算gini系數(shù):

def cal_gini(data):
  '''calculate the gini index
  input:data(list)
  output:gini(float)
  '''
  total_sample = len(data)
  if total_sample == 0:
      return 0
  label_count = label_uniqueness(data)
  gini = 0
  for label in label_count:
      gini = gini + pow(label_count[label] , 2)
  gini = 1 - float(gini) / pow(total_sample , 2)
  return gini
  pass

傳進(jìn)的是一個(gè)list,計(jì)算這個(gè)list里面label數(shù)量陪白,然后統(tǒng)計(jì)gini系數(shù)返回颈走。
還有一個(gè)分別計(jì)算類(lèi)別數(shù)量的函數(shù),剛剛的gini系數(shù)用到的:

def label_uniqueness(data):
  '''Counting the number of defferent labels in the dataset
  input:dataset
  output:Number of labels
  '''
  label_uniq = {}
  for x in data:
      label = x[len(x) - 1]
      if label not in label_uniq:
          label_uniq[label] = 0
      label_uniq[label] += 1
  return label_uniq
  pass

這個(gè)就是tool文件里面的咱士。
創(chuàng)建節(jié)點(diǎn)node:

class node:
  '''Tree node
  '''
  def __init__(self , fea = -1, value = None, results = None, right = None, left = None):
      '''
      initialization function
      :param fea:column index value
      :param value:split value
      :param results:The class belongs to
      :param right:right side
      :param left:left side
      '''
      self.fea = fea
      self.value = value
      self.results = results
      self.right = right
      self.left = left
      pass

fea就是當(dāng)前分割的維度立由,value就是分割的值,result就是label序厉,right右子樹(shù)锐膜,left左子樹(shù)。
接下來(lái)就是主要?jiǎng)?chuàng)建樹(shù)的類(lèi)了:

class decision_tree(object):

  def build_tree(self,data):
      '''Create decision tree
      input:data
      output:root
      '''
      if len(data) == 0:
          return node()

      currentGini = tool.cal_gini(data)
      bestGain = 0.0
      bestCriterria = None # store the optimal cutting point
      bestSets = None # store two datasets which have been splited

      feature_num = len(data[0]) - 1 # Number of features
      for fea in range(0 , feature_num):
          feature_values = {}
          for sample in data:
              feature_values[sample[fea]] = 1 # store the value in the demension fea possibly
          for value in feature_values.keys():
              (set_first, set_second) = self.split_tree(data, fea, value)
              nowGini = float(len(set_first) * tool.cal_gini(set_first) + len(set_second) * tool.cal_gini(set_second)) / len(data)
              gain = currentGini - nowGini
              if gain > bestGain and len(set_first) > 0 and len(set_second) > 0:
                  bestGain = gain
                  bestCriterria = (fea , value)
                  bestSets = (set_first , set_second)
              pass
      if bestGain > 0:
          right = self.build_tree(bestSets[0])
          left = self.build_tree(bestSets[1])
          return node(fea = bestCriterria[0], value = bestCriterria[1], right = right, left = left)
      else:
          return node(results=tool.label_uniqueness(data))

  def split_tree(self , data , fea , value):
      '''split the dataset according demension and value
      input:data
      output:two data
      '''
      set_first = []
      set_second = []
      for x in data:
          if x[fea] >= value:
              set_first.append(x)
          else:
              set_second.append(x)
      return (set_first, set_second)
      pass

  def predict(self, sample, tree):
      '''prediction
      input:sample, the tree which we have been built
      output:label
      '''
      if tree.results != None:
          return tree.results

      else:
          val_sample = sample[tree.fea]
          branch = None
          if val_sample >= tree.value:
              branch = tree.right
          else:
              branch = tree.left
          return self.predict(sample, branch)

  def predcit_samples(self, samples, tree):
      predictions = []
      for sample in samples:
          predictions.append(self.predict(sample, tree))
      return predictions

  pass

其實(shí)很簡(jiǎn)單弛房,就是按照f(shuō)eature和value分類(lèi)道盏。忘了這個(gè)是前向還是后向了,我是看那個(gè)二叉樹(shù)跟著搞的文捶,大一的時(shí)候?qū)W過(guò)荷逞,過(guò)了半年差不多忘光了。
看看預(yù)測(cè)效果吧粹排!
使用的數(shù)據(jù)還是iris數(shù)據(jù)集种远,可視化還得降維,麻煩顽耳,于是就是可視化樹(shù)了坠敷,發(fā)現(xiàn)更麻煩:

if __name__ == '__main__':
  print('load_data......')
  dataSet = load_data()
  data = dataSet.data
  target = dataSet.target
  dataframe = pd.DataFrame(data = data, dtype = np.float32)
  dataframe.insert(4, 'label', target)
  dataMat = np.mat(dataframe)

  '''test and train
  '''
  X_train, X_test, y_train, y_test = train_test_split(dataMat[:, 0:-1], dataMat[:, -1], test_size=0.3, random_state=0)
  data_train = np.hstack((X_train, y_train))
  data_train = data_train.tolist()
  X_test = X_test.tolist()
  tree = decisionTree.decision_tree()
  tree_root = tree.build_tree(data_train)
  predictions = tree.predcit_samples(X_test, tree_root)
  pres = []
  for i in predictions:
      pres.append(list(i.keys()))

  y_test = y_test.tolist()
  accuracy = 0
  for i in range(len(y_test)):
      if y_test[i] == pres[i]:
          accuracy += 1
  print('Accuracy : ', accuracy / len(y_test))

準(zhǔn)確率還是蠻高的。
首先要求樹(shù)的葉子數(shù):
一樣是遞歸射富。

def getNumLeafs(myTree):
  if myTree == None:
      return 0
  elif myTree.right == None and myTree.left == None:
      return 1
  else:
      return getNumLeafs(myTree.right) + getNumLeafs(myTree.left)

然后是求深度:

def getDepth(myTree):
  if myTree == None:
      return 0
  right = getDepth(myTree.right)
  left = getDepth(myTree.left)
  return max(right+1, left+1)

之后就是畫(huà)節(jié)點(diǎn)了膝迎,求深度和葉子數(shù)只是想著可以按照深度把樹(shù)畫(huà)的分開(kāi)點(diǎn)。
還有一個(gè)裝parent節(jié)點(diǎn)坐標(biāo)的:

class TreeNode(object):
  def __init__(self, x, y, parentX = None, parentY = None):
      self.x = x
      self.y = y
      self.parentX = parentX
      self.parentY = parentY
  pass

最后就是主要的畫(huà)圖了:


def drawNode(x, y ,parent,color, marker, myTree, position):
  if myTree.results == None or len(list(myTree.results.keys())) > 1:
      plt.scatter(x, y, c=color, marker=marker, s=200)

  if myTree.right == None and myTree.left == None:
      results = list(myTree.results.keys())
      plt.annotate(s = 'label == ' + str(results[0]), xy=(x - 15, y))
      if results[0] == 0.0:
         plt.annotate(s='label == 0.0', xy=(x , y))
         plt.scatter(x, y, c='orange', marker='H', s=100)
      if results[0] == 1.0:
         plt.scatter(x, y, c='pink', marker='8', s=100)
      if results[0] == 2.0:
         plt.scatter(x, y, c='r', marker='+', s=100)

  if myTree.value != None and myTree.fea != None:
      po = 5
      if position == 'right':
         plt.annotate(s = 'dimension' + str(myTree.fea) + '>' + str(round(myTree.value, 2)), xy = (x-25 - po, y))
      else:
         plt.annotate(s='dimension' + str(myTree.fea) + '>' + str(round(myTree.value, 2)), xy=(x - 25 + po, y))
  if parent != None:
     plt.plot([x, parent.x], [y, parent.y], color = 'gray', alpha = 0.5)
def draw(myTree, parent = None, x = 100, y = 100, color = 'r', marker = '^', position = None):
  NumberLeaf = getNumLeafs(myTree)
  Depth = getDepth(myTree)
  delta = (NumberLeaf+Depth)
  drawNode(x, y, parent, color, marker, myTree,position)
  if myTree.right != None:
      draw(myTree.right, parent=TreeNode(x, y) ,x=x+5*delta, y=y-5-delta,color='b', marker='x', position='right')
  if myTree.left != None:
      draw(myTree.left,parent=TreeNode(x, y) ,x=x-5*delta, y=y-2-delta, color='g', marker='o', position='left')
  pass

加上這句 plt.annotate(s='label == 0.0', xy=(x , y))是因?yàn)槟莻€(gè)注釋死活畫(huà)不出來(lái)胰耗,應(yīng)該是擋住了限次。主要還是draw函數(shù),drawNode只是畫(huà)而已柴灯,判斷都是為了加注釋的卖漫,來(lái)看看效果圖:




如果當(dāng)時(shí)學(xué)數(shù)據(jù)結(jié)構(gòu)用的是python多好!

所有代碼在GitHub上:
https://github.com/GreenArrow2017/MachineLearning/tree/master/MachineLearning/DecisionTree

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弛槐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子依啰,更是在濱河造成了極大的恐慌乎串,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異叹誉,居然都是意外死亡鸯两,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)长豁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钧唐,“玉大人,你說(shuō)我怎么就攤上這事匠襟《巯溃” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵酸舍,是天一觀的道長(zhǎng)帅韧。 經(jīng)常有香客問(wèn)我,道長(zhǎng)啃勉,這世上最難降的妖魔是什么忽舟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮淮阐,結(jié)果婚禮上叮阅,老公的妹妹穿的比我還像新娘。我一直安慰自己泣特,他們只是感情好浩姥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著群扶,像睡著了一般及刻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竞阐,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天缴饭,我揣著相機(jī)與錄音,去河邊找鬼骆莹。 笑死颗搂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的幕垦。 我是一名探鬼主播丢氢,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼先改!你這毒婦竟也來(lái)了疚察?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仇奶,失蹤者是張志新(化名)和其女友劉穎貌嫡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岛抄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年别惦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夫椭。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掸掸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹭秋,到底是詐尸還是另有隱情扰付,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布感凤,位于F島的核電站悯周,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陪竿。R本人自食惡果不足惜眯娱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一扣墩、第九天 我趴在偏房一處隱蔽的房頂上張望趾浅。 院中可真熱鬧举娩,春花似錦、人聲如沸礁哄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)桐绒。三九已至夺脾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茉继,已是汗流浹背咧叭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烁竭,地道東北人菲茬。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像派撕,于是被迫代替她去往敵國(guó)和親婉弹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容