如何将 panda.Series 与动态比较器进行比较?
How to compare panda.Series with a dynamic comparator?
我确实有一个可行的解决方案。我很高兴自己真的找到了一个。但是,似乎应该有一个我目前不知道的更好的方法?
我希望能够在将 panda.Series 与另一个 panda.Series 或标量进行比较时动态指定要使用的比较器。
我目前的解决方案
import numpy as np
import pandas as pd
def func(data, values, shifts, comparator):
_if = comparator[0]( data.shift( shifts[0] ), values[0] )
_then = comparator[1]( data.shift( shifts[1] ), values[1] )
_else = comparator[2]( data.shift( shifts[2] ), values[2] )
return data[ np.where(_if, _then, _else) ]
if __name__ == '__main__':
series = pd.Series([1, 1, 0, 1, 1, 1, -1, -1, 0, -1, 1, 1, 1])
filter = series[ np.where(series == 0, series.shift(1) > 0, series > 0) ]
filter2 = func(
data=series,
values=[0,0,0],
shifts=[0,1,0],
comparator=[pd.Series.eq, pd.Series.gt, pd.Series.gt]
)
filter
和filter2
都给出完全相同的预期输出。我只是忍不住想有比我的自定义函数更好的方法,func()
代码解释:
series
指随时间变化的随机游走数据。 1
是向上的一步,-1
是向下的一步,0
是保持不变。我写 func()
是为了能够找到数据何时上升或下降。我希望能够在尽可能少的代码中选择、寻找、升级或退出。
当我说 "version" 时,我指的是获得有用结果并将其放入 filter
或 filter2
的代码,在我看来这些是版本 1 和2分别。要扩展我的 "readability" 评论,请注意每个评论中有多少代码:
- 第一个版本只有一行代码,很明显它的每个部分在做什么以及为什么
- 使用
func
的版本涉及10行代码,认知负荷更高。我,代码的 reader,必须将大量状态穿入和穿出函数
举个例子,如果我想获取两个连续值 > 0 的值,天真的解决方案是:
series[(series > 0) & (series.shift(1) > 0)]
但是用func
,虽然我觉得应该可以,但是我当然不能像上面那样轻松写出来。我想用 monte carlo 链做的更复杂的事情当然不能用它来表达
总的来说,我不鼓励您尝试编写 "generalized as possible" 代码,尤其是因为 "in future" 事情往往不会发生,或者至少发生的方式与您的 "general" 不同代码不够通用。也就是说,尝试 think/work 虽然像这样的练习确实有用,而且您一定会找到应用您的东西的方法 discovered/learned。尝试编写最通用的东西几乎总是一个错误,确定正确的抽象级别很难,需要大量的实践和经验
这种事情经常发生,甚至有一个术语来形容它:"You aren't gonna need it". there are lots of blog articles 说类似的话
希望有用,抱歉有点乱!
我确实有一个可行的解决方案。我很高兴自己真的找到了一个。但是,似乎应该有一个我目前不知道的更好的方法?
我希望能够在将 panda.Series 与另一个 panda.Series 或标量进行比较时动态指定要使用的比较器。
我目前的解决方案
import numpy as np
import pandas as pd
def func(data, values, shifts, comparator):
_if = comparator[0]( data.shift( shifts[0] ), values[0] )
_then = comparator[1]( data.shift( shifts[1] ), values[1] )
_else = comparator[2]( data.shift( shifts[2] ), values[2] )
return data[ np.where(_if, _then, _else) ]
if __name__ == '__main__':
series = pd.Series([1, 1, 0, 1, 1, 1, -1, -1, 0, -1, 1, 1, 1])
filter = series[ np.where(series == 0, series.shift(1) > 0, series > 0) ]
filter2 = func(
data=series,
values=[0,0,0],
shifts=[0,1,0],
comparator=[pd.Series.eq, pd.Series.gt, pd.Series.gt]
)
filter
和filter2
都给出完全相同的预期输出。我只是忍不住想有比我的自定义函数更好的方法,func()
代码解释:
series
指随时间变化的随机游走数据。 1
是向上的一步,-1
是向下的一步,0
是保持不变。我写 func()
是为了能够找到数据何时上升或下降。我希望能够在尽可能少的代码中选择、寻找、升级或退出。
当我说 "version" 时,我指的是获得有用结果并将其放入 filter
或 filter2
的代码,在我看来这些是版本 1 和2分别。要扩展我的 "readability" 评论,请注意每个评论中有多少代码:
- 第一个版本只有一行代码,很明显它的每个部分在做什么以及为什么
- 使用
func
的版本涉及10行代码,认知负荷更高。我,代码的 reader,必须将大量状态穿入和穿出函数
举个例子,如果我想获取两个连续值 > 0 的值,天真的解决方案是:
series[(series > 0) & (series.shift(1) > 0)]
但是用func
,虽然我觉得应该可以,但是我当然不能像上面那样轻松写出来。我想用 monte carlo 链做的更复杂的事情当然不能用它来表达
总的来说,我不鼓励您尝试编写 "generalized as possible" 代码,尤其是因为 "in future" 事情往往不会发生,或者至少发生的方式与您的 "general" 不同代码不够通用。也就是说,尝试 think/work 虽然像这样的练习确实有用,而且您一定会找到应用您的东西的方法 discovered/learned。尝试编写最通用的东西几乎总是一个错误,确定正确的抽象级别很难,需要大量的实践和经验
这种事情经常发生,甚至有一个术语来形容它:"You aren't gonna need it". there are lots of blog articles 说类似的话
希望有用,抱歉有点乱!