[FIXED] Berechnung des Rollabstands zwischen zwei Spalten in einem sortierten Pandas-Datenrahmen

Ausgabe

Ich habe eine Frage, auf die ich in einem ähnlichen Zusammenhang bereits eine Antwort erhalten habe. Es gelingt mir jedoch nicht, die Lösung zu übertragen, und ich bin für jeden Hinweis dankbar, wo ich den Fehler mache.

Ich möchte den Abstand (Abstand) zwischen einer ArucoID i und der vorhergehenden ArucoID i+1 in Bewegungsrichtung für jede FrameID berechnen. Grundsätzlich ist dies die Berechnung des Abstands zwischen Werten aus zwei Spalten eines sortierten und gruppierten Datenrahmens. Dann möchte ich den gleitenden Mittelwert auch auf diese Entfernung (rolling_headway) anwenden.

Ich gehe davon aus, dass die von @jlandercy vorgeschlagene Lösung analog funktionieren sollte:

Die Daten sind:

import numpy as np
import pandas as pd

data1 = {
    'ArucoID' : [910, 910, 910, 910, 910, 898, 898, 898, 898, 898, 912, 912, 912, 912, 912],
    'Subtrial' : ['01', '01', '01', '01', '01', '01', '01', '01', '01', '01', '01', '01', '01', '01', '01'],
    'frameID' : [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5],
    'xPos' : [10.0, 10.5, 11.0, 12.0, 13, 4.0, 5.0, 6.0, 7.0, 9.0, 1.5, 2.0, 2.5, 3.0, 4.0 ],
    'yPos' : [-0.2, -0.1, -0.1, 0.0, 0.0, 0.2, 0.2, -0.1, 0.0, 0.05, -0.2, -0.1, 0.0, 0.1, 0.05],
}

data2 = {
    'ArucoID' : [910, 910, 910, 910, 910, 898, 898, 898, 898, 898, 912, 912, 912, 912, 912],
    'Subtrial' : ['02', '02', '02', '02', '02', '02', '02', '02', '02', '02', '02', '02', '02', '02', '02'],
    'frameID' : [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5],
    'xPos' : [9.4, 9.5, 9.0, 9.0, 10, 3.0, 4.0, 5.0, 6.0, 7.0, 2.5, 3.0, 3.5, 3.5, 5.0 ],
    'yPos' : [-0.2, -0.1, -0.1, 0.0, 0.0, 0.2, 0.2, -0.1, 0.0, 0.05, -0.2, -0.1, 0.0, 0.1, 0.05],
}

df_raw = pd.concat([
    pd.DataFrame(data1),
    pd.DataFrame(data2) 
])

Mein Versuch:

  1. Sortieren der df nach frameID. Hier ist es wichtig, dass die ArucoID unsortiert bleibt, da die Reihenfolge nicht zwingend aufsteigend ist. Mit anderen Worten, ich möchte die Reihenfolge der ArucoIDs beibehalten.
df = df_raw.sort_values(["Subtrial", "frameID"])
  1. Ermittlung der verschobenen x-Position (Bewegungsrichtung ist in x-Richtung):
shifted = df.groupby(["Subtrial"]).shift(-1)
#print(shifted)
shifted = shifted.drop("frameID", axis=1).rename(columns=lambda x: x + "_")
data = pd.concat([df, shifted], axis=1)
  1. Berechnung des Abstands in Punkt (Rahmen):
def dX(x):
    return np.sqrt(np.power(x["xPos"] - x["xPos_"], 2))
        
data['point_headway'] = data.apply(dX, axis=1)
  1. Sortieren Sie die dfs nach ArucoID und Subtrial (weil ich den gleitenden Mittelwert für die spezifische ArucoID haben möchte), wenden Sie dann den gleitenden Mittelwert an (unter der Annahme einer Fenstergröße von 3 hier).
data["rolling_headway"] = data.sort_values(["Subtrial", "ArucoID",'frameID']).groupby(["Subtrial", "ArucoID"]).rolling(3, min_periods=2).mean()["point_headway"].values
#print(data)

Es fuehrt zu:

    frameID  xPos  yPos  ...  ArucoID_ point_headway  rolling_headway
