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

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

新規登録して質問してみよう
ただいま回答率
85.35%
並列処理

複数の計算が同時に実行される手法

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

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

Q&A

解決済

1回答

10188閲覧

Python:Pandas.Dataframeで前の行の値を使って、行の値を変更したい

Takudom

総合スコア9

並列処理

複数の計算が同時に実行される手法

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

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

0グッド

0クリップ

投稿2021/01/03 23:47

編集2021/01/04 12:32

前提・実現したいこと

Pandas.Dataframeで前の行の値を使って、行の値を変更したい

発生している問題・エラーメッセージ

以下のようなPandas.Dataframeのデータがあります。
各行はそのTimeの時点におけるx,y,zの位置を表しています。(Timeはmsec,xyzはmm)

Time x y z

0 0 1950.385254 -114.936646 845.404541
1 504 1950.385254 -114.936676 845.404419
2 1832 1950.385376 -114.936737 845.404541
3 1976 1950.389038 -114.934784 845.401611
4 1984 1950.414795 -114.921631 845.382813
5 1992 1950.484375 -114.885681 845.331421
6 2000 1950.619995 -114.815666 845.231262
7 2008 1950.843750 -114.700241 845.066101
8 2016 1951.177246 -114.528023 844.820007
9 2024 1951.642944 -114.287712 844.475952
10 2032 1952.261841 -113.967934 844.018433
11 2040 1953.056641 -113.557175 843.430725
12 2048 1954.048828 -113.044235 842.696533
13 2056 1955.259888 -112.417793 841.799194
14 2064 1956.711426 -111.666199 840.722046
15 2072 1958.424561 -110.778175 839.448792
16 2080 1960.421387 -109.742630 837.962463
17 2088 1962.721436 -108.547462 836.246277
18 2096 1965.346558 -107.182030 834.282959
19 2104 1968.317383 -105.634575 832.055420
20 2112 1971.652832 -103.893509 829.545898
21 2120 1975.370239 -101.949677 826.739685

これをうまいこと処理して、前の行との
時間の差分
位置の差分((x0-x1) ** 2 + (y0-y1) ** 2 + (z0-z1) ** 2 ) ** 0.5
位置の差分 / 時間の差分を求めたいです。

サンプルのソースコード

Python

1import pandas as pd 2 3def length(pos1,pos2): 4 ans = ((pos1.x - pos2.x) **2 + (pos1.y - pos2.y) **2 + (pos1.z - pos2.z) **2)** 0.5 5 return ans 6 7df = pd.read_excel('test2.xlsx') 8lastvar = 0 9df['df_time'] = 0 10df['len'] = 0.0 11df['spd'] = 0.0 12 13for item in df.itertuples(): 14 if (hasattr(lastvar, 'Time')): 15 diff = item.Time - lastvar.Time 16 len = length(item,lastvar) 17 df.at[item.Index, 'df_time'] = diff 18 df.at[item.Index, 'len'] = len 19 df.at[item.Index, 'spd'] = len / diff * 1000 20 21 lastvar = item 22print(df)

結果

Time x y z df_time len spd

0 0 1950.385254 -114.936646 845.404541 0 0.000000 0.000000
1 504 1950.385254 -114.936676 845.404419 504 0.000126 0.000249
2 1832 1950.385376 -114.936737 845.404541 1328 0.000183 0.000138
3 1976 1950.389038 -114.934784 845.401611 144 0.005080 0.035280
4 1984 1950.414795 -114.921631 845.382813 8 0.034493 4.311665
5 1992 1950.484375 -114.885681 845.331421 8 0.093675 11.709316
6 2000 1950.619995 -114.815666 845.231262 8 0.182556 22.819506
7 2008 1950.843750 -114.700241 845.066101 8 0.301110 37.638782
8 2016 1951.177246 -114.528023 844.820007 8 0.448822 56.102707
9 2024 1951.642944 -114.287712 844.475952 8 0.626895 78.361925
10 2032 1952.261841 -113.967934 844.018433 8 0.833436 104.179465
11 2040 1953.056641 -113.557175 843.430725 8 1.070435 133.804352
12 2048 1954.048828 -113.044235 842.696533 8 1.336630 167.078779
13 2056 1955.259888 -112.417793 841.799194 8 1.632272 204.034050
14 2064 1956.711426 -111.666199 840.722046 8 1.957576 244.697004
15 2072 1958.424561 -110.778175 839.448792 8 2.311838 288.979722
16 2080 1960.421387 -109.742630 837.962463 8 2.696079 337.009862
17 2088 1962.721436 -108.547462 836.246277 8 3.108689 388.586106
18 2096 1965.346558 -107.182030 834.282959 8 3.551097 443.887085
19 2104 1968.317383 -105.634575 832.055420 8 4.022729 502.841118
20 2112 1971.652832 -103.893509 829.545898 8 4.522635 565.329433
21 2120 1975.370239 -101.949677 826.739685 8 5.047022 630.877725

試したこと

添付のコードのように、For文でかけるといえばかけるのですが、なんだかしっくり来ないというか、
スマートでないですし、前の値をループで保存しているので、並列化等ができないと思っています。
このコードをスマートに書き換えていただけないでしょうか?

