Застрял с ForLoop и вставкой фрейма данных

#python #pandas #dataframe #for-loop

#питон #панды #фрейм данных #for-цикл #python

Вопрос:

У меня есть этот фрейм данных:

     manufacturer    description
0   toyota          toyota, gmc 10 years old.
1   NaN             gmc, Motor runs and drives good.
2   NaN             Motor old, in pieces.
3   NaN             2 owner 0 rust. Cadillac.
  

И я хочу заполнить значения NaN ключевым словом, взятым из описания. С этой целью я создал список с нужными мне ключевыми словами:

 keyword = ['gmc', 'toyota', 'cadillac']
  

Наконец, я хочу перебрать каждую строку в фрейме данных. Разделите содержимое столбца «описание» в каждой строке и, если это слово также есть в списке «ключевое слово», добавьте его в столбец «производитель». В качестве примера, это будет выглядеть так:

     manufacturer    description
0   toyota          toyota, gmc 10 years old.
1   gmc             gmc, Motor runs and drives good.
2   NaN             Motor old, in pieces.
3   cadillac        2 owner 0 rust. Cadillac.
  

Благодаря дружелюбному человеку в этом сообществе я смог улучшить свой код до этого:

 import re
keyword = ['gmc', 'toyota', 'cadillac']
bag_of_words = []
for i, description in enumerate(test3['description']):
bag_of_words = re.findall(r"""[A-Za-z-] """, test3["description"][i])
for word in bag_of_words: 
    if word.lower() in keyword:
            test3.loc[i, 'manufacturer'] = word.lower()
  

Но я понял, что первая строка также изменила значения, хотя это был не NaN:

   manufacturer  description
0   gmc         toyota, gmc 10 years old.
1   gmc         gmc, Motor runs and drives good.
2   NaN         Motor old, in pieces.
3   cadillac    2 owner 0 rust. Cadillac.
  

Я хотел бы изменить только значения NaN, но когда я пытаюсь добавить:

 if word.lower() in keyword and test3.loc[i, 'manufacturer'] == np.nan:
  

Это не имеет никакого эффекта.

Ответ №1:

Вот быстрое решение. Вы сделали несколько вещей неправильно:

  • Смешивание индекса описания и самого описания (решается enumerate() ).
  • bag_of_words должно обновляться для каждого слова, а не добавляться.
  • Повторяется неправильный элемент (должен быть word , нет bag_of_words ).

Некоторые ошибки можно легко увидеть, если были выбраны интуитивно понятные / обычные имена. Потратьте на это некоторое время.

Код:

 from nltk.tokenize import RegexpTokenizer

# test3 = the main dataset
keyword = ['gmc', 'toyota', 'cadillac']

tokenizer = RegexpTokenizer('w |$[d.] |S ')

for i, description in enumerate(test3['description']):
    bag_of_words = tokenizer.tokenize(description.lower())
    for word in bag_of_words:
        if word in keyword:
            test3.loc[i, 'manufacturer'] = word
  

Вывод:

 test3
Out[31]: 
  manufacturer                       description
0       toyota             toyota, 10 years old.
1          gmc  gmc, Motor runs and drives good.
2          NaN             Motor old, in pieces.
3     cadillac         2 owner 0 rust. Cadillac.
  

re.findall() поверх RegexpTokenizer

Я лично считаю nltk , что это относительно тяжелый модуль для импорта, установки и развертывания. Если необходимо выполнить только разделение строки, я бы рекомендовал использовать re.findall для извлечения допустимых шаблонов слов. Например:

 import re

# won't extract numbers, currency signs and apostrophes
re.findall(r"""[A-Za-z-] """, test3["description"][3])

# the output is much cleaner than before
Out[39]: ['owner', 'rust', 'Cadillac']
  

Но это зависит от выбора пользователя в зависимости от всей задачи.