nltk wor dnet лемматизация с помощью POS-тега на фрейме данных pyspark - PullRequest
0 голосов
/ 22 января 2020

Я обрабатываю текстовые данные в фрейме данных pyspark. До сих пор мне удалось токенизировать данные в виде столбца массивов и создать следующую таблицу:

print(df.schema)

StructType(List(StructField(_c0,IntegerType,true),StructField(pageid,IntegerType,true),StructField(title,StringType,true),StructField(text,ArrayType(StringType,true),true)))

df.show(5)

+---+------+-------------------+--------------------+
|_c0|pageid|              title|                text|
+---+------+-------------------+--------------------+
|  0|137277|    Sutton, Vermont|[sutton, is, town...|
|  1|137278|    Walden, Vermont|[walden, is, town...|
|  2|137279| Waterford, Vermont|[waterford, is, t...|
|  3|137280|West Burke, Vermont|[west, burke, is,...|
|  4|137281|  Wheelock, Vermont|[wheelock, is, to...|
+---+------+-------------------+--------------------+
only showing top 5 rows

Затем я попытался лемматизировать их с помощью функций udf


def get_wordnet_pos(treebank_tag):
    """
    return WORDNET POS compliance to WORDENT lemmatization (a,n,r,v) 
        """
    if treebank_tag.startswith('J'):
            return wordnet.ADJ
    elif treebank_tag.startswith('V'):
            return wordnet.VERB
    elif treebank_tag.startswith('N'):
            return wordnet.NOUN
    elif treebank_tag.startswith('R'):
            return wordnet.ADV
    else:
    # As default pos in lemmatization is Noun
        return wordnet.NOUN


def postagger(p):
    import nltk
    x =  list(nltk.pos_tag(p))
    return x

sparkPosTagger = udf(lambda z: postagger(z),ArrayType(StringType()))

def lemmer(postags):
    import nltk
    from nltk.stem import WordNetLemmatizer
    lemmatizer = WordNetLemmatizer()
    x = [lemmatizer.lemmatize(word, get_wordnet_pos(pos_tag)) for [word,pos_tag] in nltk.pos_tag(postags)]
    return x

sparkLemmer = udf(lambda z: lemmer(z), ArrayType(StringType()))

#df = df.select('_c0','pageid','title','text', sparkPosTagger("text").alias('lemm'))
df = df.select('_c0','pageid','title','text', sparkLemmer("lemm").alias('lems'))


, которая возвращает это ошибка:

PicklingError: args[0] from __newobj__ args has the wrong class

Я полагаю, что ошибка в основном происходит из-за несовместимости с объектом, который создает nltk.pos_tag (postags). Обычно, когда предоставляется список токенов, nltk.pos_tag () создает список кортежей.

Хотя я застрял в поиске обходного пути. Как вы можете видеть из кода, я пытался заранее разделить процесс с помощью pos_tagging отдельно, только чтобы получить ту же ошибку.

Есть ли способ заставить эту работу?

1 Ответ

0 голосов
/ 23 января 2020

Вопреки тому, что я подозревал, проблема была на самом деле из-за начальной функции:

def get_wordnet_pos(treebank_tag):
    """
    return WORDNET POS compliance to WORDENT lemmatization (a,n,r,v) 
        """
    if treebank_tag.startswith('J'):
            return wordnet.ADJ
    elif treebank_tag.startswith('V'):
            return wordnet.VERB
    elif treebank_tag.startswith('N'):
            return wordnet.NOUN
    elif treebank_tag.startswith('R'):
            return wordnet.ADV
    else:
    # As default pos in lemmatization is Noun
        return wordnet.NOUN

, которая в обычном python работает нормально. Однако в pyspark при импорте nltk возникает драма, и поэтому вызов wor dnet проблематичен c. Были аналогичные проблемы, когда другие пытались импортировать стоп-слова:

pickle.PicklingError: args [0] из __newobj__ args имеет неправильный класс со значением oop python

, хотя я не решил причину root, я изменил код из того, что я увидел в Интернете, как практический обходной путь для удаления ссылок на wor dnet (в любом случае был ненужен):

def get_wordnet_pos(treebank_tag):
    """
    return WORDNET POS compliance to WORDENT lemmatization (a,n,r,v) 
        """
    if treebank_tag.startswith('J'):
            return 'a'
    elif treebank_tag.startswith('V'):
            return 'v'
    elif treebank_tag.startswith('N'):
            return 'n'
    elif treebank_tag.startswith('R'):
            return 'r'
    else:
    # As default pos in lemmatization is Noun
        return 'n'


def lemmatize1(data_str):
    # expects a string
    list_pos = 0
    cleaned_str = ''
    lmtzr = WordNetLemmatizer()
    #text = data_str.split()
    tagged_words = nltk.pos_tag(data_str)
    for word in tagged_words:
        lemma = lmtzr.lemmatize(word[0], get_wordnet_pos(word[1]))
        if list_pos == 0:
            cleaned_str = lemma
        else:
            cleaned_str = cleaned_str + ' ' + lemma
        list_pos += 1
    return cleaned_str

sparkLemmer1 = udf(lambda x: lemmatize1(x), StringType())
...