A better question would have been what are those ("()", "'",",") in the ngrams output?

>>> from nltk import ngrams
>>> from nltk import word_tokenize

# Split a sentence into a list of "words"
>>> word_tokenize("This is a foo bar sentence")
['This', 'is', 'a', 'foo', 'bar', 'sentence']
>>> type(word_tokenize("This is a foo bar sentence"))
<class 'list'>

# Extract bigrams.
>>> list(ngrams(word_tokenize("This is a foo bar sentence"), 2))
[('This', 'is'), ('is', 'a'), ('a', 'foo'), ('foo', 'bar'), ('bar', 'sentence')]

# Okay, so the output is a list, no surprise.
>>> type(list(ngrams(word_tokenize("This is a foo bar sentence"), 2)))
<class 'list'>

But what type is ('This', 'is')?

>>> list(ngrams(word_tokenize("This is a foo bar sentence"), 2))[0]
('This', 'is')
>>> first_thing_in_output = list(ngrams(word_tokenize("This is a foo bar sentence"), 2))[0]
>>> type(first_thing_in_output)
<class 'tuple'>

Ah, it's a tuple, see https://realpython.com/python-lists-tuples/

What happens when you print a tuple?

>>> print(first_thing_in_output)
('This', 'is')

What happens if you convert them into a str()?

>>> print(str(first_thing_in_output))
('This', 'is')

But I want the output This is instead of ('This', 'is'), so I will use the str.join() function, see https://www.geeksforgeeks.org/join-function-python/:

>>> print(' '.join((first_thing_in_output)))
This is

Now this is a good point to really go through the tutorial of basic Python types to understand what is happening. Additionally, it'll be good to understand how "container" types work too, e.g. https://github.com/usaarhat/pywarmups/blob/master/session2.md


Going through the original post, there are quite some issues with the code.

I guess the goal of the code is to:

  • Tokenize the text and remove stopwords
  • Extract ngrams (without stopwords)
  • Print out their string forms and their counts

The tricky part is the stopwords.words('english') does not contain punctuation, so you'll end up with strange ngrams that contains punctuations:

from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english'))

tokens = [token for token in nltk.word_tokenize(text) if token not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('The', 'pure'),
 ('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', ','),
 (',', 'newborn'),
 ('newborn', '.'),
 ('.', 'I'),
 ('I', 'looked'),
 ('looked', 'far'),
 ('far', ','),
 (',', ','), ...]

