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

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

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

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

892閲覧

ある特定のデータフレームにパラメータを渡すことで任意の列計算をした結果として生成するプログラムを作りたい。

H.K2

総合スコア88

Python 3.x

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

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2020/08/13 17:07

編集2020/08/14 00:26

前提・実現したいこと

pandas のデータフレームに取り込んだ任意のデータについて、任意の列計算を行い、
別のデータフレームに変換して、最終的にexcelに張り付けるなどを汎用的に行いたいと考えています。

発生している問題

そのため、下記の図のようなイメージで動くメソッドを作りたいのですが、
パラメータ(自分のイメージでは、ordered_dict)に渡した名称を使って、dataframeを作る段になって、
どうやったらdfが生成できるかのイメージがわかず困っています。どのようにしたら、カラム名を使った
列計算をした形でデータフレームが初期化できるでしょうか。お手数をおかけいたしますが、
ご回答いただけましたら幸甚です。
イメージ説明

補足情報(FW/ツールのバージョンなど)

python 3.6
pandas 1.0

問題の背景・回答

入力・出力は?→
入力:test_dfと、新しく作るデータフレームの列名と、任意の列計算するための計算式
出力:新しいデータフレーム

pythonで普通に計算式を書いては?→
計算式を直接プログラムに書ければそれでよいのですが、下記2点の理由でできれば避けたいということです。
・計算式が頻繁に変わるので、コードの中に入れると、配布用にexe化することが現実的でなくなる。
・pythonプログラムを書いたことない人でも(列名さえわかれば)設定できるようにしたい。
(Excelしか触ったことないような人がパラメータを設定するくらいを想定しています。)

dfの作り方が分からない?→
Dataframeの作り方は標準的な生成方法はわかります。(が、それだとできないのでは?と思っています。)

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

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

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

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

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

aokikenichi

2020/08/14 00:10

何が入力で何が出力か分かりません test_df:「pandas のデータフレームに取り込んだ任意のデータ」 param_orderd_dict:「任意の列計算を行い、」  ←これをExcelに貼り付ける等いこと?  ←計算式を任意にということ?  ←「生成先の列名、計算式を持てるように」なら、Pythonで普通に数式を書けばよいのでは? change_df:「別のデータフレームに変換」 これな何を貼り付ける?:「最終的にexcelに張り付けるなどを汎用的に」 それとも単にDataFrameの作り方が分からないだけ?でしょうか
H.K2

2020/08/14 00:23

入力は、test_dfと、計算式のパラメータ(ここではordered_dictを想定してますが、ほかのコンテナでもよいと思っています。ただ、新しく作るデータフレームの列名と、計算式がいるので、このような形かなと思っているだけです。) test_dfを、任意の列名を用いた計算を行って新たなデータフレームを生成したい (Excelに張り付けるのはあくまで一つの例) 計算式を直接プログラムに書ければそれでよいのですが、下記2点の理由でできれば避けたいということです。 ・計算式が頻繁に変わるので、コードの中に入れると、配布用にexe化することが現実的でなくなる。 ・pythonプログラムを書いたことない人でも(列名さえわかれば)設定できるようにしたい。  (Excelしか触ったことないような人がパラメータを設定するくらいを想定しています。) Dataframeの作り方は標準的な生成方法はわかります。(が、それだとできないのでは?と思っています。)
YT0014

2020/08/14 03:36

計算式を、文字列などで入力して、それを内部で解釈して処理したい、ということでしょうか?
H.K2

2020/08/15 03:09

そうです。ただ、究極の目的は、列計算の部分を外だしして、pythonが分からない人に対しても列間のデータを加減乗除できればいいので、ほかのやり方があればご教示いただけますと助かります。
aokikenichi

2020/08/15 03:22

「pythonが分からない人に対しても列間のデータを加減乗除できればいい」 「最終的にexcelに張り付けるなどを汎用的に行いたい」 それならこんな面倒なことをせずにExcelで普通に計算するのが一番良いのでは、、、
H.K2

2020/08/15 03:32

