一文概覽NLP算法(Python)

一姐呐、自然語言處理(NLP)簡介

自然語言處理就是用計算機(jī)來分析和生成自然語言(文本聚至、語音)化戳,目的是讓人類可以用自然語言形式跟計算機(jī)系統(tǒng)進(jìn)行人機(jī)交互,從而更便捷切平、有效地進(jìn)行信息管理握础。

NLP是人工智能領(lǐng)域歷史較為悠久的領(lǐng)域,但由于語言的復(fù)雜性(語言表達(dá)多樣性/歧義/模糊等等)悴品,如今的發(fā)展及收效相對緩慢禀综。比爾·蓋茨曾說過简烘,"NLP是 AI 皇冠上的明珠。" 在光鮮絢麗的同時定枷,卻可望而不可及(...)孤澎。


為了揭開NLP的神秘面紗,本文接下來會梳理下NLP流程依鸥、主要任務(wù)及算法,并最終落到實際NLP項目(經(jīng)典的文本分類任務(wù)的實戰(zhàn))悼沈。順便說一句贱迟,個人水平有限,不足之處還請留言指出~~

二絮供、NLP主要任務(wù)及技術(shù)

NLP任務(wù)可以大致分為詞法分析衣吠、句法分析、語義分析三個層面壤靶。具體的缚俏,本文按照單詞-》句子-》文本做順序展開,并介紹各個層面的任務(wù)及對應(yīng)技術(shù)贮乳。本節(jié)上半部分的分詞忧换、命名實體識別、詞向量等等可以視為NLP基礎(chǔ)的任務(wù)向拆。下半部分的句子關(guān)系亚茬、文本生成及分類任務(wù)可以看做NLP主要的應(yīng)用任務(wù)。


這里浓恳,貼一張自然語言處理的技術(shù)路線圖刹缝,介紹了NLP任務(wù)及主流模型的分支:

高清圖可如下路徑下載(原作者graykode):https://github.com/aialgorithm/AiPy/tree/master/Ai%E7%9F%A5%E8%AF%86%E5%9B%BE%E5%86%8C/Ai_Roadmap

2.1 數(shù)據(jù)清洗 + 分詞(系列標(biāo)注任務(wù))

  • 數(shù)據(jù)語料清洗。我們拿到文本的數(shù)據(jù)語料(Corpus)后颈将,通常首先要做的是梢夯,分析并清洗下文本,主要用正則匹配刪除掉數(shù)字及標(biāo)點符號(一般這些都是噪音晴圾,對于實際任務(wù)沒有幫助)颂砸,做下分詞后,刪掉一些無關(guān)的詞(停用詞)死姚,對于英文還需要統(tǒng)一下復(fù)數(shù)沾凄、語態(tài)、時態(tài)等不同形態(tài)的單詞形式知允,也就是詞干/詞形還原撒蟀。

  • 分詞。即劃分為詞單元(token)温鸽,是一個常見的序列標(biāo)注任務(wù)保屯。對于英文等拉丁語系的語句分詞手负,天然可以通過空格做分詞,

    對于中文語句姑尺,由于中文詞語是連續(xù)的竟终,可以用結(jié)巴分詞(基于trie tree+維特比等算法實現(xiàn)最大概率的詞語切分)等工具實現(xiàn)。

import jieba
jieba.lcut("我的地址是上海市松江區(qū)中山街道華光藥房")

>>> ['我', '的', '地址', '是', '上海市', '松江區(qū)', '中山', '街道', '華光', '藥房']

  • 英文分詞后的詞干/詞形等還原(去除時態(tài) 語態(tài)及復(fù)數(shù)等信息切蟋,統(tǒng)一為一個“單詞”形態(tài))统捶。這并不是必須的,還是根據(jù)實際任務(wù)是否需要保留時態(tài)柄粹、語態(tài)等信息喘鸟,有WordNetLemmatizer、 SnowballStemmer等方法驻右。

  • 分詞及清洗文本后什黑,還需要對照前后的效果差異,在做些微調(diào)堪夭。這里可以統(tǒng)計下個單詞的頻率愕把、句長等指標(biāo),還可以通過像詞云等工具做下可視化~

from wordcloud import WordCloud
ham_msg_cloud = WordCloud(width =520, height =260,max_font_size=50, background_color ="black", colormap='Blues').generate(原文本語料)
plt.figure(figsize=(16,10))
plt.imshow(ham_msg_cloud, interpolation='bilinear')
plt.axis('off') # turn off axis
plt.show()

2.2 詞性標(biāo)注(系列標(biāo)注任務(wù))