Perhaps you would like to extend the stoplist with punctuations, e.g.

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('The', 'pure'),
 ('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', 'newborn'),
 ('newborn', 'I'),
 ('I', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'), ...]

Then you realized that tokens like I should be a stopword but still exists in your list of ngrams. It's because the list from stopwords.words('english') are lowercased, e.g.

>>> stopwords.words('english')

[out]:

['i',
 'me',
 'my',
 'myself',
 'we',
 'our',
 'ours',
 'ourselves',
 'you',
 "you're", ...]

So when you're checking whether a token is in the stoplist, you should also lowercase the token. (Avoid lowercasing the sentence before word_tokenize because word_tokenize may take cues from capitalization). Thus:

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token.lower() not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', 'newborn'),
 ('newborn', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'), ...]

Now the ngrams looks like it's achieving the objectives:

  • Tokenize the text and remove stopwords
  • Extract ngrams (without stopwords)

Then on the last part where you want to print out the ngrams to a file in sorted order, you could actually use the Freqdist.most_common() which will list in descending order, e.g.

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords
from nltk import FreqDist

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token.lower() not in stoplist]

FreqDist(ngrams(tokens, 2)).most_common()

[out]:

[(('looked', 'far'), 4),
 (('far', 'looked'), 3),
 (('visual', 'held'), 2),
 (('held', 'memory'), 2),
 (('memory', 'Little'), 2),
 (('Little', 'little'), 2),
 (('little', 'returned'), 2),
 (('returned', 'waking'), 2),
 (('waking', 'nurse'), 2),
 (('pure', 'amnesia'), 1),
 (('amnesia', 'face'), 1),
 (('face', 'newborn'), 1),
 (('newborn', 'looked'), 1),
 (('far', 'visual'), 1),
 (('nurse', 'visual'), 1)]

(See also: Difference between Python's collections.Counter and nltk.probability.FreqDist)

Final finally, printing it out to file, you should really use a context manager, http://eigenhombre.com/introduction-to-context-managers-in-python.html

with open('bigrams-list.tsv', 'w') as fout:
    for bg, count in FreqDist(ngrams(tokens, 2)).most_common():
        print('\t'.join([' '.join(bg), str(count)]), end='\n', file=fout)

[bigrams-list.tsv]:

looked far  4
far looked  3
visual held 2
held memory 2
memory Little   2
Little little   2
little returned 2
returned waking 2
waking nurse    2
pure amnesia    1
amnesia face    1
face newborn    1
newborn looked  1
far visual  1
nurse visual    1

Food for thought

Now you see this strange bigram Little little, does it make sense?

It's a by-product of removing by from

Little by little

So now, depending on what's the ultimate task for the ngrams you've extracted, you might not really want to remove stopwords from the list.

Answer from alvas on Stack Overflow
Top answer
1 of 2
9

A better question would have been what are those ("()", "'",",") in the ngrams output?

>>> from nltk import ngrams
>>> from nltk import word_tokenize

# Split a sentence into a list of "words"
>>> word_tokenize("This is a foo bar sentence")
['This', 'is', 'a', 'foo', 'bar', 'sentence']
>>> type(word_tokenize("This is a foo bar sentence"))
<class 'list'>

# Extract bigrams.
>>> list(ngrams(word_tokenize("This is a foo bar sentence"), 2))
[('This', 'is'), ('is', 'a'), ('a', 'foo'), ('foo', 'bar'), ('bar', 'sentence')]

# Okay, so the output is a list, no surprise.
>>> type(list(ngrams(word_tokenize("This is a foo bar sentence"), 2)))
<class 'list'>

But what type is ('This', 'is')?

>>> list(ngrams(word_tokenize("This is a foo bar sentence"), 2))[0]
('This', 'is')
>>> first_thing_in_output = list(ngrams(word_tokenize("This is a foo bar sentence"), 2))[0]
>>> type(first_thing_in_output)
<class 'tuple'>

Ah, it's a tuple, see https://realpython.com/python-lists-tuples/

What happens when you print a tuple?

>>> print(first_thing_in_output)
('This', 'is')

What happens if you convert them into a str()?

>>> print(str(first_thing_in_output))
('This', 'is')

But I want the output This is instead of ('This', 'is'), so I will use the str.join() function, see https://www.geeksforgeeks.org/join-function-python/:

>>> print(' '.join((first_thing_in_output)))
This is

Now this is a good point to really go through the tutorial of basic Python types to understand what is happening. Additionally, it'll be good to understand how "container" types work too, e.g. https://github.com/usaarhat/pywarmups/blob/master/session2.md


Going through the original post, there are quite some issues with the code.

I guess the goal of the code is to:

  • Tokenize the text and remove stopwords
  • Extract ngrams (without stopwords)
  • Print out their string forms and their counts

The tricky part is the stopwords.words('english') does not contain punctuation, so you'll end up with strange ngrams that contains punctuations:

from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english'))

tokens = [token for token in nltk.word_tokenize(text) if token not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('The', 'pure'),
 ('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', ','),
 (',', 'newborn'),
 ('newborn', '.'),
 ('.', 'I'),
 ('I', 'looked'),
 ('looked', 'far'),
 ('far', ','),
 (',', ','), ...]

Perhaps you would like to extend the stoplist with punctuations, e.g.

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('The', 'pure'),
 ('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', 'newborn'),
 ('newborn', 'I'),
 ('I', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'), ...]

Then you realized that tokens like I should be a stopword but still exists in your list of ngrams. It's because the list from stopwords.words('english') are lowercased, e.g.

>>> stopwords.words('english')

[out]:

['i',
 'me',
 'my',
 'myself',
 'we',
 'our',
 'ours',
 'ourselves',
 'you',
 "you're", ...]

So when you're checking whether a token is in the stoplist, you should also lowercase the token. (Avoid lowercasing the sentence before word_tokenize because word_tokenize may take cues from capitalization). Thus:

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token.lower() not in stoplist]

list(ngrams(tokens, 2))

[out]:

[('pure', 'amnesia'),
 ('amnesia', 'face'),
 ('face', 'newborn'),
 ('newborn', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'),
 ('looked', 'far'),
 ('far', 'looked'), ...]

Now the ngrams looks like it's achieving the objectives:

  • Tokenize the text and remove stopwords
  • Extract ngrams (without stopwords)

Then on the last part where you want to print out the ngrams to a file in sorted order, you could actually use the Freqdist.most_common() which will list in descending order, e.g.

from string import punctuation
from nltk import word_tokenize
from nltk.util import ngrams
from nltk.corpus import stopwords
from nltk import FreqDist

text = '''The pure amnesia of her face,
newborn. I looked so far into her that, for a while, looked so far into her that, for a while  looked so far into her that, for a while looked so far into her that, for a while the visual 
held no memory. Little by little, I returned to myself, waking to nurse the visual held no  memory. Little by little, I returned to myself, waking to nurse
'''

stoplist = set(stopwords.words('english') + list(punctuation))

tokens = [token for token in nltk.word_tokenize(text) if token.lower() not in stoplist]

FreqDist(ngrams(tokens, 2)).most_common()

[out]:

[(('looked', 'far'), 4),
 (('far', 'looked'), 3),
 (('visual', 'held'), 2),
 (('held', 'memory'), 2),
 (('memory', 'Little'), 2),
 (('Little', 'little'), 2),
 (('little', 'returned'), 2),
 (('returned', 'waking'), 2),
 (('waking', 'nurse'), 2),
 (('pure', 'amnesia'), 1),
 (('amnesia', 'face'), 1),
 (('face', 'newborn'), 1),
 (('newborn', 'looked'), 1),
 (('far', 'visual'), 1),
 (('nurse', 'visual'), 1)]

(See also: Difference between Python's collections.Counter and nltk.probability.FreqDist)

Final finally, printing it out to file, you should really use a context manager, http://eigenhombre.com/introduction-to-context-managers-in-python.html

with open('bigrams-list.tsv', 'w') as fout:
    for bg, count in FreqDist(ngrams(tokens, 2)).most_common():
        print('\t'.join([' '.join(bg), str(count)]), end='\n', file=fout)

[bigrams-list.tsv]:

looked far  4
far looked  3
visual held 2
held memory 2
memory Little   2
Little little   2
little returned 2
returned waking 2
waking nurse    2
pure amnesia    1
amnesia face    1
face newborn    1
newborn looked  1
far visual  1
nurse visual    1

Food for thought

Now you see this strange bigram Little little, does it make sense?

It's a by-product of removing by from

Little by little

So now, depending on what's the ultimate task for the ngrams you've extracted, you might not really want to remove stopwords from the list.

2 of 2
0

So just to "fix" your output: Use this to print your data:

for kk,vv in tmp:
    print(" ".join(list(kk)),",%d" % vv)

BUT if you are going to parse this into an csv you should collect your output in a different format.

Currently you are creating a list of tupels containing a tupel and a number. try to collect your data as a list of lists containing each value. That way you can just write it directly into an csv file.

Take a look here: Create a .csv file with values from a Python list

🌐
Medium
medium.com › @maheshpardeshi002 › removing-special-characters-or-tags-from-text-in-data-pre-processing-using-python-5fa62f886956
Removing special characters or tags from Text in data pre-processing using Python. | by Mahesh Pardeshi | Medium
July 2, 2019 - Removing Stopwards from Text. from nltk.corpus import stopwords stop_words = set(stopwords.words('english')) def removeStopWords(text): sents=[] [stop_words.add(commonWd) for commonWd in commonStopwords] for i in range(len(sent)): word_tokens = word_tokenize(sent[i]) filtered_sentence = [w for w in word_tokens if not w in stop_words] sents.append(' '.join(map(str, filtered_sentence))) return sents
🌐
NLTK
nltk.org › book_1ed › ch03.html
Nltk
We also need a list of words to ... it to remove any proper names. Let's find words ending with ed using the regular expression «ed$». We will use the re.search(p, s) function to check whether the pattern p can be found somewhere inside the string s. We need to specify the characters of interest, and use the dollar sign which has a special behavior in ...
🌐
StudyRaid
app.studyraid.com › en › read › 14389 › 490363 › removing-punctuation-and-special-characters
Removing punctuation and special characters - Python NLTK
By iterating through the text and filtering out these characters, you achieve cleaner output without relying on regex patterns. ... from nltk.corpus import stopwords import string punctuation_set = set(string.punctuation) text = "Hello!
Find elsewhere
🌐
CodeSignal
codesignal.com › learn › courses › foundations-of-nlp-data-processing-2 › lessons › text-cleaning-and-normalization-in-nlp
Text Cleaning and Normalization in NLP
Unicode normalization helps in handling characters from different languages and scripts consistently. Lowercasing ensures that words are treated the same regardless of their case. Finally, we remove stopwords, correct any misspellings, and apply stemming or lemmatization to clean the text further: ... import nltk from nltk.corpus import stopwords from autocorrect import Speller from nltk.stem import PorterStemmer from nltk.stem import WordNetLemmatizer # Download stopwords and WordNet data nltk.download('stopwords') nltk.download('wordnet') # Initialize spell checker, stopwords, stemmer, and l
Top answer
1 of 2
13

Solution 1: Tokenize and strip punctuation off the tokens

>>> from nltk import word_tokenize
>>> import string
>>> punctuations = list(string.punctuation)
>>> punctuations
['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
>>> punctuations.append("''")
>>> sent = '''He said,"that's it."'''
>>> word_tokenize(sent)
['He', 'said', ',', "''", 'that', "'s", 'it', '.', "''"]
>>> [i for i in word_tokenize(sent) if i not in punctuations]
['He', 'said', 'that', "'s", 'it']
>>> [i.strip("".join(punctuations)) for i in word_tokenize(sent) if i not in punctuations]
['He', 'said', 'that', 's', 'it']

Solution 2: remove punctuation then tokenize

>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> sent = '''He said,"that's it."'''
>>> " ".join("".join([" " if ch in string.punctuation else ch for ch in sent]).split())
'He said that s it'
>>> " ".join("".join([" " if ch in string.punctuation else ch for ch in sent]).split()).split()
['He', 'said', 'that', 's', 'it']
2 of 2
6

If you want to tokenize your string all in one shot, I think your only choice will be to use nltk.tokenize.RegexpTokenizer. The following approach will allow you to use punctuation as a marker to remove characters of the alphabet (as noted in your third requirement) before removing the punctuation altogether. In other words, this approach will remove *u* before stripping all punctuation.

One way to go about this, then, is to tokenize on gaps like so:

>>> from nltk.tokenize import RegexpTokenizer
>>> s = '''He said,"that's it." *u* Hello, World.'''
>>> toker = RegexpTokenizer(r'((?<=[^\w\s])\w(?=[^\w\s])|(\W))+', gaps=True)
>>> toker.tokenize(s)
['He', 'said', 'that', 's', 'it', 'Hello', 'World']  # omits *u* per your third requirement

This should meet all three of the criteria you specified above. Note, however, that this tokenizer will not return tokens such as "A". Furthermore, I only tokenize on single letters that begin and end with punctuation. Otherwise, "Go." would not return a token. You may need to nuance the regex in other ways, depending on what your data looks like and what your expectations are.

🌐
Medium
medium.com › @blueberry92450 › three-ways-to-remove-special-characters-from-string-in-python-da1035cc93b8
Three ways to Remove Special Characters from String in Python Including Time Comparison | Medium
August 8, 2022 - Removing special characters is needed in various types of programming such as NLP, making safe file names, preprocessing text data and so on.
🌐
Netlify
michael-fuchs-python.netlify.app › 2021 › 05 › 22 › nlp-text-pre-processing-i-text-cleaning
NLP - Text Pre-Processing I (Text Cleaning) - Michael Fuchs Python
def remove_accented_chars_func(text): ''' Removes all accented characters from a string, if present Args: text (str): String to which the function is to be applied, string Returns: Clean string without accented characters ''' return unicodedata.normalize('NFKD', text).encode('ascii', ...
🌐
YouTube
youtube.com › watch
- YouTube
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
🌐
NLTK
nltk.org › _modules › nltk › tokenize › casual.html
NLTK :: nltk.tokenize.casual
:param text: str :rtype: list(str) :return: a tokenized list of strings; joining this list returns\ the original string if `preserve_case=False`. """ # Fix HTML character entities: text = _replace_html_entities(text) # Remove username handles if self.strip_handles: text = remove_handles(text) # Normalize word lengthening if self.reduce_len: text = reduce_lengthening(text) # Shorten problematic sequences of characters safe_text = HANG_RE.sub(r"\1\1\1", text) # Recognise phone numbers during tokenization if self.match_phone_numbers: words = self.PHONE_WORD_RE.findall(safe_text) else: words = sel
🌐
datagy
datagy.io › home › python posts › python strings › python: remove special characters from a string
Python: Remove Special Characters from a String • datagy
December 17, 2022 - Learn how to use Python to remove special characters from a string, including how to do this using regular expressions and isalnum.
Top answer
1 of 1
2

I never worked with nltk before. There could be a better solution too. In my code snippet I am simply doing the following:

  1. Reading a file that needs to be checked for non-english/english words named as frequencyList.txt to a variable named as lines.

  2. Then I am opening a new file named as eng_words_only.txt. This file will contain the english words only. Initially this file will be empty, later after executing the script this file will contain all the English language words present in frequencyList.txt

  3. Now for every word in frequencyList.txt I check if it is also present in wordnet. If the word is present then I write this word to the eng_words_only.txt file, else I do nothing. Please see I am using wordnet just for demo purpose. It doesn't contains all the English language words!

Code:

from nltk.corpus import wordnet

fList = open("frequencyList.txt","r")#Read the file
lines = fList.readlines()

eWords = open("eng_words_only.txt", "a")#Open file for writing

for w in lines:
    if not wordnet.synsets(w):#Comparing if word is non-English
        print 'not '+w
    else:#If word is an English word
        print 'yes '+w
        eWords.write(w)#Write to file 
        
eWords.close()#Close the file

Testing: I first created a file named as frequencyList.txt with the following contents:

cat 
meoooow 
mouse

then upon executing the code snippet you'll see the following output in the console:

not cat

not meoooow

yes mouse

Then a file will be created eng_words_only.txt which contains only the words that were supposed to be of the English language. The eng_words_only.txt will contain only mouse word. You may notice that cat is an English word but it is still not in the eng_words_only.txt file. This is the reason why you should use a good source instead of wordnet. Please note: The python script file and the frequencyList.txt should be in the same directory. Also, instead of frequencyList.txt you can use any of your file that you want to check/investigate. In that case don't forget to change the files names in the code snippet too.

Second Solution: Although you didn't ask for it but still there is an other way too to do this English word test.

Here is the code: Here the wordlist-eng.txt is the file which contains the English words. You have to keep

wordlist-eng.txt, frequencyList.txt and the python script in the same directory.

with open("wordlist-eng.txt") as word_file:
    english_words = set(word.strip().lower() for word in word_file)

fList = open("frequencyList.txt","r")
lines = fList.readlines()
fList.close()

eWords = open("eng_words_only.txt", "a")

for w in lines:
    if w.strip().lower() in english_words:
        eWords.write(w)
    else: pass
eWords.close()

After executing the script the eng_words_only.txt will contain all the English words that were present in frequencyList.txt file.

I hope this was helpful.