In breve:
Ha qualcosa a che fare con il modo python3
hash chiavi quando la funzione similar()
utilizza il dizionario contatore. Vedi http://pastebin.com/ysAF6p6h
Vedi How and why is the dictionary hashes different in python2 and python3?
a Long:
Cominciamo con:
from nltk.book import *
L'importazione qui viene da https://github.com/nltk/nltk/blob/develop/nltk/book.py che importano l'oggetto nltk.text.Text
e leggere diversi corpora nell'oggetto Text
objec t.
E.g. Questo è come la variabile text1
è stato letto da nltk.book
:
>>> import nltk.corpus
>>> from nltk.text import Text
>>> moby = Text(nltk.corpus.gutenberg.words('melville-moby_dick.txt'))
Ora, se andiamo giù per il codice per la funzione similar()
a https://github.com/nltk/nltk/blob/develop/nltk/text.py#L377, vediamo questo l'inizializzazione se è la prima istanza di accesso self._word_context_index
:
def similar(self, word, num=20):
"""
Distributional similarity: find other words which appear in the
same contexts as the specified word; list most similar words first.
:param word: The word used to seed the similarity search
:type word: str
:param num: The number of words to generate (default=20)
:type num: int
:seealso: ContextIndex.similar_words()
"""
if '_word_context_index' not in self.__dict__:
#print('Building word-context index...')
self._word_context_index = ContextIndex(self.tokens,
filter=lambda x:x.isalpha(),
key=lambda s:s.lower())
word = word.lower()
wci = self._word_context_index._word_to_contexts
if word in wci.conditions():
contexts = set(wci[word])
fd = Counter(w for w in wci.conditions() for c in wci[w]
if c in contexts and not w == word)
words = [w for w, _ in fd.most_common(num)]
print(tokenwrap(words))
else:
print("No matches")
In modo che ci punti all'oggetto nltk.text.ContextIndex
, che è supporre di raccogliere tutte le parole con la finestra di contesto simile e memorizzarle. La docstring dice:
Un indice bidirezionale tra le parole e i loro "contesti" in un testo. Il contesto di una parola viene in genere definito come le parole che si verificano in una finestra fissa attorno alla parola; ma altre definizioni possono anche essere usate fornendo una funzione di contesto personalizzata.
Per impostazione predefinita, se si sta chiamando la funzione similar()
, sarà inizializzare la _word_context_index
con le impostazioni di default del contesto vale a direla finestra di token a sinistra ea destra, vedere https://github.com/nltk/nltk/blob/develop/nltk/text.py#L40
@staticmethod
def _default_context(tokens, i):
"""One left token and one right token, normalized to lowercase"""
left = (tokens[i-1].lower() if i != 0 else '*START*')
right = (tokens[i+1].lower() if i != len(tokens) - 1 else '*END*')
return (left, right)
Dalla funzione similar()
, vediamo che esegue un'iterazione parola nel contesto memorizzata nel word_context_index, cioè wci = self._word_context_index._word_to_contexts
.
In sostanza, _word_to_contexts
è un dizionario, dove le chiavi sono le parole del corpus ed i valori sono le parole a destra ea sinistra da https://github.com/nltk/nltk/blob/develop/nltk/text.py#L55:
self._word_to_contexts = CFD((self._key(w), self._context_func(tokens, i))
for i, w in enumerate(tokens))
E qui vediamo che si tratta di un CFD, che è un nltk.probability.ConditionalFreqDist
oggetto, che non include il livellamento della probabilità di token, vedere il codice completo a https://github.com/nltk/nltk/blob/develop/nltk/probability.py#L1646.
L'unico eventualmente di ottenere il risultato diverso è quando la funzione similar()
passanti attraverso le parole most_common a https://github.com/nltk/nltk/blob/develop/nltk/text.py#L402
Dato che due chiavi in un oggetto Counter
hanno gli stessi conteggi, la parola con un inferiore hash ordinata stamperà prima e l'hash della chiave dipende dal bit-dimensioni della CPU, vedere http://www.laurentluce.com/posts/python-dictionary-implementation/
L'intero processo di trovare le si parole simili è deterministico, dal:
- corpus/ingresso è fisso
Text(gutenberg.words('melville-moby_dick.txt'))
- contesto di default per ogni parola è anche corretto, cioè
self._word_context_index
- calcolo della distribuzione di frequenza condizionale per
_word_context_index._word_to_contexts
è discreto
Salvo quando la funzione genera l'elenco most_common
, che quando c'è un pareggio nei valori Counter
, verrà emesso l'elenco delle chiavi in base ai loro hash.
In python2
, non c'è ragione per ottenere un output diverso da diverse istanze dello stessa macchina con il seguente codice:
$ python
>>> from nltk.book import *
>>> text1.similar('monstrous')
>>> exit()
$ python
>>> from nltk.book import *
>>> text1.similar('monstrous')
>>> exit()
$ python
>>> from nltk.book import *
>>> text1.similar('monstrous')
>>> exit()
Ma in Python3
, dà un output diverso ogni volta che si esegue text1.similar('monstrous')
, vedi http://pastebin.com/ysAF6p6h
Ecco un semplice esperimento per dimostrare che le differenze di hashing eccentrici tra python2
e python3
:
[email protected]:~$ python -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('foobar', 1), ('foo', 1), ('bar', 1), ('barfoo', 1)]
[email protected]:~$ python -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('foobar', 1), ('foo', 1), ('bar', 1), ('barfoo', 1)]
[email protected]:~$ python -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('foobar', 1), ('foo', 1), ('bar', 1), ('barfoo', 1)]
[email protected]:~$ python3 -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('barfoo', 1), ('foobar', 1), ('bar', 1), ('foo', 1)]
[email protected]:~$ python3 -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('foo', 1), ('barfoo', 1), ('bar', 1), ('foobar', 1)]
[email protected]:~$ python3 -c "from collections import Counter; x = Counter({'foo': 1, 'bar': 1, 'foobar': 1, 'barfoo': 1}); print(x.most_common())"
[('bar', 1), ('barfoo', 1), ('foobar', 1), ('foo', 1)]
Potete fornire il testo di input e il frammento di codice che avete utilizzato? Quindi, possiamo provare a esaminare il codice e vedere come spiegare la differenza. – alvas
Ho appena seguito le istruzioni che fanno parte di questa pagina del libro NLTK. http://www.nltk.org/book/ch01.html –
Qual è il bit della macchina che stai utilizzando per il tuo snippet di codice nella domanda? http://stackoverflow.com/questions/9964396/python-check-if-a-system-is-32-or-64-bit-to-determine-whether-to-run-the-funct, qual è il tuo output per la struttura di importazione 'python -c"; print struct.calcsize ('P') * 8 "' – alvas