Два цикла Python, которые выглядят так, как будто они должны делать то же самое, но выводить разные результаты?
Вчера я пытался завершить Урок 11 Udacity, посвященный векторизации текста. Я просмотрел код, и все это, казалось, работало нормально - я беру несколько писем, открываю их, удаляю несколько слов подписи и возвращаю слова из каждого письма в список.
Вот цикл 1:
for name, from_person in [("sara", from_sara), ("chris", from_chris)]:
for path in from_person:
### only look at first 200 emails when developing
### once everything is working, remove this line to run over full dataset
# temp_counter += 1
if temp_counter < 200:
path = os.path.join('/xxx', path[:-1])
email = open(path, "r")
### use parseOutText to extract the text from the opened email
email_stemmed = parseOutText(email)
### use str.replace() to remove any instances of the words
### ["sara", "shackleton", "chris", "germani"]
email_stemmed.replace("sara","")
email_stemmed.replace("shackleton","")
email_stemmed.replace("chris","")
email_stemmed.replace("germani","")
### append the text to word_data
word_data.append(email_stemmed.replace('\n', ' ').strip())
### append a 0 to from_data if email is from Sara, and 1 if email is from Chris
if from_person == "sara":
from_data.append(0)
elif from_person == "chris":
from_data.append(1)
email.close()
Вот цикл 2:
for name, from_person in [("sara", from_sara), ("chris", from_chris)]:
for path in from_person:
### only look at first 200 emails when developing
### once everything is working, remove this line to run over full dataset
# temp_counter += 1
if temp_counter < 200:
path = os.path.join('/xxx', path[:-1])
email = open(path, "r")
### use parseOutText to extract the text from the opened email
stemmed_email = parseOutText(email)
### use str.replace() to remove any instances of the words
### ["sara", "shackleton", "chris", "germani"]
signature_words = ["sara", "shackleton", "chris", "germani"]
for each_word in signature_words:
stemmed_email = stemmed_email.replace(each_word, '') #careful here, dont use another variable, I did and broke my head to solve it
### append the text to word_data
word_data.append(stemmed_email)
### append a 0 to from_data if email is from Sara, and 1 if email is from Chris
if name == "sara":
from_data.append(0)
else: # its chris
from_data.append(1)
email.close()
Следующая часть кода работает как задумано:
print("emails processed")
from_sara.close()
from_chris.close()
pickle.dump( word_data, open("/xxx/your_word_data.pkl", "wb") )
pickle.dump( from_data, open("xxx/your_email_authors.pkl", "wb") )
print("Answer to Lesson 11 quiz 19: ")
print(word_data[152])
### in Part 4, do TfIdf vectorization here
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction import stop_words
print("SKLearn has this many Stop Words: ")
print(len(stop_words.ENGLISH_STOP_WORDS))
vectorizer = TfidfVectorizer(stop_words="english", lowercase=True)
vectorizer.fit_transform(word_data)
feature_names = vectorizer.get_feature_names()
print('Number of different words: ')
print(len(feature_names))
Но когда я вычисляю общее количество слов в цикле 1, я получаю неправильный результат. Когда я делаю это с помощью цикла 2, я получаю правильный результат.
Я слишком долго смотрю на этот код и не вижу разницы - что я сделал не так в цикле 1?
Для записи, неправильный ответ, который я продолжал получать, был 38825. Правильный ответ должен быть 38757.
Большое спасибо за вашу помощь, добрый незнакомец!
1 ответ
Эти строки ничего не делают:
email_stemmed.replace("sara","")
email_stemmed.replace("shackleton","")
email_stemmed.replace("chris","")
email_stemmed.replace("germani","")
replace
возвращает новую строку и не изменяет email_stemmed
, Вместо этого вы должны установить возвращаемое значение email_stemmed
:
email_stemmed = email_stemmed.replace("sara", "")
Так далее и тому подобное.
Второй цикл на самом деле устанавливает возвращаемое значение в цикле for:
for each_word in signature_words:
stemmed_email = stemmed_email.replace(each_word, '')
Фрагменты кода сверху не эквивалентны в том, что в конце первого фрагмента email_stemmed
полностью без изменений из-за replace
используется правильно, в то время как в конце второго stemmed_email
был фактически лишен каждого слова.