質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

6732閲覧

txtを一行ずつ分かち書き, 品詞抽出したいが、入力のまま出力される

tono_1812

総合スコア9

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2019/07/18 14:08

編集2019/07/19 19:47

txtを一行ずつ分かち書きしてtxtに保存。
また、txtを一行ずつ"形容詞"、"名詞"、"動詞"を抽出、保存したいと考えています。

python

1import MeCab 2 3tagger = MeCab.Tagger("-Owakati") 4 5f = open("lines.txt","r") 6read_text = f.readline() # readline()で一行ずつ読み込み。 7 8for text in read_text: # readline()だけだと一行しか読み込まれなかったため、for文で繰り返す。 9 for output in tagger.parse(text): # 分かち書きを行う。 10 with open("wakati_lines.txt", mode="a") as write_file: # wでは、上書きされるため、aモードで追記する。 11 write_file.write(output)

上記のスクリプトで分かち書きされると考えていますが、入力がそのまま出力されます。
@hayataka2049さんの回答により原因の判明と分かち書きが出来ました。

python

1import MeCab 2import codecs 3import ast 4 5tagger = MeCab.Tagger() # mecab標準辞書でオブジェクト生成 6 7f = open('lines.txt', 'r') 8reader = f.read() 9reader = reader.replace("\n", "|") 10f.close() 11 12node = tagger.parseToNode(reader) 13result = [reader] 14 15while node: 16 word = node.surface 17 #品詞を取得 18 pos = node.feature.split(",")[0] 19 if pos in ["名詞"]: 20 result.append(node.surface) 21 elif pos in["動詞","形容詞"]: 22 result.append(node.feature.split(",")[6]) 23 #次の単語に進める 24 node = node.next 25 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/

txt

