次のようなtxtファイルがあります。
Word, 23
Words, 2
test, 1
tests, 4
そして、私はそれらをこのように見せたい:
Word, 23
Word, 2
test, 1
test, 4
Pythonでtxtファイルを取得し、複数形を単数形に変換できるようにしたい。コードは次のとおりです。
import nltk
f = raw_input("Please enter a filename: ")
def openfile(f):
with open(f,'r') as a:
a = a.read()
a = a.lower()
return a
def stem(a):
p = nltk.PorterStemmer()
[p.stem(Word) for Word in a]
return a
def returnfile(f, a):
with open(f,'w') as d:
d = d.write(a)
#d.close()
print openfile(f)
print stem(openfile(f))
print returnfile(f, stem(openfile(f)))
stem
定義の代わりに、次の2つの定義も試しました。
def singular(a):
for line in a:
line = line[0]
line = str(line)
stemmer = nltk.PorterStemmer()
line = stemmer.stem(line)
return line
def stem(a):
for Word in a:
for suffix in ['s']:
if Word.endswith(suffix):
return Word[:-len(suffix)]
return Word
その後、重複する単語(test
とtest
など)を取得し、それらの横にある数字を合計してマージしたいと思います。例えば:
Word, 25
test, 5
どうすればいいのかわかりません。解決策は素晴らしいですが、必須ではありません。
あなたはPythonにかなり精通しているようですが、それでもいくつかの手順を説明しようと思います。単語の非複数化の最初の質問から始めましょう。 a.read()を使用して複数行のファイル(Word、この場合は数値csv)を読み込むと、ファイルの本文全体が1つの大きな文字列に読み込まれます。
def openfile(f):
with open(f,'r') as a:
a = a.read() # a will equal 'soc, 32\nsoc, 1\n...' in your example
a = a.lower()
return a
これは問題ありませんが、結果をstem()に渡したい場合は、単語のリストではなく、1つの大きな文字列になります。これは、for Word in a
を使用して入力を反復処理すると、入力文字列の個々の文字を反復処理し、それらの個々の文字にステマーを適用することを意味します。
def stem(a):
p = nltk.PorterStemmer()
a = [p.stem(Word) for Word in a] # ['s', 'o', 'c', ',', ' ', '3', '2', '\n', ...]
return a
これは間違いなくあなたの目的には機能しません、そして私たちができるいくつかの異なることがあります。
便宜上、#1でロールしましょう。これには、openfile(f)を次のように変更する必要があります。
def openfile(f):
with open(f,'r') as a:
a = a.readlines() # a will equal 'soc, 32\nsoc, 1\n...' in your example
b = [x.lower() for x in a]
return b
これにより、行のリストとしてbが得られます。つまり、['soc、32'、 'soc、1'、...]です。したがって、次の問題は、文字列のリストをstem()に渡すときに、そのリストをどうするかということです。 1つの方法は次のとおりです。
def stem(a):
p = nltk.PorterStemmer()
b = []
for line in a:
split_line = line.split(',') #break it up so we can get access to the Word
new_line = str(p.stem(split_line[0])) + ',' + split_line[1] #put it back together
b.append(new_line) #add it to the new list of lines
return b
これは間違いなくかなり大まかな解決策ですが、入力のすべての行を適切に反復し、それらを非複数化する必要があります。文字列を分割して再組み立てするのは、スケールアップするときに特に速くないため、大雑把です。ただし、これに満足している場合は、新しい行のリストを繰り返し処理して、ファイルに書き込むだけです。私の経験では、通常は新しいファイルに書き込む方が安全ですが、これは問題なく機能するはずです。
def returnfile(f, a):
with open(f,'w') as d:
for line in a:
d.write(line)
print openfile(f)
print stem(openfile(f))
print returnfile(f, stem(openfile(f)))
次の場合input.txt
soc, 32
socs, 1
dogs, 8
次のstdoutを取得します。
Please enter a filename: input.txt
['soc, 32\n', 'socs, 1\n', 'dogs, 8\n']
['soc, 32\n', 'soc, 1\n', 'dog, 8\n']
None
そしてinput.txtは次のようになります:
soc, 32
soc, 1
dog, 8
同じ単語で数字をマージすることに関する2番目の質問は、上記のソリューションを変更します。コメントの提案に従って、これを解決するために辞書を使用することを検討する必要があります。これをすべて1つの大きなリストとして行うのではなく、これを行うためのより良い(そしておそらくよりPythonicな)方法は、入力の各行を反復処理し、処理しながらそれらをステミングすることです。あなたがまだそれを理解するために働いているなら、私はこれについて少しコードを書きます。
単数化する複雑な単語がある場合は、ステミングを使用することはお勧めしませんが、適切なpythonパッケージリンクpattern
:
from pattern.text.en import singularize
plurals = ['caresses', 'flies', 'dies', 'mules', 'geese', 'mice', 'bars', 'foos',
'families', 'dogs', 'child', 'wolves']
singles = [singularize(plural) for plural in plurals]
print singles
戻り値:
>>> ['caress', 'fly', 'dy', 'mule', 'goose', 'mouse', 'bar', 'foo', 'foo', 'family', 'family', 'dog', 'dog', 'child', 'wolf']
完璧ではありませんが、私が見つけた最高のものです。ドキュメントに基づく96%: http://www.clips.ua.ac.be/pages/pattern-en#pluralization
Nodebox English Linguisticsライブラリには、複数形を単一形に、またはその逆に変換するためのスクリプトが含まれています。チェックアウトチュートリアル: https://www.nodebox.net/code/index.php/Linguistics#pluralization
複数形を単一形に変換するには、singular
モジュールをインポートし、singular()
関数を使用します。末尾が異なる単語や不規則な形式などの単語の適切な変換を処理します。
from en import singular
print(singular('analyses'))
print(singular('planetoids'))
print(singular('children'))
>>> analysis
>>> planetoid
>>> child