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

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

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

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

Q&A

解決済

5回答

8091閲覧

DataFrameの1行を複数行に分ける方法について教えてください。

WatanabeJin

総合スコア44

Python

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

0グッド

0クリップ

投稿2021/06/30 05:49

編集2021/06/30 08:55

問題

以下のようなデータフレームがあったとします。

属性コメントフラグ
患者おはようございます。今日もいい天気ですね1
患者はい0
医師かしこまりました。0

このデータフレームのコメントの内容を「。」で分割して複数行にしたいです。

最終的には以下のようにしたいと考えています。

属性コメントフラグ
患者おはようございます。1
患者今日もいい天気ですね1
患者はい0
医師かしこまりました。0

「おはようございます。今日もいい天気ですね」を「おはようございます。」「今日もいい天気ですね」に分割して2行にしたいです。コメント列以外はすべて同じになっています。

データフレームでこのような動作をうまく行う方法が思いつかなかったので教えていただきたいです。

データフレームは以下で作成可能です。

import pandas as pd zoku = ["患者", "患者", "医師"] comment = ["おはようございます。今日もいい天気ですね", "はい", "かしこまりました。"] flag = [1, 0, 0] df = pd.DataFrame({'属性':zoku, 'コメント':comment, 'フラグ':flag})

追記
説明足らずで申し訳ございません。
データフレームは用意されていると仮定していますので、データフレーム作成に利用したリストはないものと考えていただければと思います。(df['コメント'].tolist()などで一応可能ですが、もうすこしスマートな方法があれば知りたいです)

また、「おはようございます。今日もいい天気ですね。どこに行きますか」などは2行ではなく3行になる想定です。

属性コメントフラグ
患者おはようございます。1
患者今日もいい天気ですね1
患者 どこに行きますか1
患者はい0
医師かしこまりました。0

すでに多くの回答を頂きまして、ありがとうございます。説明不足でしたので追記させていただきました。

私が試したのは以下になります。もっとスマートなものがあれば教えていただきたいです。

import pandas as pd zoku = ["患者", "患者", "医師", "患者"] comment = ["おはようございます。今日もいい天気ですね", "はい", "かしこまりました。", "いいえ。そうではないです。"] flag = [1, 0, 0, 0] df = pd.DataFrame({'属性':zoku, 'コメント':comment, 'フラグ':flag}) def split_comment(df, index, index_list, comment_list): # 日本語の文章では|は利用されないと想定して区切り文字にする for comment in df["コメント"].replace('。','。|').split('|'): if comment != '': index_list.append(index) comment_list.append(comment) index_list = [] comment_list = [] df.apply(lambda x: split_comment(x, x.name, index_list, comment_list), axis=1) comment_df = pd.DataFrame({'コメント':comment_list}, index=index_list)

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

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

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

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

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

guest

回答5

0

ベストアンサー

解決済になっていますが、ベストアンサーが適当ではないので書いておきます。

句点のあとに適当な文字列を追加してそこで区切るという案は他の方と同じです。
.str.split()を用いるとリストが要素となったシリーズが返却されますが、.explode()メソッドを用いるとリストをスムーズに複数行に分割できます。

python

1df.assign(コメント=df['コメント'].str.replace('。', '。 ').str.split()).explode('コメント')

なお.explode()メソッドの使い方は公式ドキュメントを参照してください。
pandas.DataFrame.explode — pandas 1.2.5 documentation


追記:.str.split()メソッドで正規表現を工夫すれば.str.replace()は不要でした。

python

1df.assign(コメント=df['コメント'].str.split(r'(?<=。)(?=.)')).explode('コメント')

投稿2021/07/02 01:30

編集2021/07/02 01:34
kirara0048

総合スコア1399

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

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

WatanabeJin

2021/07/02 02:22

explodeがまさに私が求めていた関数でした。ありがとうございます。 ベストアンサーにさせていただきました。
toshikawa

2021/07/02 07:40

pandasは奥が深いですね。split()で正規表現が使えるのも初めてしりました。
guest

0

python