1今年の梅雨は遅い。 2寝る時間よ。 3もう手遅れだ。 4嘘を付くのは悪いことだ。 5そろそろ寝る時間だぞ。 6右側通行をしなさい。 7私に任せなさい。 8```環境:Ubuntu 18.04 9 10 11何卒、ご教授よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

修正点1

python

1read_text = f.readline() 2 3for text in read_text:

read_textには「f.readline()で得られた一行分の文字列」が入ります。なので、そもそもやっていることが間違っています。f.readlines()なら正しいですし、そもそも単にfと書いてもいいのですが。
(あと、ファイルはopenしたらcloseしましょう)

修正点2

上の点を修正すると、上のコードの場合結果のファイル(あ、追記モードでこれまでやっていたなら一度削除してください)には、

plain

1今年 の 梅雨 は 遅い 。 2寝る 時間 よ 。 3もう 手遅れ だ 。 4嘘 を 付く の は 悪い こと だ 。 5そろそろ 寝る 時間 だ ぞ 。 6右側 通行 を し なさい 。 7私 に 任せ なさい 。

のようなスペースで区切られた文字列が入ります。

オプションを-Owakatiとした場合、

python

1>>> import MeCab 2>>> tagger = MeCab.Tagger("-Owakati") 3>>> tagger.parse("昨日はたいへんだった") # 空白で区切られた文字列である 4'昨日 は たいへん だっ た \n'

という挙動になるのですが、実は内側のforは文字列から1文字ずつ取り出して1文字ずつ書くという動作をしているだけなので、純粋に無駄です。

以上を勘案して、スペース区切りでいいのであればこんな感じ。

python

1import MeCab 2 3tagger = MeCab.Tagger("-Owakati") 4 5f = open("lines.txt","r") 6read_text = f.readlines() 7f.close() # withを使うべきかどうか、またreadlinesが効率的かという議論もあるのですが、ひとまず 8 9for text in read_text: 10 result = tagger.parse(text) 11 with open("hinshi_lines.txt", mode="a") as write_file: 12 write_file.writelines(result) 13

質問文のコードはひどく非効率的なことをしています。

修正点3

今年の梅雨は遅い。-> ['今年', '梅雨', '遅い']

結果はpythonのlistを期待しているということでしょうか? その場合は、ファイル出力時のフォーマットをどうするのかというところから検討するべきだと思います。また、人間が簡単に読めなくても良いのであればpickleなどを使うという手もあります(そういうことがしたいようにも思えます)。

修正点4

下のコードの場合。whileループ内でファイルにresultを書き込むのはおかしいです。インデントを一段階上げて、外側のforのブロックに属するようにするのがたぶんただしいのでしょう。

修正点5

修正点3とも関連しますが、上の修正を施して実行すると、

今年梅雨遅い寝る時間手遅れ嘘付くの悪いこと寝る時間右側通行するなさる私任せるなさるのようにすべての単語が連続して出てくるので、出力フォーマットについてはよく考えて、適切な書き出し処理を行いましょう。

修正点6

コメントの半分くらいが本当の処理内容と違っているので、混乱しないように直す。

投稿2019/07/18 16:59

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tono_1812

2019/07/18 17:31

了解しました。 修正点を踏まえ、質問部分を修正します。 具体的には、 ・品詞抽出スクリプトの修正 ・なぜlist出力したいのかとそれを踏まえた書き出し処理 を追加します。
hayataka2049

2019/07/18 18:28 編集

writelinesは「listを引数に取る」というだけで、listの構造を復元できるような形で保存する訳ではないので、使うことは無意味です。 ・スペース区切りなどのフォーマットで出力し、読み込み時に改めてsplitする ・strで文字列に変換して、ast.literal_evalで読み込む ・jsonやxmlなど任意のフォーマットに変換して出力・再読み込みする ・pickleなどのバイナリ形式で保存する あたりが選択肢になります。それぞれ書くべきコードは異なります。あと考え方も。
hayataka2049

2019/07/18 22:18 編集

質問文の追記を見ましたが、率直に言えばかなりデタラメな、少なくとも可読性も効率もとても悪くて、意図する動作に書き換えられないようなことをやっていると感じます(けなすつもりではなく、客観的事実として)。 ・f.read()が何を返すのか理解する必要があります。 ・resultとnodeを宣言している位置もおかしいです。複数回ループすることを想定しているのなら、ループのたびに上書きされるので無意味です。まあ、結果的にはこれでファイル全体を形態素解析できるのですが(f.read()の結果と関係する)。 ・下のwhileも、一単語取るたびにファイルを上書きしてしまう動作になっています。
hayataka2049

2019/07/18 22:16

質問文に書いてあるようなpythonのlistをprintしたような形式で保存することを望むであれば、先のコメントで書いた通り読み込みにはast.literal_evalが使えます。
tono_1812

2019/07/19 20:05

ast.literal_evalなのですが、 今年の梅雨は遅い。 ^ SyntaxError: invalid character in identifier 読み込みでそのまま使えません。また、最後のresultで使うと全てを一つのリストにしてしまいます。
hayataka2049

2019/07/20 06:17

['今年', '梅雨', '遅い']のような文字列をリストに復元するのに使えるという意味ですが、たぶん使うタイミングが違うのではないでしょうか。
tono_1812

2019/07/25 10:22 編集

自身のスキル不足でベストアンサーをなかなか出せずに申し訳ありません。
guest

0

これで取得できると思います。for text in read_text:をやると重複するのでこれが一番無難なやり方な気がします。

python

1f = open('lines.txt', 'r') 2reader = f.readline() 3result = [] 4 5node = mecab.parseToNode(reader) 6 7 8while node: 9 #単語を取得 10 word = node.surface 11 #品詞を取得 12 pos = node.feature.split(",")[0] 13 if pos in ["名詞"]: 14 result.append(node.surface) 15 elif pos in["動詞","形容詞"]: 16 result.append(node.feature.split(",")[6]) 17 #次の単語に進める 18 node = node.next 19print(result)

投稿2019/07/18 16:32

bamboo-nova

総合スコア1408

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tono_1812

2019/07/18 17:02 編集

ご回答頂きありがとうございます! 一行分ではありますが、期待する処理が出ました! うまくforを使ってみます! もしよろしければ、保存するアイデアなどがございましたら、教えて頂けると幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問