13

次のような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)))

定義の代わりに、次の 2 つの定義も試しましたstem

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その後、重複した単語 (たとえばand test) を取得し、それらの横にある数字を合計してそれらをマージしたいと思います。例えば:

word, 25
test, 5

どうすればいいのかわかりません。解決策があればいいのですが、必須ではありません。

4

3 に答える 3

11

あなたは Python にかなり慣れているようですが、いくつかの手順について説明します。単語の複数形化の最初の質問から始めましょう。a.read() を使用して複数行のファイル (この場合は 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. 入力ファイルを行の 1 つのリストとして読み取るように変更できます。
  2. 大きな文字列を使用して、自分でリストに分解できます。
  3. 行のリスト内の各行を一度に 1 つずつ調べて、ステム処理することができます。

便宜上、#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

次の標準出力を取得します。

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 つの大きなリストとして行う代わりに、入力の各行を反復処理し、処理しながらそれらをステミングすることをお勧めします。あなたがまだそれを理解しようとしているなら、私はこれについてのコードを少し書きます。

于 2015-07-13T19:51:53.433 に答える