5         1   4.0  0.20  ...     912.0           2.5         2.750000
6         2   5.0  0.20  ...     912.0           3.0         4.166667
7         3   6.0 -0.10  ...     912.0           3.5         5.500000
8         4   7.0  0.00  ...     912.0           4.0              NaN
9         5   9.0  0.05  ...     912.0           5.0         9.500000

Was ich erwartet habe (siehe letzte Spalte)

    frameID  xPos  yPos  ...  ArucoID_ point_headway    expected
5         1   4.0  0.20  ...     912.0           2.5         NaN
6         2   5.0  0.20  ...     912.0           3.0         NaN
7         3   6.0 -0.10  ...     912.0           3.5         3.000000 (2.5+3.0+3.5)/3
8         4   7.0  0.00  ...     912.0           4.0         3.500000 (3.0+3.5+4.0)/3
9         5   9.0  0.05  ...     912.0           5.0         4.166667 (3.5+4.0+5.0)/3

Wo habe ich den Denkfehler? Ich glaube, ich sortiere falsch, nicht wahr?

Vielen Dank im Voraus für Ihren Rat!

Lösung

df = df_raw.sort_values(["Subtrial", "frameID"])

# I wasn't sure what your were doing here... 
# absolute value was the only thing that made sense.
# I also didn't bother to make all those new columns.
df['point_headway'] = df.xPos.sub(df.groupby('Subtrial').xPos.shift(-1)).abs()

# I ignore_index here, so that the order is what you seem to expect.
df = df.sort_values(["Subtrial", "ArucoID",'frameID'], ignore_index=True)

# Your issue was here. You explicitly called `.values`,
# Probably to avoid an error. But you ended up losing your indexing,
# which was all over the place due to your sortings.
df["rolling_headway"] = (df.groupby(['Subtrial', 'ArucoID'])['point_headway']
                           .apply(lambda x: x.rolling(3).mean()))
# I used apply, just because it drops all the groupby key data and gives us our original index.

print(df)

Ausgabe:

    ArucoID Subtrial  frameID  xPos  yPos  point_headway  rolling_headway
0       898       01        1   4.0  0.20            2.5              NaN
1       898       01        2   5.0  0.20            3.0              NaN
2       898       01        3   6.0 -0.10            3.5         3.000000
3       898       01        4   7.0  0.00            4.0         3.500000
4       898       01        5   9.0  0.05            5.0         4.166667
5       910       01        1  10.0 -0.20            6.0              NaN
6       910       01        2  10.5 -0.10            5.5              NaN
7       910       01        3  11.0 -0.10            5.0         5.500000
8       910       01        4  12.0  0.00            5.0         5.166667
9       910       01        5  13.0  0.00            4.0         4.666667
10      912       01        1   1.5 -0.20            9.0              NaN
11      912       01        2   2.0 -0.10            9.0              NaN
12      912       01        3   2.5  0.00            9.5         9.166667
13      912       01        4   3.0  0.10           10.0         9.500000
14      912       01        5   4.0  0.05            NaN              NaN
15      898       02        1   3.0  0.20            0.5              NaN
16      898       02        2   4.0  0.20            1.0              NaN
17      898       02        3   5.0 -0.10            1.5         1.000000
18      898       02        4   6.0  0.00            2.5         1.666667
19      898       02        5   7.0  0.05            2.0         2.000000
20      910       02        1   9.4 -0.20            6.4              NaN
21      910       02        2   9.5 -0.10            5.5              NaN
22      910       02        3   9.0 -0.10            4.0         5.300000
23      910       02        4   9.0  0.00            3.0         4.166667
24      910       02        5  10.0  0.00            3.0         3.333333
25      912       02        1   2.5 -0.20            7.0              NaN
26      912       02        2   3.0 -0.10            6.0              NaN
27      912       02        3   3.5  0.00            5.5         6.166667
28      912       02        4   3.5  0.10            6.5         6.000000
29      912       02        5   5.0  0.05            NaN              NaN


Beantwortet von –
BeRT2me


Antwort geprüft von –
Jay B. (FixError Admin)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like