1import pandas as pd 2zoku = ["患者", "患者", "医師"] 3comment = ["おはようございます。今日もいい天気ですね。よろしくお願いします。", "はい", "かしこまりました。"] 4flag = [1, 0, 0] 5df = pd.DataFrame({'属性':zoku, 'コメント':comment, 'フラグ':flag}) 6 7# コメントを「。」でリスト分割。リストの長さを変数に代入 8df['コメント']=df['コメント'].str.replace('。','。 ').str.split() 9df['m']=df['コメント'].apply(lambda x: len(x)) 10 11# コメントのリストの長さで複製 12df = pd.DataFrame(np.repeat(df.reset_index().values,df.m,axis=0),columns=['インデックス','属性','コメント','フラグ','カウント']) 13 14# リストからの取り出しインデックスを作成 15df['カウント']=df.groupby('インデックス').expanding().count()['コメント'] .values.astype('int') - 1 16 17# コメント抽出 18df['コメント']=df.apply(lambda x: x['コメント'][x['カウント']],axis=1) 19 20# 不要な列を削除 21df.drop(['インデックス','カウント'],inplace=True,axis=1) 22 23""" 24df 25 26 属性 コメント フラグ 270 患者 おはようございます。 1 281 患者 今日もいい天気ですね。 1 292 患者 よろしくお願いします。 1 303 患者 はい 0 314 医師 かしこまりました。 0 32"""

いかがでしょうか?  2行以上も対応してみました。

投稿2021/06/30 08:35

編集2021/06/30 10:04
toshikawa

総合スコア388

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

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

WatanabeJin

2021/06/30 10:55

とてもわかりやすかったです。参考にさせていただきました。 こちらをベストアンサーとさせていただきました。 皆様ありがとうございました。
guest

0

コメントだけ分解して、あとはマージしました。

python

1N = 100 2index = [] 3comment = [] 4for i, c in df[['コメント']].itertuples(): 5 c_split = c.split('。') 6 c_last = c_split.pop() 7 c_list = [s + '。' for s in c_split] 8 if c_last != '': 9 c_list.append(c_last) 10 for j in range(len(c_list)): 11 index.append(i * N + j) 12 comment.append(c_list[j]) 13 14df_temp = pd.DataFrame({'index': index, 'コメント':comment}) 15df_temp2 = df.reset_index().drop('コメント', axis=1) 16df_temp2['index'] = df_temp2['index'] * N 17df_result = pd.merge(df_temp, df_temp2, how='left')[['属性', 'コメント', 'フラグ']].fillna(method='ffill') 18df_result['フラグ'] = df_result['フラグ'].astype(int)

Nは'。'で区切られる分の数の最大値より大きいものを指定してください。

結果

python

1>>> print(df_result) 2 属性 コメント フラグ 30 患者 おはようございます。 1 41 患者 今日もいい天気ですね 1 52 患者 はい 0 63 医師 かしこまりました。 0

投稿2021/06/30 08:40

ppaul

総合スコア24666

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

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

0

愚直に2重リストを作ったあとでdataframeにします。

Python

1import pandas as pd 2pd.set_option('display.unicode.east_asian_width', True) 3 4zoku = ["患者", "患者", "医師","あああ"] 5comment = ["おはようございます。今日もいい天気ですね", "はい", "かしこまりました。", ""] 6flag = [1, 0, 0, 9] 7 8data = [] 9for z,c,f in zip(zoku,comment,flag): 10 11 cs = c.replace('。', '。\n').split('\n') 12 cs = [e for e in cs if e] # 空行は無視 13 14 # 元コメントが空も考慮。空1行のみ追加 15 if not cs: 16 cs = [''] 17 for c in cs: 18 data.append([z,c,f]) 19 20df = pd.DataFrame(data, columns=['属性', 'コメント', 'フラグ']) 21print(df) 22""" 23 属性 コメント フラグ 240 患者 おはようございます。 1 251 患者 今日もいい天気ですね 1 262 患者 はい 0 273 医師 かしこまりました。 0 284 あああ 9 29"""

投稿2021/06/30 08:29

can110

総合スコア38278

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

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

0

愚直にリストを足してみました
「。」の重複を無視します(['おはよう。。ありがとう']->['おはよう。','ありがとう']

python

1zoku = ["患者", "患者", "医師"] 2comment = ["おはようございます。今日もいい天気ですね", "はい", "かしこまりました。"] 3flag = [1, 0, 0] 4zoku2=[] 5comment2=[] 6flag2=[] 7 8for i,txt in enumerate(comment): 9 splited = txt.split("。") 10 for j,txt2 in enumerate(splited): 11 if j != len(splited) -1 : 12 txt2 += "。" #splitで消えた「。」の補充 13 if txt2 == "" or txt2 == "。": #ここで"。"のみを無視 14 pass 15 else: 16 comment2 += [txt2] 17 zoku2 += [zoku[i]] #i番目の属性をコピー 18 flag2 += [flag[i]] #i番目のフラグをコピー 19print(zoku2) 20print(comment2) 21print(flag2)

投稿2021/06/30 07:30

編集2021/06/30 07:34
Third_Kei

総合スコア65

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問