Excelでやると、ブック間の参照とかを突っ込まれたりして、いつの間にかファイルが壊されてしまうので、できれば最終段だけExcelにしておきたかったのですが、Excelでやったほうがいいでしょうか…。うーん。ありがとうございます。Pythonでやろうとすると思いのほか面倒、ということなんですね。
aokikenichi

2020/08/15 03:47

ご質問の内容で数式を出してExcelに貼り付けても、ブック間の参照を突っ込まれるかどうか、には何ら影響しないかと思います。 計算式が決まっているならばPythonで計算したほうがいいですし 計算式が任意ならExcelにて 「ブック間の参照」が必要ならば今回のご質問の内容では対応出来ません 別途そういうツールを作るか、Excelで保護をいろいろ掛ける方が得策かと ご質問の内容からPythonの勉強の1つとしてトライされているのかと思いましたが、実運用での問題 とのことであればPython云々よりも実運用でやりたいこと、制約を今一度整理なさったほうがよろしいかと思います。
H.K2

2020/08/15 03:57 編集

承知いたしました。ご指摘のとおりかもしれませんね。ExcelやVBAでやろうとしてもちょっと面倒なレベルで行、列データが実際は多いこと、pythonでやろうとするとどういう感じになるのかというのもあった(pandasの機能とかを使えばそのあたりを簡単にできるものがあるのかもという期待もあった)のですが、まずはもう少し課題を整理してみようと思います。お手数をおかけいたしました。(ゴールについても、もう少しわかるように見直してみようと思います。何かうまく伝わっていない気がするのもあるので…。)
aokikenichi

2020/08/15 04:30

示された問題だけならVBAもいらず ユーザーがただ計算式を入れるだけだと思いますが なぜシート参照するのかもよく分かりません 少なくとも示された問題であれば下のコードで出力されますのでよろしければお試しください
H.K2

2020/08/15 06:26

上記はあくまで簡単な例としての話となります。(実際はいろいろなデータが複数のシートにまたがっているので、シート参照が必要になっているようです。そういう意味では例が悪いのだと思います…。) コードは試してみたのですが、ちょっと思っていたのと違うようなので、もう少しコードの動きを見てみます。すみません。
guest

回答2

0

ベストアンサー

演算子をパースするのは大変なのでexec()を使うのはどうでしょう?

python

1import pandas as pd 2from io import StringIO 3 4def create_dataframe_by_rules(df, rules): 5 new_df = pd.DataFrame() 6 for col_name, rule in rules.items(): 7 for column in df.columns: 8 rule = rule.replace(column, f"df['{column}']") 9 exec(f"new_df['{col_name}'] = {rule}") 10 return new_df 11 12 13str_input = """ 14hoge,foo,bar 151,2,3 164,5,6 177,8,9 18""" 19test_df = pd.read_csv(StringIO(str_input)) 20rules = {"列1": "hoge+foo", "列2": "hoge*2+foo*3+bar*4/2"} 21 22change_df = create_dataframe_by_rules(test_df, rules) 23print(change_df) 24 25# 実行結果 26# 列1 列2 27# 0 3 14.0 28# 1 9 35.0 29# 2 15 56.0

投稿2020/08/15 23:28

編集2020/08/15 23:34
yymmt

総合スコア1615

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

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

H.K2

2020/08/16 13:32 編集

ああ、ありがとうございます!こういうのを求めていたんです。 なるほど、replaceでカラム名をそのままdf[""]に置き換えてしまえば、execが通せるんですね!わかりやすいコードで大変ありがたいです!
guest

0

  • こんな2ファイルを用意して

data.csv

hoge,foo,bar 1,2,3 4,5,6 7,8,9

rule.csv

1,2 hoge+foo,hoge*2+foo*3+bar*4/2
  • 下記でご要望のものと思われる出力が出ました(ちょっと泥なこーどになっちまいましたがお許しを)
    • change_df で例示いただいた出力は誤っているかと
      • 12+23+3*4/2=2+6+6=14 なので

Python