詞性標(biāo)注是對句子中的成分做簡單分析森爽,區(qū)分出分名詞恨豁、動詞、形容詞之類爬迟。對于句法分析圣絮、信息抽取的任務(wù),經(jīng)過詞性標(biāo)注后的文本會帶來很大的便利性(其他方面的應(yīng)用好像比較少)雕旨。

常用的詞性標(biāo)注有基于規(guī)則扮匠、統(tǒng)計以及深度學(xué)習(xí)的方法,像HanLP凡涩、結(jié)巴分詞等工具都有這個功能棒搜。

2.3 命名實體識別(系列標(biāo)注任務(wù))

命名實體識別(Named Entity Recognition,簡稱NER)是一個有監(jiān)督的系列標(biāo)注任務(wù)活箕,又稱作“專名識別”力麸,是指識別文本中具有特定意義的實體,主要包括人名育韩、地名克蚂、機(jī)構(gòu)名、時間筋讨、專有名詞等關(guān)鍵信息埃叭。


通過NER識別出一些關(guān)鍵的人名、地名就可以很方便地提取出“某人去哪里悉罕,做什么事的信息”赤屋,很方便信息提取立镶、問答系統(tǒng)等任務(wù)。NER主流的模型實現(xiàn)有BiLSTM-CRF类早、Bert-CRF媚媒,如下一個簡單的中文ner項目:https://github.com/Determined22/zh-NER-TF

2.4 詞向量(表示學(xué)習(xí))

對于自然語言文本,計算機(jī)無法理解詞后面的含義涩僻。輸入模型前缭召,首先要做的就是詞的數(shù)值化表示,常用的轉(zhuǎn)化方式有2種:One-hot編碼逆日、詞嵌入分布式方法嵌巷。

  • One-hot編碼:最簡單的表示方法某過于onehot表示,每個單詞是否出現(xiàn)就用一位數(shù)單獨展示屏富。進(jìn)一步晴竞,句子的表示也就是累加每個單詞的onehot蛙卤,也就是常說的句子的詞袋模型(bow)表示狠半。
## 詞袋表示
from sklearn.feature_extraction.text import CountVectorizer
bow = CountVectorizer(
                analyzer = 'word',
                strip_accents = 'ascii',
                tokenizer = [],
                lowercase = True,
                max_features = 100, 
                )
  • 詞嵌入分布式表示:自然語言的單詞數(shù)是成千上萬的,One-hot編碼會有高維颤难、詞語間無聯(lián)系的缺陷神年。這時有一種更有效的方法就是——詞嵌入分布式表示,通過神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)構(gòu)造一個低維行嗤、稠密已日,隱含詞語間關(guān)系的向量表示。常見有Word2Vec栅屏、Fasttext飘千、Bert等模型學(xué)習(xí)每個單詞的向量表示,在表示學(xué)習(xí)后相似的詞匯在向量空間中是比較接近的栈雳。


# Fasttext embed模型
from gensim.models import FastText,word2vec

model = FastText(text,  size=100,sg=1, window=3, min_count=1, iter=10, min_n=3, max_n=6,word_ngrams=1,workers=12)
print(model.wv['hello']) # 詞向量
model.save('./data/fasttext100dim')

特別地护奈,正因為Bert等大規(guī)模自監(jiān)督預(yù)訓(xùn)練方法,又為NLP帶來了春天~


  • 對于學(xué)習(xí)后的詞表示向量哥纫,還可以通過重要程度進(jìn)行特征加權(quán)霉旗,合適的加權(quán)方法對于任務(wù)可以有不錯的提升效果。常用的有卡方chi2蛀骇、TF-IDF等加權(quán)方法厌秒。TF-IDF是一種基于統(tǒng)計的方法,其核心思想是假設(shè)字詞的重要性與其在某篇文章中出現(xiàn)的比例成正比擅憔,與其在其他文章中出現(xiàn)的比例成反比鸵闪。


# TF-IDF可以直接調(diào)用sklearn
from sklearn.feature_extraction.text import TfidfTransformer

2.5 句法、語義依存分析

句法暑诸、語義依存分析是傳統(tǒng)自然語言的基礎(chǔ)句子級的任務(wù)岛马,語義依存分析是指在句子結(jié)構(gòu)中分析實詞和實詞之間的語義關(guān)系棉姐,這種關(guān)系是一種事實上或邏輯上的關(guān)系,且只有當(dāng)詞語進(jìn)入到句子時才會存在啦逆。語義依存分析的目的即回答句子的”Who did what to whom when and where”的問題伞矩。例如句子“張三昨天告訴李四一個秘密”,語義依存分析可以回答四個問題夏志,即誰告訴了李四一個秘密乃坤,張三告訴誰一個秘密,張三什么時候告訴李四一個秘密沟蔑,張三告訴李四什么湿诊。


