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

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

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

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

pandas

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

Q&A

解決済

2回答

1342閲覧

pandasでDataFrameの中のデータを計算

memene

総合スコア1

Python

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

pandas

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

0グッド

0クリップ

投稿2021/06/15 13:58

編集2021/06/16 14:30

前提・実現したいこと

pandasでDataFrameを作成しています。
既に出来上がっているDFの内容を計算して、その結果を列に追加したいのですが、方法がわからなくて困っています。

データフレーム A B a 1 1 a 2 2 a 4 4 a 3 5 b 3 1 b 2 2 b 1 4 b 4 5 : :

abc・・・のグループ内で、それぞれの行のA数値+1の行とのBの値の差を
列を作成して追加したいです。

1行目は、2-1=1を追加
2行目は、5-2=3を追加
3行目は、4以上が無いので0

試したこと

forで一行ずつ処理する方法を試してみましたが、
データ数的に時間がかかってしまった?みたいです。

一気にできる方法などありましたら、ご教授いただけますでしょうか

解決方法

df.assign(C=-df.reset_index().groupby('index').apply(lambda sdf: sdf.sort_values('順位')['得点'].diff(-1).sort_index()).to_numpy())

現在の状況 1

昨日に頂いたコードを実行しました。
ありがとうございます。
目標)
indexのグループ別に、次の順位の人との得点の差を求めたいです

結果)
順位の最大数がindex別に変わるためだと思いますが、数値がずれるようです

df.head(20) 順位 得点 201901010101 1.0 1.4 201901010101 2.0 3.5 201901010101 6.0 46.6 201901010101 7.0 56.8 201901010101 9.0 140.3 201901010101 3.0 9.7 201901010101 8.0 114.7 201901010101 5.0 26.1 201901010101 4.0 16.4 201901010102 4.0 4.3 201901010102 6.0 19.8 201901010102 5.0 13.9 201901010102 8.0 27.2 201901010102 2.0 4.1 201901010102 7.0 27.0 201901010102 1.0 2.9 201901010102 3.0 4.2 201901010103 3.0 4.5 201901010103 1.0 3.6 201901010103 7.0 14.0

実行と結果になります。

df2 = df.reset_index() df2['C'] = 0 for i in range(max(df['順位'].astype(int))): df2['shift_index'] = df2['index'].shift(-i-1) df2['shift_B'] = df2['得点'].shift(-i-1) df2['C'] = df2['C'].mask((df2['順位']==i+1) & (df2['index']==df2['shift_index']), df2['shift_B']-df2['得点']) df3 = df2.drop(['shift_index', 'shift_B'], axis=1).set_index('index') df3.head(20) 順位 得点 C index 201901010101 1.0 1.4 2.1 201901010101 2.0 3.5 53.3 201901010101 6.0 46.6 -30.2 201901010101 7.0 56.8 0.0 201901010101 9.0 140.3 0.0 201901010101 3.0 9.7 6.7 201901010101 8.0 114.7 0.0 201901010101 5.0 26.1 0.0 201901010101 4.0 16.4 0.0 201901010102 4.0 4.3 -0.2 201901010102 6.0 19.8 -15.6 201901010102 5.0 13.9 -9.7 201901010102 8.0 27.2 0.0 201901010102 2.0 4.1 -1.2 201901010102 7.0 27.0 0.0 201901010102 1.0 2.9 1.3 201901010102 3.0 4.2 0.0 201901010103 3.0 4.5 54.6 201901010103 1.0 3.6 10.4 201901010103 7.0 14.0 39.3

現在の状況 2

C列の計算結果は正しい数値が取得できました。ありがとうございます
あとは、DataFrameの構造をもとに戻す方法と、やり方が見えてきたので崩さずに追加できないか模索してみます!