Python初めて2日程度なので、Pythonらしく直していただいて構いません。

改良後のソースコード

lehshellさんから改良案を頂き、そのあたりで自分で調べた結果もふまえて書き換えたコードを以下においておきます。
shiftメソッドの他に、diffでもできるみたいです。

Python

1import pandas as pd 2 3def length(pos1,pos2): 4 ans = ((pos1.x - pos2.x) **2 + (pos1.y - pos2.y) **2 + (pos1.z - pos2.z) **2)** 0.5 5 return ans 6 7def length2(diffx,diffy,diffz): 8 ans = (diffx ** 2 + diffy ** 2 + diffz ** 2) ** 0.5 9 return ans 10 11def method1(): #改良前 12 df = pd.read_excel('test2.xlsx') 13 lastvar = 0 14 df['df_time'] = 0 15 df['len'] = 0.0 16 df['spd'] = 0.0 17 18 for item in df.itertuples(): 19 if (hasattr(lastvar, 'Time')): 20 diff = item.Time - lastvar.Time 21 len = length(item,lastvar) 22 df.at[item.Index, 'df_time'] = diff 23 df.at[item.Index, 'len'] = len 24 df.at[item.Index, 'spd'] = len / diff * 1000 25 lastvar = item 26 print(df) 27 28def method2(): #改良案1 29 df = pd.read_excel('test2.xlsx') 30 df['df_time'] = (df['Time'] - df['Time'].shift(1)).fillna(0) 31 df['len'] = length(df, df.shift(1)).fillna(0) 32 df['spd'] = (df['len'] / df['df_time'] * 1000).fillna(0) 33 print(df) 34 35def method3(): #改良案2 36 df = pd.read_excel('test2.xlsx') 37 df['df_time'] = df['Time'].diff().fillna(0) 38 df['len'] = length2(df["x"].diff(),df["y"].diff(),df["z"].diff()).fillna(0) 39 df['spd'] = (df['len'] / df['df_time'] * 1000).fillna(0) 40 print(df) 41 42 43method1() 44method2() 45method3()

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/01/04 02:20

ここは質問をする場所であって、「書き換えていただけないでしょうか」という依頼をする場所ではありませんよ。
ppaul

2021/01/04 08:39

スマートに書き換える、は何を期待していますか。 Takudomさんのコードは十分に読めます。 性能的には遅いでしょう。 もっと短く書くことはできそうですが、それが読みやすいかどうかは不明です。 何を期待されているかを書いていただければ、考えてみます。
Takudom

2021/01/04 12:02

m-oguraさん ご指摘ありがとうございます。承知しました、次から気をつけます。 ppaulさん 読めるのはおそらく読めますし、結果は正しいのでそのままでも良いとは思います。 ただ、For文で前のループの値を保存して、次のループで使っているので、シングルスレッドで走らせる用のプログラミングスタイルに見えます。 今回の計算で必要なのは、前のループの結果ではなく、そのセルとその次のセルのデータなので、そのような指定方法ができれば、並列化できるだろうと考えた次第です。 問題だったのはFor文の箇所でしたが、そこはlehshellさんが解決してくださいました。
guest

回答1

0

ベストアンサー

Python

1import pandas as pd 2 3def length(pos1,pos2): 4 ans = ((pos1.x - pos2.x) **2 + (pos1.y - pos2.y) **2 + (pos1.z - pos2.z) **2)** 0.5 5 return ans 6 7df = pd.read_excel('test2.xlsx') 8df['df_time'] = (df['Time'] - df['Time'].shift(1)).fillna(0) 9df['len'] = length(df, df.shift(1)).fillna(0) 10df['spd'] = (df['len'] / df['df_time'] * 1000).fillna(0) 11print(df)

投稿2021/01/04 01:47

lehshell

総合スコア1156

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

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

Takudom

2021/01/04 12:06

Lehshellさん ありがとうございます。 まさにこのようなやり方を求めてました。 キーはshift()メソッドだったようですね。
lehshell

2021/01/04 13:26

単に丸写しするだけでなく、消化した上で他の方法も調査しその結果を提示されているのは素晴らしいですね。 コードの書き方は人それぞれですが、関数化するのであれば個人的には def method2(): #改良案1   df = pd.read_excel('test2.xlsx')   ...   print(df) と関数内に固有のファイル名 'test2.xlsx' を入れるのは避けたいですね。 def add_calc_data(df):   ...   return df として df = pd.read_excel('test2.xlsx') df2 = add_calc_data(df) print(df2) と関数には df を渡し df の計算結果の追加の責務にとどめ return でアップデートした df を戻すようにした方が保守性が良いと感じます。
lehshell

2021/01/04 14:06

失礼、この場合 df に対してインプレース処理ですから return は不要でしたね。 def add_calc_data(df):   ... として df = pd.read_excel('test2.xlsx') add_calc_data(df) print(df) に訂正します。
Takudom

2021/01/04 14:53

lehshellさん 追加でありがとうございます。 おっしゃるとおりです。実際に使うときはファイル名は引数にします。 何から何までありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問