傳統(tǒng)的自然語言處理多是參照了語言學(xué)家對于自然語言的歸納總結(jié),通過句法瘦材、語義分析可以挖掘出詞語間的聯(lián)系(主謂賓厅须、施事受事等關(guān)系),用于制定文本規(guī)則食棕、信息抽壤屎汀(如正則匹配疊加語義規(guī)則應(yīng)用于知識抽取或者構(gòu)造特征)〔鞠可以參考spacy庫眶拉、哈工大NLP的示例:http://ltp.ai/demo.html

隨著深度學(xué)習(xí)技術(shù)RNN/LSTM等強(qiáng)大的時序模型(sequential modeling)和詞嵌入方法的普及,能夠在一定程度上刻畫句子的隱含語法結(jié)構(gòu)憔儿,學(xué)習(xí)到上下文信息忆植,已經(jīng)逐漸取代了詞法、句法等傳統(tǒng)自然語言處理流程谒臼。

2.6 相似度算法(句子關(guān)系的任務(wù))

自然語言處理任務(wù)中朝刊,我們經(jīng)常需要判斷兩篇文檔的相似程度(句子關(guān)系),比如檢索系統(tǒng)輸出最相關(guān)的文本蜈缤,推薦系統(tǒng)推薦相似的文章拾氓。文本相似度匹配常用到的方法有:文本編輯距離、WMD劫樟、 BM2.5痪枫、詞向量相似度 、Approximate Nearest Neighbor以及一些有監(jiān)督的(神經(jīng)網(wǎng)絡(luò))模型判斷文本間相似度叠艳。

2.7 文本分類任務(wù)

文本分類是經(jīng)典的NLP任務(wù)奶陈,就是將文本系列對應(yīng)預(yù)測到類別。

  • 一種是輸入序列輸出這整個序列的類別附较,如短信息吃粒、微博分類、意圖識別等拒课。
  • 另一種是輸入序列輸出序列上每個位置的類別徐勃,上文提及的系列標(biāo)注可以看做為詞粒度的一種分類任務(wù)事示,如實體命名識別。

分類任務(wù)使用預(yù)訓(xùn)練+(神經(jīng)網(wǎng)絡(luò))分類模型的端對端學(xué)習(xí)是主流僻肖,深度學(xué)習(xí)學(xué)習(xí)特征的表達(dá)然后進(jìn)行分類肖爵,大大減少人工的特征。但以實際項目中的經(jīng)驗來看臀脏,對于一些困難任務(wù)(任務(wù)的噪聲大)劝堪,加入些人工的特征工程還是很有必要的。


2.8 文本生成任務(wù)

文本生成也就是由類別生成序列 或者 由序列到序列的預(yù)測任務(wù)揉稚。按照不同的輸入劃分秒啦,文本自動生成可包括文本到文本的生成(text-to-text generation)、意義到文本的生成(meaning-to-text generation)搀玖、數(shù)據(jù)到文本的生成(data-to-text generation)以及圖像到文本的生成(image-to-text generation)等余境。具體應(yīng)用如機(jī)器翻譯、文本摘要理解灌诅、閱讀理解芳来、閑聊對話、寫作延塑、看圖說話绣张。 常用的模型如RNN答渔、CNN关带、seq2seq、Transformer沼撕。


同樣的宋雏,基于大規(guī)模預(yù)訓(xùn)練模型的文本生成也是一大熱門,可見《A Survey of Pretrained Language Models Based Text Generation》

三务豺、垃圾短信文本分類實戰(zhàn)

3.1 讀取短信文本數(shù)據(jù)并展示

本項目是通過有監(jiān)督的短信文本磨总,學(xué)習(xí)一個垃圾短信文本分類模型。數(shù)據(jù)樣本總的有5572條笼沥,label有spam(垃圾短信)和ham兩種蚪燕,是一個典型類別不均衡的二分類問題。


# 源碼可見https://github.com/aialgorithm/Blog
import pandas as pd
import numpy as np
import  matplotlib.pyplot as plt

spam_df = pd.read_csv('./data/spam.csv', header=0, encoding="ISO-8859-1")

# 數(shù)據(jù)展示
_, ax = plt.subplots(1,2,figsize=(10,5))
spam_df['label'].value_counts().plot(ax=ax[0], kind="bar", rot=90, title='label');
spam_df['label'].value_counts().plot(ax=ax[1], kind="pie", rot=90, title='label', ylabel='');
print("Dataset size: ", spam_df.shape)