df2 = df.reset_index() df2 = df2.rename(columns={'index':'group'}) temp_df = df2.set_index(['group', '順位']) new_df = temp_df.assign(C=(temp_df.rename(index=lambda s: s-1, level=1) - temp_df)).reset_index() new_df.head(20) group 順位 得点 C 0 201901010101 1.0 1.4 2.1 1 201901010101 2.0 3.5 6.2 2 201901010101 6.0 46.6 10.2 3 201901010101 7.0 56.8 57.9 4 201901010101 9.0 140.3 NaN 5 201901010101 3.0 9.7 6.7 6 201901010101 8.0 114.7 25.6 7 201901010101 5.0 26.1 20.5 8 201901010101 4.0 16.4 9.7 9 201901010102 4.0 4.3 9.6 10 201901010102 6.0 19.8 7.2 11 201901010102 5.0 13.9 5.9 12 201901010102 8.0 27.2 NaN 13 201901010102 2.0 4.1 0.1 14 201901010102 7.0 27.0 0.2 15 201901010102 1.0 2.9 1.2 16 201901010102 3.0 4.2 0.1 17 201901010103 3.0 4.5 NaN 18 201901010103 1.0 3.6 NaN 19 201901010103 7.0 14.0 NaN

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

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

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

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

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

bsdfan

2021/06/16 00:17

「abc・・・のグループ内で、それぞれの行のA数値+1の行」というのがどういうことかよくわかりません。 > 1行目は、2-1=1を追加 1行目はAが1、1+1=2行目のBは2、1行目のBの1との差 2-1=1 > 2行目は、5-2=3を追加 2行目はAが2、2+1=3行目のBは4、2行目のBの2との差 4-2=2 2行目の5というのはどこから出てきますか?(自身の行からAの値下の行とか??) 現状のコードで、時間がかかっても正しい結果が出ているなら、コードを載せていただいた方が、やりたいことが分かりやすいです。
memene

2021/06/16 13:54

ありがとうございます。 説明不足でお手間とらせてしまって申し訳ございません! 本来のデータの意味とは違うのですが、仮に学校のテストのデータとすると indexのグループごとに、次の順位の人との得点の差を求めたかったです! 得点差以外にも、他の計算式に変えて、いろいろ求めて追加をしていきたいと考えています 目的としていた結果は、追記させていただいた「現在の状況 2」が正しいです。
bsdfan

2021/06/16 14:32

A数値+1の行が、A数値+1行目かと思ったのですが、次の順位という説明で理解できました。
memene

2021/06/16 14:37

ご教授くださった皆様、ありがとうございました この場をかりてお礼申し上げます!
guest

回答2

0

ベストアンサー

やりたいことがよくわかっていないのですが、A列でソートしてB列の一個下との差をとるということですか?

python

1df = pd.DataFrame([['a', 1, 1], ['a', 2, 2], ['a', 4, 4], ['a', 3, 5], 2 ['b', 3, 1], ['b', 2, 2], ['b', 1, 4], ['b', 4, 5], 3 ['c', 3, 1], ['c', 4, 2], ['c', 1, 4], ['c', 2, 6]], 4 columns=['group', 'A', 'B']) 5# group A B 6# 0 a 1 1 7# 1 a 2 2 8# 2 a 4 4 9# 3 a 3 5 10# 4 b 3 1 11# 5 b 2 2 12# 6 b 1 4 13# 7 b 4 5 14# 8 c 3 1 15# 9 c 4 2 16# 10 c 1 4 17# 11 c 2 6 18 19 20# 方法1 21new_df = df.assign(C=-df.groupby('group').apply(lambda sdf: sdf.sort_values('A')['B'].diff(-1).sort_index()).to_numpy()) 22# 方法2 23new_df = df.assign(C=df.merge(df.eval('A = A-1'), on=['group', 'A'], how='left').eval('B_y - B_x')) 24# 方法3 25temp_df = df.set_index(['group', 'A']) 26new_df = temp_df.assign(C=(temp_df.rename(index=lambda s: s-1, level=1) - temp_df)).reset_index() 27 28new_df 29# group A B C 30# 0 a 1 1 1.0 31# 1 a 2 2 3.0 32# 2 a 4 4 NaN 33# 3 a 3 5 -1.0 34# 4 b 3 1 4.0 35# 5 b 2 2 -1.0 36# 6 b 1 4 -2.0 37# 7 b 4 5 NaN 38# 8 c 3 1 1.0 39# 9 c 4 2 NaN 40# 10 c 1 4 2.0 41# 11 c 2 6 -5.0

