#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']
Но это зависит от выбора пользователя в зависимости от всей задачи.