spam_df.head(5)

3.2 數(shù)據(jù)清洗預(yù)處理

數(shù)據(jù)清洗在于去除一些噪聲信息奔浅,這里對短信文本做按空格分詞馆纳,統(tǒng)一大小寫,清洗非英文字符汹桦,去掉停用詞并做了詞干還原鲁驶。考慮到短信文本里面的數(shù)字位數(shù)可能有一定的含義舞骆,這里將數(shù)字替換為‘x’的處理钥弯。最后径荔,將標(biāo)簽統(tǒng)一為數(shù)值(0、1)是否垃圾短信脆霎。

# 導(dǎo)入相關(guān)的庫
import nltk
from nltk import word_tokenize
from nltk.corpus import stopwords
from nltk.data import load
from nltk.stem import SnowballStemmer
from string import punctuation

import re  # 正則匹配
stop_words = set(stopwords.words('english'))
non_words = list(punctuation)


# 詞形总处、詞干還原
# from nltk.stem import WordNetLemmatizer
# wnl = WordNetLemmatizer()
stemmer = SnowballStemmer('english')
def stem_tokens(tokens, stemmer):
    stems = []
    for token in tokens:
        stems.append(stemmer.stem(token))
    return stems

### 清除非英文詞匯并替換數(shù)值x
def clean_non_english_xdig(txt,isstem=True, gettok=True):
    txt = re.sub('[0-9]', 'x', txt) # 去數(shù)字替換為x
    txt = txt.lower() # 統(tǒng)一小寫
    txt = re.sub('[^a-zA-Z]', ' ', txt) #去除非英文字符并替換為空格
    word_tokens = word_tokenize(txt) # 分詞
    if not isstem: #是否做詞干還原
        filtered_word = [w for w in word_tokens if not w in stop_words]  # 刪除停用詞
    else:
        filtered_word = [stemmer.stem(w) for w in word_tokens if not w in stop_words]   # 刪除停用詞及詞干還原
    if gettok:   #返回為字符串或分詞列表
        return filtered_word
    else:
        return " ".join(filtered_word)

spam_df['token'] = spam_df.message.apply(lambda x:clean_non_english_xdig(x))
spam_df.head(3)

# 數(shù)據(jù)清洗
spam_df['token'] = spam_df.message.apply(lambda x:clean_non_english_xdig(x))

# 標(biāo)簽整數(shù)編碼
spam_df['label'] = (spam_df.label=='spam').astype(int)

spam_df.head(3)

3.3 fasttext詞向量表示學(xué)習(xí)