投稿2021/06/16 01:09

kirara0048

総合スコア1399

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

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

memene

2021/06/16 13:30

はい!おっしゃる通りです。 実行結果を追記いたします!
kirara0048

2021/06/16 13:49 編集

順位に抜け(「1位と3位があるのに2位はない」という状態)がないなら、質問文のdfに対しては下記コードで可能だと思うのですがいかがでしょうか。 df.assign(C=-df.reset_index().groupby('index').apply(lambda sdf: sdf.sort_values('順位')['得点'].diff(-1).sort_index()).to_numpy())
memene

2021/06/16 14:02

こちらも、とても魅力的なコードでした! 質問内容として、差分だけでしたらこちらがファイナルアンサーでした! しかし、のちのち他の計算(倍率等々)も視野にいれていた背景もあったので、3番目を選択した次第です
guest

0

A列の値は1以上であることと、aとかbは連続していることを仮定してみました。

残念ながら、一気にできる方法は思いつけませんでした。
for文で回していますが、一行ずつやるよりは速いと思います。

python

1df2 = df.reset_index() 2df2['C'] = 0 3 4for i in range(max(df['A'])): 5 df2['shift_index'] = df2['index'].shift(-i-1) 6 df2['shift_B'] = df2['B'].shift(-i-1) 7 df2['C'] = df2['C'].mask((df2['A']==i+1) & (df2['index']==df2['shift_index']), df2['shift_B']-df2['B']) 8 9df3 = df2.drop(['shift_index', 'shift_B'], axis=1).set_index('index') 10print(df3)

テストデータは以下です。

python

1>>> print(df) 2 A B 3a 1 1 4a 2 2 5a 4 4 6a 3 5 7b 3 1 8b 2 2 9b 1 4 10b 4 5 11c 3 1 12c 4 2 13c 1 4 14c 2 6

実行結果は以下です。

python

1>>> df2 = df.reset_index() 2>>> df2['C'] = 0 3>>> 4>>> for i in range(max(df['A'])): 5... df2['shift_index'] = df2['index'].shift(-i-1) 6... df2['shift_B'] = df2['B'].shift(-i-1) 7... df2['C'] = df2['C'].mask((df2['A']==i+1) & (df2['index']==df2['shift_index']), df2['shift_B']-df2['B']) 8... 9>>> df3 = df2.drop(['shift_index', 'shift_B'], axis=1).set_index('index') 10>>> print(df3) 11 A B C 12index 13a 1 1 1 14a 2 2 3 15a 4 4 0 16a 3 5 0 17b 3 1 4 18b 2 2 3 19b 1 4 1 20b 4 5 0 21c 3 1 5 22c 4 2 0 23c 1 4 2 24c 2 6 0

投稿2021/06/15 15:42

ppaul

総合スコア24668

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

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

memene

2021/06/15 18:31 編集

お時間いただき、本当にありがとうございます。 私も、「for i in len(tst['A'].unique())」でなんとか・・と、、、 shiftを使うとは思いつきもしませんでした! しかしながら、どうしても結果にズレがでてしまって、もう一度データを精査しました。質問前にすべき所、ほんとすみません。 時間をおいて頭を捻ってチャレンジしますが、何か方法があれば見捨てず御助力頂けると嬉しいです。 ・indexは年月○○〇に近い数値で、テストデータではabcとなってますが一貫性はないです。 ・Aは順位で常に1以上ですが、aやb内で順不同で、1-6や1-9と行数がバラバラです(おそらくこれが・・・曲者) ・Bは得点です 私には難易度高すぎて、頭痛が・・・
ppaul

2021/06/16 11:54

私が回答したコードで結果にズレがでるものがあるのならば、そのデータを機械可読な形で質問に追加していただければ見てみます。
memene

2021/06/16 13:17 編集

帰宅が遅くなりました。 追加いたします
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問