1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【NLP】用code2vec、glow和spaCy進行詞嵌入

        共 4342字,需瀏覽 9分鐘

         ·

        2020-08-31 03:26

        作者 | Maria Malitckaya?

        編譯 | VK?

        來源 | Towards Data Science

        改進機器學習模型的一個有效方法是使用詞嵌入。使用詞嵌入,你可以捕獲文檔中單詞的上下文,然后找到語義和語法上的相似之處。

        在這篇文章中,我們將討論詞嵌入技術(shù)的一個不尋常的應(yīng)用。我們將嘗試使用OpenAPI的規(guī)范作為數(shù)據(jù)集在其中找到最好的詞嵌入技術(shù)。作為OpenAPI規(guī)范的一個例子,我們將使用OpenAPI specifications(https://swagger.io/specification/)提供的OpenAPI規(guī)范數(shù)據(jù)集。

        最大的挑戰(zhàn)是,OpenAPI規(guī)范既不是自然語言,也不是代碼。但這也意味著我們可以自由使用任何可用的嵌入模型。在這個實驗中,我們將研究三種可能可行的候選方案:code2vec、glow和spaCy。

        code2vec是一個神經(jīng)模型,可以學習與源代碼相關(guān)的類比。該模型是在Java代碼數(shù)據(jù)庫上訓練的,但是你可以將其應(yīng)用于任何代碼。

        還有GloVe。GloVe是一種常用的自然語言處理算法。它是在維基百科和Gigawords上訓練的。

        最后,我們有了spaCy。雖然spaCy是最近才發(fā)展起來的,但該算法已經(jīng)以世界上最快的詞嵌入而聞名。

        讓我們看看這些算法中哪一種更適合OpenAPI數(shù)據(jù)集,哪種算法對于OpenAPI規(guī)范的運行速度更快. 我把這篇文章分為六個部分,每個部分都包含代碼示例和一些將來使用的提示,外加一個結(jié)論。

        1. 下載數(shù)據(jù)集

        2. 下載詞匯表

        3. 提取字段名稱

        4. 標識化

        5. 創(chuàng)建字段名稱的數(shù)據(jù)集

        6. 測試嵌入

        7. 結(jié)論

        現(xiàn)在,我們可以開始了。

        1.下載數(shù)據(jù)集

        首先,我們需要下載整個apis-guru數(shù)據(jù)庫:https://apis.guru/。

        你會注意到,大多數(shù)apis-guru規(guī)范都是Swagger 2.0格式。但是,OpenAPI規(guī)范的最新版本是OpenAPI 3.0。

        因此,讓我們使用Unmock腳本將整個數(shù)據(jù)集轉(zhuǎn)換為這種格式!你可以按照Unmock openapi腳本的README文件中的說明完成此操作:https://github.com/meeshkan/unmock-openapi-scripts/blob/master/README.md。

        這可能需要一段時間,最后,你將得到一個大數(shù)據(jù)集。

        2.下載詞匯表

        「code2vec」

        1. 從code2vec GitHub頁面下載模型,按照快速入門部分中的說明進行操作。

        2. 使用gensim庫加載。

        model?=?word2vec.load_word2vec_format(vectors_text_path,?binary=False)

        「GloVe」

        1. 從網(wǎng)站下載一個GloVe詞匯表。我們選了最大的一個,因為這樣它就更有可能找到我們所有的單詞。你可以選擇下載它的位置,但為了方便起見,最好將其存儲在工作目錄中。

        2. 手動加載GloVe詞匯表。

        embeddings_dict?=?{}
        with?open("../glove/glove.6B.300d.txt",?'r',?encoding="utf-8")?as?f:
        ????for?line?in?f:
        ????????values?=?line.split()
        ????????word?=?values[0]
        ????????vector?=?np.asarray(values[1:],?"float32")
        ????????embeddings_dict[word]?=?vector

        「spaCy」

        加載spaCy的詞匯表:

        nlp?=?spacy.load(‘en_core_web_lg’).

        3.提取字段名

        OpenAPI規(guī)范名稱的整個列表可以從scripts/fetch-list.sh文件或使用以下函數(shù)(對于Windows)獲?。?/p>

        def?getListOfFiles(dirName):
        ????listOfFile?=?os.listdir(dirName)
        ????allFiles?=?list()
        ????for?entry?in?listOfFile:
        ????????fullPath?=?posixpath.join(dirName,?entry)
        ????????if?posixpath.isdir(fullPath):
        ????????????allFiles?=?allFiles?+?getListOfFiles(fullPath)
        ????????else:
        ????????????allFiles.append(fullPath)
        ????????????????
        ????return?allFiles

        另一個大問題是從我們的OpenAPI規(guī)范中獲取字段名。為此,我們將使用openapi-typed庫。讓我們定義一個get_fields函數(shù),該函數(shù)接受OpenAPI規(guī)范并返回字段名列表:

        def?get_fields_from_schema(o:?Schema)?->?Sequence[str]:
        ????return?[
        ????????*(o['properties'].keys()?if?('properties'?in?o)?and?(type(o['properties'])?==?type({}))?else?[]),
        ????????*(sum([
        ????????????get_fields_from_schema(schema)?for?schema?in?o['properties'].values()?if?not?('$ref'?in?schema)?and?type(schema)?==?type({})],?[])?if?('properties'?in?o)?and?($????????*(get_fields_from_schema(o['additionalProperties'])?if?('additionalProperties'?in?o)?and?(type(o['additionalProperties'])?==?type({}))?else?[]),
        ????????*(get_fields_from_schema(o['items'])?if?('items'?in?o)?and??(type(o['items']?==?type({})))?else?[]),
        ????]

        def?get_fields_from_schemas(o:?Mapping[str,?Union[Schema,?Reference]])?->?Sequence[str]:
        ????return?sum([get_fields_from_schema(cast(Schema,?maybe_schema))?for?maybe_schema?in?o.values()?if?not?('$ref'?in?maybe_schema)?and?(type(maybe_schema)?==?type({}))],?[])


        def?get_fields_from_components(o:?Components)?->?Sequence[str]:
        ????return?[
        ????????*(get_fields_from_schemas(o['schemas'])?if?'schemas'?in?o?else?[]),
        ????????????]???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

        def?get_fields(o:?OpenAPIObject)?->?Sequence[str]:
        ????return?[
        ????????*(get_fields_from_components(o['components'])?if?'components'?in?o?else?[]),
        ????]

        恭喜!現(xiàn)在我們的數(shù)據(jù)集準備好了。

        4.標識化

        字段名可能包含標點符號,如_和-符號,或大小寫為駝峰的單詞。我們可以把這些單詞切分,稱為標識。

        下面的camel_case函數(shù)檢查駝峰命名。首先,它檢查是否有標點符號。如果是,那就不是駝峰命名。然后,它檢查單詞內(nèi)部是否有大寫字母(不包括第一個和最后一個字符)。

        def?camel_case(example):??????
        ????if??any(x?in?example?for?x??in?string.punctuation)==True:
        ????????return?False
        ????else:
        ????????if?any(list(map(str.isupper,?example[1:-1])))==True:
        ????????????return?True
        ????????else:
        ????????????return?False

        下一個函數(shù)camel_case_split將駝峰單詞拆分為多個部分。為此,我們應(yīng)該識別大寫字母并標記大小寫更改的位置。函數(shù)返回拆分后的單詞列表。例如,字段名BodyAsJson轉(zhuǎn)換為一個列表['Body','As','Json']。

        def?camel_case_split(word):
        ????idx?=?list(map(str.isupper,?word))
        ????case_change?=?[0]
        ????for?(i,?(x,?y))?in?enumerate(zip(idx,?idx[1:])):
        ????????if?x?and?not?y:??
        ????????????case_change.append(i)
        ????????elif?not?x?and?y:??
        ????????????case_change.append(i+1)
        ????case_change.append(len(word))
        ????return?[word[x:y]?for?x,?y?in?zip(case_change,?case_change[1:])?if?x?

        這個camel_case_split函數(shù)隨后用于以下標記化算法。在這里,我們首先檢查單詞中是否有標點符號。然后,我們把這個詞分成幾部分。這些詞有可能是駝峰詞。如果是這樣的話,我們可以把它分成小塊。最后,拆分每個元素后,整個列表將轉(zhuǎn)換為小寫。

        def?tokenizer(mylist):
        ????tokenized_list=[]
        ????for?word?in?mylist:

        ????????if?'_'??in?word:
        ????????????splitted_word=word.split('_')
        ????????????for?elem?in?splitted_word:
        ????????????????if?camel_case(elem):
        ????????????????????elem=camel_case_split(elem)
        ????????????????????for?el1?in?elem:
        ????????????????????????tokenized_list.append(el1.lower())
        ????????????????else:????
        ????????????????????tokenized_list.append(elem.lower())
        ????????elif?'-'?in?word:
        ????????????hyp_word=word.split('-')
        ????????????for?i?in?hyp_word:
        ????????????????if?camel_case(i):
        ????????????????????i=camel_case_split(i)
        ????????????????????for?el2?in?i:
        ????????????????????????tokenized_list.append(el2.lower())
        ????????????????else:?
        ????????????????????tokenized_list.append(i.lower())
        ????????elif?camel_case(word):
        ????????????word=camel_case_split(word)
        ????????????for?el?in?word:
        ????????????????tokenized_list.append(el.lower())
        ????????else:
        ????????????tokenized_list.append(word.lower())
        ????return(tokenized_list)
        tokenizer(my_word)

        5.創(chuàng)建字段名的數(shù)據(jù)集

        現(xiàn)在,讓我們用所有規(guī)范中的字段名創(chuàng)建一個大數(shù)據(jù)集。

        下面的dict_dataset函數(shù)獲取文件名和路徑的列表,并打開每個規(guī)范文件。對于每個文件,get_field函數(shù)返回字段名的列表。某些字段名稱可能在一個規(guī)范中重復(fù)。為了避免這種重復(fù),讓我們使用list(dict.fromkeys(col))將列表中的字段名列表轉(zhuǎn)換為字典,然后再返回。然后我們可以將列表標識化。最后,我們創(chuàng)建一個以文件名為鍵,以字段名列表為值的字典。

        def?dict_dataset(datasets):
        ????dataset_dict={}
        ????for?i?in?datasets:
        ????????with?open(i,?'r')?as?foo:
        ????????????col=algo.get_fields(yaml.safe_load(foo.read()))
        ????????????if?col:
        ????????????????mylist?=?list(dict.fromkeys(col))
        ????????????????tokenized_list=tokenizer(mylist)
        ????????????????dataset_dict.update({i:?tokenized_list})
        ????????????else:
        ????????????????continue
        ????return?(dataset_dict)

        6.測試嵌入

        「code2vec和GloVe」

        現(xiàn)在我們可以找出詞匯表外的單詞(未識別的單詞)并計算這些單詞在code2vec詞匯表中所占的百分比。以下代碼也適用于GloVe。

        not_identified_c2v=[]
        count_not_indent=[]
        total_number=[]

        for?ds?in?test1:
        ????count=0
        ????for?i?in?data[ds]:
        ????????if?not?i?in?model:
        ????????????not_identified_c2v.append(i)
        ????????????count+=1
        ????count_not_indent.append(count)
        ????total_number.append(len(data[ds]))

        total_code2vec=sum(count_not_indent)/sum(total_number)*100

        「spaCy」

        spaCy詞匯表不同,因此我們需要相應(yīng)地修改代碼:

        not_identified_sp=[]
        count_not_indent=[]
        total_number=[]

        for?ds?in?test1:
        ????count=0
        ????for?i?in?data[ds]:
        ????????f?not?i?in?nlp.vocab:
        ????????????????count+=1
        ????????????????not_identified_sp.append(i)
        ????count_not_indent.append(count)
        ????total_number.append(len(data[ds]))

        ????????
        total_spacy=sum(count_not_indent)/sum(total_number)*100

        對于code2vec、glow和spaCy,未識別單詞的百分比分別為3.39、2.33和2.09。由于每個算法的百分比相對較小且相似,因此我們可以進行另一個測試。

        首先,讓我們創(chuàng)建一個測試字典,其中的單詞應(yīng)該在所有API規(guī)范中都是相似的:

        test_dictionary={'host':?'server',
        'pragma':?'cache',
        'id':?'uuid',
        'user':?'client',
        'limit':?'control',
        'balance':?'amount',
        'published':?'date',
        'limit':?'dailylimit',
        'ratelimit':?'rate',
        'start':?'display',
        'data':?'categories'}

        對于GloVe和code2vec,我們可以使用gensim庫提供的similar_by_vector方法。spaCy還沒有實現(xiàn)這個方法,但是通過這個我們可以自己找到最相似的單詞。

        為此,我們需要格式化輸入向量,以便在距離函數(shù)中使用。我們將在字典中創(chuàng)建每個鍵,并檢查對應(yīng)的值是否在100個最相似的單詞中。

        首先,我們將格式化詞匯表以便使用distance.cdist函數(shù)。這個函數(shù)計算詞匯表中每對向量之間的距離。然后,我們將從最小距離到最大距離對列表進行排序,并取前100個單詞。

        from?scipy.spatial?import?distance

        for?k,?v?in?test_dictionary.items():
        ????input_word?=?k
        ????p?=?np.array([nlp.vocab[input_word].vector])
        ????closest_index?=?distance.cdist(p,?vectors)[0].argsort()[::-1][-100:]
        ????word_id?=?[ids[closest_ind]?for?closest_ind?in?closest_index]
        ????output_word?=?[nlp.vocab[i].text?for?i?in?word_id]
        ????#output_word
        ????list1=[j.lower()?for?j?in?output_word]
        ????mylist?=?list(dict.fromkeys(list1))[:50]
        ????count=0
        ????if?test_dictionary[k]?in?mylist:
        ????????count+=1
        ????????print(k,count,?'yes')
        ????else:
        ????????print(k,?'no')

        下表總結(jié)了結(jié)果。spaCy顯示單詞“client”位于單詞“user”的前100個最相似的單詞中。它對幾乎所有的OpenAPI規(guī)范都是有用的,并且可以用于將來OpenAPI規(guī)范相似性的分析。單詞“balance”的向量接近單詞“amount”的向量。我們發(fā)現(xiàn)它對支付API特別有用。

        結(jié)論

        我們已經(jīng)為OpenAPI規(guī)范嘗試了三種不同的詞嵌入算法。盡管這三個詞在這個數(shù)據(jù)集上都表現(xiàn)得很好,但是對最相似的單詞進行額外的比較表明spaCy對我們的情況更好。

        spaCy比其他算法更快。spaCy詞匯表的讀取速度比glow或code2vec詞匯表快5倍。然而,在使用該算法時,缺少內(nèi)置函數(shù)(如similar_by_vector和similar_word)是一個障礙。

        另外,spaCy與我們的數(shù)據(jù)集很好地工作,這并不意味著spaCy對世界上的每個數(shù)據(jù)集都會更好。所以,請隨意嘗試為你自己的數(shù)據(jù)集嵌入不同的單詞,感謝你的閱讀!

        原文鏈接:https://towardsdatascience.com/word-embeddings-with-code2vec-glove-and-spacy-5b26420bf632



        往期精彩回顧





        獲取一折本站知識星球優(yōu)惠券,復(fù)制鏈接直接打開:

        https://t.zsxq.com/662nyZF

        本站qq群1003271085。

        加入微信群請掃碼進群(如果是博士或者準備讀博士請說明):

        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            全免费A级毛片在线视频微信 | 欧美午夜羞羞羞免费视频app | 天天日天天操天天舔 | 男女洗澡一边做一边摸 | 男人女人性生活视频 | 日韩人妻一区 | 柚子TV| ass中国女演员裸体pics | 免费看a毛片 | 大香蕉伊人7 |