我們需要將單詞文本轉(zhuǎn)化為數(shù)值的詞向量才能輸入模型睛蛛。詞向量表示常用的詞袋辨泳、fasttext、bert等方法菠红,這里訓(xùn)練的是fasttext摹闽,模型的主要輸入?yún)?shù)是蚜迅,輸入分詞后的語料(通常訓(xùn)練語料越多越好,當(dāng)現(xiàn)有語料有限時候亡蓉,直接拿github上合適的大規(guī)模預(yù)訓(xùn)練模型來做詞向量也是不錯的選擇)晕翠,詞向量的維度size(一個經(jīng)驗的詞向量維度設(shè)定是,dim > 8.33 logN, N為詞匯表的大小,當(dāng)維度dim足夠大才能表達(dá)好這N規(guī)模的詞匯表的含義淋肾《保可參考《# 最小熵原理(六):詞向量的維度應(yīng)該怎么選擇可霎? By 蘇劍林》)龄恋。語料太大的時候可以使用workers開啟多進(jìn)程訓(xùn)練(其他參數(shù)及詞表示學(xué)習(xí)原理后續(xù)會專題介紹短蜕,也可以自行了解)。

# 訓(xùn)練詞向量 Fasttext embed模型
from gensim.models import FastText,word2vec

fmodel = FastText(spam_df.token,  size=100,sg=1, window=3, min_count=1, iter=10, min_n=3, max_n=6,word_ngrams=1,workers=12)
print(fmodel.wv['hello']) # 輸出hello的詞向量
# fmodel.save('./data/fasttext100dim')

按照句子所有的詞向量取平均碌尔,為每一句子生成句向量浇辜。

fmodel = FastText.load('./data/fasttext100dim')

#對每個句子的所有詞向量取均值,來生成一個句子的vector
def build_sentence_vector(sentence,w2v_model,size=100):
    sen_vec=np.zeros((size,))
    count=0
    for word in sentence:
        try:
            sen_vec+=w2v_model[word]#.reshape((1,size))
            count+=1
        except KeyError:
            continue
    if count!=0:
        sen_vec/=count
    return sen_vec

# 句向量
sents_vec = []
for sent in spam_df['token']:
    sents_vec.append(build_sentence_vector(sent,fmodel,size=100))
        
print(len(sents_vec))

3.4 訓(xùn)練文本分類模型

示例采用的fasttext embedding + lightgbm的二分類模型唾戚,類別不均衡使用lgb代價敏感學(xué)習(xí)解決(即class_weight='balanced')柳洋,超參數(shù)是手動簡單配置的,可以自行搜索下較優(yōu)超參數(shù)叹坦。

### 訓(xùn)練文本分類模型
from sklearn.model_selection import train_test_split
from lightgbm import LGBMClassifier
from sklearn.linear_model import LogisticRegression

train_x, test_x, train_y, test_y = train_test_split(sents_vec, spam_df.label,test_size=0.2,shuffle=True,random_state=42)
result = []
clf = LGBMClassifier(class_weight='balanced',n_estimators=300, num_leaves=64, reg_alpha= 1,reg_lambda= 1,random_state=42)
#clf = LogisticRegression(class_weight='balanced',random_state=42)

clf.fit(train_x,train_y)

import pickle
# 保存模型
pickle.dump(clf, open('./saved_models/spam_clf.pkl', 'wb'))

# 加載模型
model = pickle.load(open('./saved_models/spam_clf.pkl', 'rb'))

3.5 模型評估

訓(xùn)練集測試集按0.2劃分熊镣,分布驗證訓(xùn)練集測試集的AUC、F1score等指標(biāo)募书,均有不錯的表現(xiàn)绪囱。


from sklearn.metrics import auc,roc_curve,f1_score,precision_score,recall_score
def model_metrics(model, x, y,tp='auc'):
    """ 評估 """
    yhat = model.predict(x)
    yprob = model.predict_proba(x)[:,1]
    fpr,tpr,_ = roc_curve(y, yprob,pos_label=1)
    metrics = {'AUC':auc(fpr, tpr),'KS':max(tpr-fpr),
               'f1':f1_score(y,yhat),'P':precision_score(y,yhat),'R':recall_score(y,yhat)}
    
    roc_auc = auc(fpr, tpr)

    plt.plot(fpr, tpr, 'k--', label='ROC (area = {0:.2f})'.format(roc_auc), lw=2)

    plt.xlim([-0.05, 1.05])  # 設(shè)置x、y軸的上下限莹捡,以免和邊緣重合鬼吵,更好的觀察圖像的整體
    plt.ylim([-0.05, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')  # 可以使用中文,但需要導(dǎo)入一些庫即字體
    plt.title('ROC Curve')
    plt.legend(loc="lower right")


    return metrics

print('train ',model_metrics(clf,  train_x, train_y,tp='ks'))
print('test ',model_metrics(clf, test_x,test_y,tp='ks'))
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末篮赢,一起剝皮案震驚了整個濱河市齿椅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荷逞,老刑警劉巖媒咳,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粹排,死亡現(xiàn)場離奇詭異种远,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)顽耳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門坠敷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人射富,你說我怎么就攤上這事膝迎。” “怎么了胰耗?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵限次,是天一觀的道長。 經(jīng)常有香客問我,道長卖漫,這世上最難降的妖魔是什么费尽? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮羊始,結(jié)果婚禮上旱幼,老公的妹妹穿的比我還像新娘。我一直安慰自己突委,他們只是感情好柏卤,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著匀油,像睡著了一般缘缚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敌蚜,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天忙灼,我揣著相機(jī)與錄音,去河邊找鬼钝侠。 笑死该园,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帅韧。 我是一名探鬼主播里初,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忽舟!你這毒婦竟也來了双妨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤叮阅,失蹤者是張志新(化名)和其女友劉穎刁品,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浩姥,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡挑随,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了勒叠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜挨。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖眯分,靈堂內(nèi)的尸體忽然破棺而出拌汇,到底是詐尸還是另有隱情,我是刑警寧澤弊决,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布噪舀,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏与倡。R本人自食惡果不足惜先改,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒸走。 院中可真熱鬧仇奶,春花似錦、人聲如沸比驻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽别惦。三九已至狈茉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掸掸,已是汗流浹背氯庆。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留扰付,地道東北人堤撵。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像羽莺,于是被迫代替她去往敵國和親实昨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

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