Python:改进长累积和

2024-07-08 11:05:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个程序可以处理大量的实验数据。数据存储为具有以下属性的类实例的对象列表:

  • time_point-样本的时间
  • cluster-从中获取样本的节点群集的名称
  • 节点-从中获取样本的节点的名称
  • qty1=第一个数量的样本值
  • qty2=第二个数量的样本值

我需要从数据集中派生一些值,按三种方式分组—一种是作为一个整体的示例,一种是针对每个节点的集群,另一种是针对每个节点。我需要导出的值取决于qty1和qty2的(时间排序)累计和:qty1和qty2的累计和的元素级和的最大值,最大值出现的时间点,以及qty1和qty2在那个时间点的值。在

我想出了以下解决方案:

dataset.sort(key=operator.attrgetter('time_point'))

# For the whole set
sys_qty1 = 0
sys_qty2 = 0
sys_combo = 0
sys_max = 0

# For the cluster grouping
cluster_qty1 = defaultdict(int)
cluster_qty2 = defaultdict(int)
cluster_combo = defaultdict(int)
cluster_max = defaultdict(int)
cluster_peak = defaultdict(int)

# For the node grouping
node_qty1 = defaultdict(int)
node_qty2 = defaultdict(int)
node_combo = defaultdict(int)
node_max = defaultdict(int)
node_peak = defaultdict(int)

for t in dataset:
  # For the whole system ######################################################
  sys_qty1 += t.qty1
  sys_qty2 += t.qty2
  sys_combo = sys_qty1 + sys_qty2
  if sys_combo > sys_max:
    sys_max = sys_combo
    # The Peak class is to record the time point and the cumulative quantities
    system_peak = Peak(time_point=t.time_point,
                       qty1=sys_qty1,
                       qty2=sys_qty2)
  # For the cluster grouping ##################################################
  cluster_qty1[t.cluster] += t.qty1
  cluster_qty2[t.cluster] += t.qty2
  cluster_combo[t.cluster] = cluster_qty1[t.cluster] + cluster_qty2[t.cluster]
  if cluster_combo[t.cluster] > cluster_max[t.cluster]:
    cluster_max[t.cluster] = cluster_combo[t.cluster]
    cluster_peak[t.cluster] = Peak(time_point=t.time_point,
                                   qty1=cluster_qty1[t.cluster],
                                   qty2=cluster_qty2[t.cluster])
  # For the node grouping #####################################################
  node_qty1[t.node] += t.qty1
  node_qty2[t.node] += t.qty2
  node_combo[t.node] = node_qty1[t.node] + node_qty2[t.node]
  if node_combo[t.node] > node_max[t.node]:
    node_max[t.node] = node_combo[t.node]
    node_peak[t.node] = Peak(time_point=t.time_point,
                             qty1=node_qty1[t.node],
                             qty2=node_qty2[t.node])

这将产生正确的输出,但我想知道是否可以使它更具可读性/Pythonic,和/或更快/更具伸缩性。在

上面的方法很有吸引力,因为它只在(大的)数据集中循环一次,但是没有吸引力,因为我基本上复制/粘贴了同一算法的三个副本。在

为了避免上述复制/粘贴问题,我还尝试了以下方法:

^{pr2}$

对于(非分组)系统级计算,我还提出了这样一个方案,这很不错:

dataset.sort(key=operator.attrgetter('time_point'))

def cuml_sum(seq):
  rseq = []
  t = 0
  for i in seq:
    t += i
    rseq.append(t)
  return rseq

time_get = operator.attrgetter('time_point')
q1_get = operator.attrgetter('qty1')
q2_get = operator.attrgetter('qty2')

timeline = [time_get(t) for t in dataset]
cuml_qty1 = cuml_sum([q1_get(t) for t in dataset])
cuml_qty2 = cuml_sum([q2_get(t) for t in dataset])
cuml_combo = [q1 + q2 for q1, q2 in zip(cuml_qty1, cuml_qty2)]

combo_max = max(cuml_combo)
time_max = timeline.index(combo_max)
q1_at_max = cuml_qty1.index(time_max)
q2_at_max = cuml_qty2.index(time_max)

然而,尽管这个版本很酷地使用了list comprehensions和zip(),它在数据集中循环了三次,只是为了进行系统级的计算,我想不出一个好的方法来执行集群级和节点级的计算,而不做一些缓慢的事情,如:

timeline = defaultdict(int)
cuml_qty1 = defaultdict(int)
#...etc.

for c in cluster_list:
  timeline[c] = [time_get(t) for t in dataset if t.cluster == c]
  cuml_qty1[c] = [q1_get(t) for t in dataset if t.cluster == c]
  #...etc.

堆栈溢出有没有人有改进的建议?上面的第一个片段对于我的初始数据集(大约一百万条记录)运行得很好,但是后面的数据集将有更多的记录和集群/节点,所以可伸缩性是一个问题。在

这是我对Python的第一次非平凡的使用,我想确保我充分利用了Python语言(这将替换一组非常复杂的SQL查询,Python版本的早期版本本质上是非常不有效的直接转换)。我平时不怎么编程,所以我可能会遗漏一些基本的东西。在

非常感谢!在


Tags: innodefortimesysdatasetmaxint
1条回答
网友
1楼 · 发布于 2024-07-08 11:05:09

这似乎是应用一点面向对象的经典机会。我建议将派生的数据作为一个类,并将累计和计算抽象为对该类起作用的东西。在

比如:

class DerivedData(object):
    def __init__(self):
        self.qty1 = 0.0
        self.qty2 = 0.0
        self.combo = 0.0
        self.max = 0.0
        self.peak = Peak(time_point=0.0, qty1=0.0, qty2=0.0)

    def accumulate(self, data):
        self.qty1 += data.qty1
        self.qty2 += data.qty2
        self.combo = self.qty1 + self.qty2
        if self.combo > self.max:
            self.max = self.combo
            self.peak = Peak(time_point=data.time_point,
                             qty1=self.qty1,
                             qty2=self.qty2)

sys = DerivedData()
clusters = defaultdict(DerivedData)
nodes = defaultdict(DerivedData)

dataset.sort(key=operator.attrgetter('time_point'))

for t in dataset:
    sys.accumulate(t)
    clusters[t.cluster].accumulate(t)
    nodes[t.node].accumulate(t)

这个解决方案抽象出了寻找峰值的逻辑,但仍然只遍历数据集一次。在

相关问题 更多 >

    热门问题