1import pandas as pd 2import re 3 4data = pd.read_csv('data.csv') 5rule = pd.read_csv('rule.csv') 6 7fields1 = re.findall('[a-zA-Z]+', rule.iloc[0, 0]) 8fields2 = re.findall('[a-zA-X]+', rule.iloc[0, 1]) 9symbols1 = re.findall('[+\-*/\d]+', rule.iloc[0, 0]) 10symbols2 = re.findall('[+\-*/\d]+', rule.iloc[0, 1]) 11 12for i in range(len(data)): 13 # field1 14 formula1 = '' 15 tmp_fields1 = fields1.copy() 16 tmp_symbols1 = symbols1.copy() 17 while(tmp_fields1): 18 f = tmp_fields1.pop(0) 19 formula1 += 'data["' + f + '"][' + str(i) + ']' 20 if len(tmp_symbols1) > 0: 21 s = tmp_symbols1.pop(0) 22 formula1 += s 23 print(eval(formula1)) 24 # field2 25 formula2 = '' 26 tmp_fields2 = fields2.copy() 27 tmp_symbols2 = symbols2.copy() 28 while(tmp_fields2): 29 f = tmp_fields2.pop(0) 30 formula2 += 'data["' + f + '"][' + str(i) + ']' 31 if len(tmp_symbols2) > 0: 32 s = tmp_symbols2.pop(0) 33 formula2 += s 34 print(eval(formula2))
  • 出力
    • これをchange_df的にDataFrameは出来ると思いますので略
3 14.0 9 35.0 15 56.0

投稿2020/08/14 09:30

aokikenichi

総合スコア2218

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

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

H.K2

2020/08/15 03:12 編集

ご回答ありがとうございます。すみません。これってステップ実行しながらコードを読んでいっているのですが、formuraとsymbolをtempに入れて、ひとつずつpopしながら全列計算している、という理解でよいのでしょうか。 また、これを関数化するとしたら、入力はdataとruleのdfで、evalのdfが出力ということでよいでしょうか。
aokikenichi

2020/08/15 03:24

質問の意味がよくわからないです。ご要望のものと違うとのことでしょうか。
H.K2

2020/08/15 03:50 編集

dataを列計算した結果がevalのdfとして帰ってくるのかなと思っていました。あと、見る限り、rule[0,0],rule[0,1]しか使われていない様なのですが、列が増えると、このコードを汎用的に変えないといけないのでしょうか。 逆に、要素ごとでないと難しいということなのですね。(mapとかfilterを使うともっときれいな感じにできるのかなと思っていました。)ともあれ、ありがとうございます。
aokikenichi

2020/08/15 04:35

列計算、evalのdf がなんのことか分かりませんが evalを用いて計算した結果をdfにすることが必要ならば代入すればよいかと思います。 ご質問の点で難しい点が数式を読み取るところと、読み取った数式をPythonで実行するところと 思いましたのでそこを正規表現とevalで実行する例を示しました。 お題が2列でしたので2列にしました。汎用性はforでもmapでも使えば出来ます。 要素ごとでないと難しいとは一言も申しておりません。 時間をかければもっときれいなコードに出来ますが、難しい点と思われる点に絞って回答しました。 ご不服であれば別の方の回答をお待ち下さい。
H.K2

2020/08/15 22:46

承知いたしました。ありがとうございます。 ちょっと今抱えている問題に適用できるようにコードを変えてみます。実現できたら問題のほうをクローズとさせていただきます。
H.K2

2020/08/16 13:31

すみません。おっしゃりたいご回答について、確かに確認はできましたが、replace->execとする形のほうが、自分が求めている形としてマッチしていましたので、もう一つの案のほうをベストアンサーとさせていただきました。いろいろご指摘をいただきありがとうございました。勉強になりました。
aokikenichi

2020/08/16 13:35

全然いいんですが 「実際はいろいろなデータが複数のシートにまたがっているので、シート参照が必要になっているようです。」 は全く関係ないですよね。 一生懸命対応しているのに回答者をバカにするような対応は今後おやめください。
H.K2

2020/08/16 13:41 編集

馬鹿にしているような対応をしたつもりはなかったのですが、、、ご気分を害されてしまい、大変申し訳ありませんでした。。以後気を付けます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問