按属性过滤的设计模式
Design pattern for filtering by attributes
我是一名科学家,正在努力学习更好的软件工程实践,以便我的分析脚本更健壮并且更容易被其他人使用。我无法找到以下问题的最佳模式。是否有一个 OOP 框架可以通过实例属性轻松子集化?例如:
- 随着时间的推移,我有大量 table 车辆轨迹
[[x, y]]
。这些是不同车手的不同车手,在赛道上进行计时赛。
import pandas as pd
import numpy as np
df = pd.DataFrame({'Form': {0:'SUV', 1:'Truck', 2:'SUV', 3:'Sedan', 4:'SUV', 5:'Truck'},
'Make': {0:'Ford', 1:'Toyota', 2:'Honda', 3:'Ford', 4:'Honda', 5:'Toyota'},
'Color': {0:'White', 1:'Black', 2:'Gray', 3:'White', 4:'White', 5:'Black'},
'Driver age': {0:25, 1:37, 2:21, 3:54, 4:50, 5:67},
'Trajectory': {0: np.array([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]]),
1: np.array([[0, 0], [0.15, 1.3], [1.6, 1.3], [4.2, 4.1]]),
2: np.array([[0, 0], [0.24, 1.2], [1.3, 1.6], [4.1, 3.9]]),
3: np.array([[0, 0], [0.45, 1.6], [1.8, 1.8], [4.2, 4.6]]),
4: np.array([[0, 0], [0.85, 1.9], [1.5, 1.7], [4.5, 4.3]]),
5: np.array([[0, 0], [0.35, 1.8], [1.5, 1.8], [4.6, 4.1]]),
}
})
- 一个函数将轨迹作为输入,并随着时间的推移对其进行分析。例如
def avg_velocity(trajectory):
v = []
for t in range(len(trajectory) - 1):
v.append(trajectory[t+1] - trajectory[t])
return np.mean(v)
- 我想编写一个程序来分析特定子集的轨迹,例如。 SUV 上所有驱动器的平均速度,白色车辆上所有驱动器的平均速度。
我目前的解决方案是:
- 我使用 Pandas Dataframe 来存储 table。
- 我根据不同的标准(即
df.groupby(by=['Form'])
)
- 迭代这个数据帧列表,我将每个轨迹传递给一个函数
avg_velocity(trajectory)
。
- 我将结果存储在嵌套字典中 即。
results[vehicle_make][vehicle_form][vehicle_color][driver_age]
.
- 为了检索信息,我按键访问了嵌套字典。
一种自然的 OOP 方法可能是创建具有许多属性(即 Drive.make, Drive.form, Drive.age, ...
等)的 class Drive
。
class Drive:
def __init__(self, form, make, color, age, trajectory):
self.form = form
self.make = make
self.color = color
self.age = age
self.trajectory = trajectory
...
但是,当每个驱动器被分成不同的实例时,我不确定如何根据特定标准快速子集化。假设我突然想通过 Toyotas
绘制所有驱动器的平均速度。我必须遍历 Drive
个实例的列表,检查是否 Drive.make == 'Toyota'
。这是 OOP 的常见问题吗?
我建议坚持使用 Pandas,而不是您当前的解决方案或其 OOP 替代方案,如下所示:
# First, compute velocity
df["Average_velocity"] = df["Trajectory"].apply(avg_velocity)
df = df.drop(columns="Trajectory")
# Secondly, define a helper function to filter the dataframe as needed
def filter_by_attributes(df, form=None, make=None, color=None, age=None):
pairs = {"Form": form, "Make": make, "Color": color, "Driver age": age}
criterias = [
(df[col] == value) if value else ~df[col].isin([])
for col, value in pairs.items()
]
return df[criterias[0] & criterias[1] & criterias[2] & criterias[3]]
然后,你可以,比如,求所有白色SUV的平均速度,像这样:
print(filter_by_attributes(df, form="SUV", make=None, color="White", age=None))
# Output
Form Make Color Driver age Average_velocity
0 SUV Ford White 25 1.416667
4 SUV Honda White 50 1.466667
关注您的评论:
Is it possible to store objects (ie. a user defined class) within a dataframe? This would be congruent with the above: columns of the dataframe are retained as metadata, and another column is devoted to storing individual instances"
是的,你可以这样做:
car = Drive(
"SUV", "Ford", "White", 25, np.array([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]])
)
df = pd.DataFrame({key: [value] for key, value in car.__dict__.items()})
df["average_velocity"] = df["trajectory"].apply(avg_velocity)
df = df.drop(columns="trajectory")
df.loc[0, "instance"] = car
等等:
print(df)
# Output
form make color age average_velocity instance
0 SUV Ford White 25 1.416667 <__main__.Drive object at 0x00000236EE1F80B8>
print(df.loc[0, "instance"].form)
# Output
"SUV"
我是一名科学家,正在努力学习更好的软件工程实践,以便我的分析脚本更健壮并且更容易被其他人使用。我无法找到以下问题的最佳模式。是否有一个 OOP 框架可以通过实例属性轻松子集化?例如:
- 随着时间的推移,我有大量 table 车辆轨迹
[[x, y]]
。这些是不同车手的不同车手,在赛道上进行计时赛。
import pandas as pd
import numpy as np
df = pd.DataFrame({'Form': {0:'SUV', 1:'Truck', 2:'SUV', 3:'Sedan', 4:'SUV', 5:'Truck'},
'Make': {0:'Ford', 1:'Toyota', 2:'Honda', 3:'Ford', 4:'Honda', 5:'Toyota'},
'Color': {0:'White', 1:'Black', 2:'Gray', 3:'White', 4:'White', 5:'Black'},
'Driver age': {0:25, 1:37, 2:21, 3:54, 4:50, 5:67},
'Trajectory': {0: np.array([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]]),
1: np.array([[0, 0], [0.15, 1.3], [1.6, 1.3], [4.2, 4.1]]),
2: np.array([[0, 0], [0.24, 1.2], [1.3, 1.6], [4.1, 3.9]]),
3: np.array([[0, 0], [0.45, 1.6], [1.8, 1.8], [4.2, 4.6]]),
4: np.array([[0, 0], [0.85, 1.9], [1.5, 1.7], [4.5, 4.3]]),
5: np.array([[0, 0], [0.35, 1.8], [1.5, 1.8], [4.6, 4.1]]),
}
})
- 一个函数将轨迹作为输入,并随着时间的推移对其进行分析。例如
def avg_velocity(trajectory):
v = []
for t in range(len(trajectory) - 1):
v.append(trajectory[t+1] - trajectory[t])
return np.mean(v)
- 我想编写一个程序来分析特定子集的轨迹,例如。 SUV 上所有驱动器的平均速度,白色车辆上所有驱动器的平均速度。
我目前的解决方案是:
- 我使用 Pandas Dataframe 来存储 table。
- 我根据不同的标准(即
df.groupby(by=['Form'])
) - 迭代这个数据帧列表,我将每个轨迹传递给一个函数
avg_velocity(trajectory)
。 - 我将结果存储在嵌套字典中 即。
results[vehicle_make][vehicle_form][vehicle_color][driver_age]
. - 为了检索信息,我按键访问了嵌套字典。
一种自然的 OOP 方法可能是创建具有许多属性(即 Drive.make, Drive.form, Drive.age, ...
等)的 class Drive
。
class Drive:
def __init__(self, form, make, color, age, trajectory):
self.form = form
self.make = make
self.color = color
self.age = age
self.trajectory = trajectory
...
但是,当每个驱动器被分成不同的实例时,我不确定如何根据特定标准快速子集化。假设我突然想通过 Toyotas
绘制所有驱动器的平均速度。我必须遍历 Drive
个实例的列表,检查是否 Drive.make == 'Toyota'
。这是 OOP 的常见问题吗?
我建议坚持使用 Pandas,而不是您当前的解决方案或其 OOP 替代方案,如下所示:
# First, compute velocity
df["Average_velocity"] = df["Trajectory"].apply(avg_velocity)
df = df.drop(columns="Trajectory")
# Secondly, define a helper function to filter the dataframe as needed
def filter_by_attributes(df, form=None, make=None, color=None, age=None):
pairs = {"Form": form, "Make": make, "Color": color, "Driver age": age}
criterias = [
(df[col] == value) if value else ~df[col].isin([])
for col, value in pairs.items()
]
return df[criterias[0] & criterias[1] & criterias[2] & criterias[3]]
然后,你可以,比如,求所有白色SUV的平均速度,像这样:
print(filter_by_attributes(df, form="SUV", make=None, color="White", age=None))
# Output
Form Make Color Driver age Average_velocity
0 SUV Ford White 25 1.416667
4 SUV Honda White 50 1.466667
关注您的评论:
Is it possible to store objects (ie. a user defined class) within a dataframe? This would be congruent with the above: columns of the dataframe are retained as metadata, and another column is devoted to storing individual instances"
是的,你可以这样做:
car = Drive(
"SUV", "Ford", "White", 25, np.array([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]])
)
df = pd.DataFrame({key: [value] for key, value in car.__dict__.items()})
df["average_velocity"] = df["trajectory"].apply(avg_velocity)
df = df.drop(columns="trajectory")
df.loc[0, "instance"] = car
等等:
print(df)
# Output
form make color age average_velocity instance
0 SUV Ford White 25 1.416667 <__main__.Drive object at 0x00000236EE1F80B8>
print(df.loc[0, "instance"].form)
# Output
"SUV"