txtを一行ずつ分かち書きしてtxtに保存。
また、txtを一行ずつ"形容詞"、"名詞"、"動詞"を抽出、保存したいと考えています。
import MeCab
tagger = MeCab.Tagger("-Owakati")
f = open("lines.txt","r")
read_text = f.readline() # readline()で一行ずつ読み込み。
for text in read_text: # readline()だけだと一行しか読み込まれなかったため、for文で繰り返す。
for output in tagger.parse(text): # 分かち書きを行う。
with open("wakati_lines.txt", mode="a") as write_file: # wでは、上書きされるため、aモードで追記する。
write_file.write(output)
上記のスクリプトで分かち書きされると考えていますが、入力がそのまま出力されます。
@hayataka2049さんの回答により原因の判明と分かち書きが出来ました。
import MeCab
import codecs
import ast
tagger = MeCab.Tagger() # mecab標準辞書でオブジェクト生成
f = open('lines.txt', 'r')
reader = f.read()
reader = reader.replace("\n", "|")
f.close()
node = tagger.parseToNode(reader)
result = [reader]
while node:
word = node.surface
#品詞を取得
pos = node.feature.split(",")[0]
if pos in ["名詞"]:
result.append(node.surface)
elif pos in["動詞","形容詞"]:
result.append(node.feature.split(",")[6])
#次の単語に進める
node = node.next
print(result, file=codecs.open("haiku_wakati.txt", "w"))
期待する出力:
['今年', '梅雨', '遅い']
['寝る', '時間']
この形式にする理由は、random.chices()でランダムに要素を抽出し、翻訳生成用データセットを作るためです。
例えば、俳句の場合、
夏 + 梅雨 + 鯉 -(翻訳)-> 鯉 こく 梅雨 傘立 あふれ(分かち書き)
また、[]や''はreplce()で簡単に除去できます。
そして、今後、txt列の品詞抽出を行いたい方がいらっしゃった場合にこの質問は役に立つと考えています。
実際の出力:
['今年の梅雨は遅い。|寝る時間よ。|・・・しなさい。|私に任せなさい。', '今年', '梅雨', '遅い', '|', '寝る', '時間', '|', ・・・ '|', '私', '任せる', 'なさる']
最初に'文章', 次に'品詞','品詞'が出力されます。
read()が全てを読み込むのは分かるのですが、pop()で出来ず、最初の要素をどうやって取り除くか。品詞部分が、\n、\tでは、区切られない問題に対処する必要があると考えています。
参考サイト:
MeCabの形態素解析で使うTagger、Nodeオブジェクトのプロパティとメソッド
https://takaxtech.com/2018/11/03/article271/
Pythonでファイルの読み込み、書き込み
https://note.nkmk.me/python-file-io-open-with/
今年の梅雨は遅い。
寝る時間よ。
もう手遅れだ。
嘘を付くのは悪いことだ。
そろそろ寝る時間だぞ。
右側通行をしなさい。
私に任せなさい。
環境:Ubuntu 18.04
何卒、ご教授よろしくお願い致します。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
修正点1
read_text = f.readline()
for text in read_text:
read_text
には「f.readline()
で得られた一行分の文字列」が入ります。なので、そもそもやっていることが間違っています。f.readlines()
なら正しいですし、そもそも単にf
と書いてもいいのですが。
(あと、ファイルはopenしたらcloseしましょう)
修正点2
上の点を修正すると、上のコードの場合結果のファイル(あ、追記モードでこれまでやっていたなら一度削除してください)には、
今年 の 梅雨 は 遅い 。
寝る 時間 よ 。
もう 手遅れ だ 。
嘘 を 付く の は 悪い こと だ 。
そろそろ 寝る 時間 だ ぞ 。
右側 通行 を し なさい 。
私 に 任せ なさい 。
のようなスペースで区切られた文字列が入ります。
オプションを-Owakati
とした場合、
>>> import MeCab
>>> tagger = MeCab.Tagger("-Owakati")
>>> tagger.parse("昨日はたいへんだった") # 空白で区切られた文字列である
'昨日 は たいへん だっ た \n'
という挙動になるのですが、実は内側のfor
は文字列から1文字ずつ取り出して1文字ずつ書くという動作をしているだけなので、純粋に無駄です。
以上を勘案して、スペース区切りでいいのであればこんな感じ。
import MeCab
tagger = MeCab.Tagger("-Owakati")
f = open("lines.txt","r")
read_text = f.readlines()
f.close() # withを使うべきかどうか、またreadlinesが効率的かという議論もあるのですが、ひとまず
for text in read_text:
result = tagger.parse(text)
with open("hinshi_lines.txt", mode="a") as write_file:
write_file.writelines(result)
質問文のコードはひどく非効率的なことをしています。
修正点3
今年の梅雨は遅い。-> ['今年', '梅雨', '遅い']
結果はpythonのlist
を期待しているということでしょうか? その場合は、ファイル出力時のフォーマットをどうするのかというところから検討するべきだと思います。また、人間が簡単に読めなくても良いのであればpickle
などを使うという手もあります(そういうことがしたいようにも思えます)。
修正点4
下のコードの場合。while
ループ内でファイルにresult
を書き込むのはおかしいです。インデントを一段階上げて、外側のfor
のブロックに属するようにするのがたぶんただしいのでしょう。
修正点5
修正点3とも関連しますが、上の修正を施して実行すると、
今年梅雨遅い寝る時間手遅れ嘘付くの悪いこと寝る時間右側通行するなさる私任せるなさる
のようにすべての単語が連続して出てくるので、出力フォーマットについてはよく考えて、適切な書き出し処理を行いましょう。
修正点6
コメントの半分くらいが本当の処理内容と違っているので、混乱しないように直す。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
これで取得できると思います。for text in read_text:をやると重複するのでこれが一番無難なやり方な気がします。
f = open('lines.txt', 'r')
reader = f.readline()
result = []
node = mecab.parseToNode(reader)
while node:
#単語を取得
word = node.surface
#品詞を取得
pos = node.feature.split(",")[0]
if pos in ["名詞"]:
result.append(node.surface)
elif pos in["動詞","形容詞"]:
result.append(node.feature.split(",")[6])
#次の単語に進める
node = node.next
print(result)
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/07/19 02:31
修正点を踏まえ、質問部分を修正します。
具体的には、
・品詞抽出スクリプトの修正
・なぜlist出力したいのかとそれを踏まえた書き出し処理
を追加します。
2019/07/19 03:28 編集
・スペース区切りなどのフォーマットで出力し、読み込み時に改めてsplitする
・strで文字列に変換して、ast.literal_evalで読み込む
・jsonやxmlなど任意のフォーマットに変換して出力・再読み込みする
・pickleなどのバイナリ形式で保存する
あたりが選択肢になります。それぞれ書くべきコードは異なります。あと考え方も。
2019/07/19 07:15 編集
・f.read()が何を返すのか理解する必要があります。
・resultとnodeを宣言している位置もおかしいです。複数回ループすることを想定しているのなら、ループのたびに上書きされるので無意味です。まあ、結果的にはこれでファイル全体を形態素解析できるのですが(f.read()の結果と関係する)。
・下のwhileも、一単語取るたびにファイルを上書きしてしまう動作になっています。
2019/07/19 07:16
2019/07/20 05:05
今年の梅雨は遅い。
^
SyntaxError: invalid character in identifier
読み込みでそのまま使えません。また、最後のresultで使うと全てを一つのリストにしてしまいます。
2019/07/20 15:17
2019/07/25 19:20 編集