wellwell3176
@wellwell3176

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

データに含まれる文字の一括変換方法

Q&A

Closed

追記

回答を元に完成できました。ありがとうございます。
https://qiita.com/wellwell3176/items/5c94871b5e059fce1e3d

解決したいこと

データに含まれる特定の文字列を抽出・変換したい。
例えば表1のようなデータが有り、データは「名前+復数の記号」で構成されている。
これに対して、表2のような変換表を用いて、表3のようなデータを作りたい。

表1 生データ df_raw

No. 馬名
1 コシヒカリ○③
2 ササニシキ◎
3 ヨモギダンゴ✕②
4 タナカタロウ①

表2 変換表

key value key value
1番 本命
2番 対抗
3番 大穴

表3 作りたいデータフレーム

No. 馬名 新聞予想 自分予想
1 コシヒカリ 対抗 3番
2 ササニシキ 本命
3 ヨモギダンゴ 大穴 2番
4 タナカタロウ 1番

自分で試したこと

今は変換表を使わず力技で実装しているのですが、これだとメンテナンスが大変なので、
変換表をCSVとして読み込んで、そのデータをもとに変換を掛けたい状況です。

自作
import pandas as pd

df = pd.DataFrame(
    data=[{
        'No.': 1,
        'horse': 'コシヒカリ○③',
    }, {
        'No.': 2,
        'horse': 'ササニシキ◎',
    }, {
        'No.': 3,
        'horse': 'ヨモギダンゴ✕②',
    }, {
        'No.': 4,
        'horse': 'タナカタロウ①',
    }])

df_shinbun=df["horse"].str.extract("(○|◎|✕)").replace("◎","本命").replace("○","対抗").replace("✕","大穴").fillna("")
df_kojin=df["horse"].str.extract("(①|②|③)").replace("①","一番").replace("②","二番").replace("③","三番").fillna("")
df["horse"]=df["horse"].str.replace("○|◎|✕|①|②|③","",regex=True)

df_complete=pd.concat([df,df_shinbun,df_kojin],axis=1)
df_complete.columns=("No.","horse","新聞予想","個人予想")

結果として出力される表(表3と一致しているので、ひとまずこれを使っている)

No. horse 新聞予想 個人予想
1 コシヒカリ 対抗 三番
2 ササニシキ 本命
3 ヨモギダンゴ 大穴 二番
4 タナカタロウ 一番

追記

自作
dictionary_data = pd.read_excel("hogehoge.xlsx")
df_dict=dictionary_data.to_dict()

表2を格納したhogehoge.xlsxに対して、to_dict()を行うことで辞書データへの変換はできた。

0

2Answer

もともと使用なさっていたコードを汎用化しただけですが。。。
Pandasはほとんど使用経験がないので、もっといいやり方があるかとは思います。

def tagging(df, column, trdict): #もとのDataFrame, 分類に使用するカラム, 分類用の辞書
    for key, d in trdict.items():
        df_ = df[column].str.extract(f'({"|".join(d.keys())})')
        for k, v in d.items():
            df_ = df_.replace(k, v)
            df[column] = df[column].str.replace(k, "")
        df[key] = df_.fillna("")
    return df


tagging(
    df,
    "horse",
    {
        "新聞予想": {"◎": "本命", "○": "対抗", "✕": "大穴"},
        "個人予想": {"①": "一番", "②": "二番", "③": "三番"},
    },
)

第3引数の辞書さえ作ってしまえば目的の表が出力されます。

2Like

Comments

  1. @wellwell3176

    Questioner

    @Cartelet様

    ありがとうございます。
    tagging()の中身は勉強中ですが、出力は正確に出ていました。
    辞書の読み込み次第でうまくいきそうなので、試してみます。

  2. @wellwell3176

    Questioner

    追記:一番上にも書きましたが、無事に実装できました。
    中身も大まかな流れは理解できた気がします。どうもありがとうございました。

Carteletさんのコードの比べると、全く汎用にはなっていませんが、辞書による一括置換の部分だけでも参考になればと思いまして、恥を忍んで書かせていただきます。

コード
import pandas as pd

# CSVから読み込まれたことにする辞書データ
kojin=pd.DataFrame([
    { 'symbol':'①', 'str':'1番' },
    { 'symbol':'②', 'str':'2番' },
    { 'symbol':'③', 'str':'3番' },
])
shinbun=pd.DataFrame([
    { 'symbol':'◎', 'str':'本命' },
    { 'symbol':'○', 'str':'対抗' },
    { 'symbol':'✕', 'str':'大穴' },
])

# 操作対象データ
df = pd.DataFrame(
    data=[{
        'No.': 1,
        'horse': 'コシヒカリ○③',
    }, {
        'No.': 2,
        'horse': 'ササニシキ◎',
    }, {
        'No.': 3,
        'horse': 'ヨモギダンゴ✕②',
    }, {
        'No.': 4,
        'horse': 'タナカタロウ①',
    }])

# 辞書の生成
kojin_symbols='('+pd.Series(kojin["symbol"]).str.cat(sep='|')+')'
kojin_dict=dict(zip(kojin.symbol,kojin.str))
shinbun_symbols='('+pd.Series(shinbun["symbol"]).str.cat(sep='|')+')'
shinbun_dict=dict(zip(shinbun.symbol,shinbun.str))

# 辞書による置換
df_kojin=df["horse"].str.extract(kojin_symbols).replace(kojin_dict).fillna("")
df_shinbun=df["horse"].str.extract(shinbun_symbols).replace(shinbun_dict).fillna("")
df["horse"]=df["horse"].str.replace(shinbun_symbols,"",regex=True).replace(kojin_symbols,"",regex=True)

# 対象への操作
df_complete=pd.concat([df,df_shinbun,df_kojin],axis=1)
df_complete.columns=("No.","horse","新聞予想","個人予想")

# 出力
print (df_complete, "\n")
print(kojin, "\n", kojin_dict, "\n", kojin_symbols)
print(shinbun, "\n", shinbun_dict, "\n", shinbun_symbols)
結果
   No.   horse 新聞予想 個人予想
0    1   コシヒカリ   対抗   3番
1    2   ササニシキ   本命     
2    3  ヨモギダンゴ   大穴   2番
3    4  タナカタロウ        1番 

  symbol str
0      ①  1番
1      ②  2番
2      ③  3番 
 {'①': '1番', '②': '2番', '③': '3番'} 
 (①|②|③)
  symbol str
0      ◎  本命
1      ○  対抗
2      ✕  大穴 
 {'◎': '本命', '○': '対抗', '✕': '大穴'} 
 (◎|○|✕)​

実のところ、PandasどころかPython自体も解っていませんので、おかしなことをしていたらごめんなさい。

1Like

Comments

  1. @wellwell3176

    Questioner

    @tetr4lab様

    ありがとうございます。
    replaceの引数にdict型を入れられるんですね。
    元となる辞書ファイルが増えそうなので、そのあたりを解決する必要はある気がしますが、参考になりました。
  2. お役に立てず申し訳ありません。
    CSVとのことでしたので単純な表を想定しました。
    種類毎に分けないなら、種類を表すカラムを増やして、それでフィルタして辞書に振り分ける感じになるでしょうか。
  3. @wellwell3176

    Questioner

    実際のデータだと変換表にそれなりのサイズが有り、簡略化したことが誤解を生んだようで申し訳ありません。

    最終的には変換表をカラム別でフィルタリングしました。辞書のフィルタリングについては知らなかったので、アドバイスありがたかったです。

Your answer might help someone💌