寻找更多 efficient/pythonic 方法来对列表中的元组求和,并计算平均值
Looking for a more efficient/pythonic way to sum tuples in a list, and compute an average
我正在尝试对来自网络的数据进行一些基本计算。为此,我找到了一些提取伦勃朗作品开始和结束年份的代码。它将它保存在列表中
date_list =[(work['datebegin'], work['dateend']) for work in `rembrandt2_parsed['records']]`
date_list 是一个列表,其中包含哈佛艺术博物馆中一些伦勃朗作品的开始和结束年份的元组。为了完整起见,它看起来像这样:
[(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0), (1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
现在我想做一些基本的计算,我想对这个元组列表求和,并计算它们不为空的年份的平均值。我想到了一个解决方案:
datebegin =0
date_end =0
count_begin =0
count_end =0
for x, y in date_list:
if x !=0:
datebegin +=x
count_begin +=1
if y != 0:
date_end +=y
count_end +=1
final_date_begin = datebegin/count_begin #value = year 1636
final_date_end = date_end/count_end #value = year 1639
但我认为这可以做得更多efficient/pythonic。首先,因为我似乎需要大量代码来完成这样一个简单的任务,其次,因为如果我这样做的话,我需要初始化 4(!) 个全局变量。 有人可以启发我并告诉我解决这个问题的更有效方法吗?
你可以使用numpy
来解决这个问题:
import numpy as np
result = list(np.ma.masked_equal(date_list, 0).mean(axis=0))
这里我们首先将 date_list
存储在一个数组中,接下来我们屏蔽掉零值,然后我们计算第一个轴上的平均值。
对于您的示例数据,我们获得:
>>> list(np.ma.masked_equal(date_list, 0).mean(axis=0))
[1636.3333333333333, 1639.6666666666667]
性能:对于包含 100'000 个二元组的列表,生成方式:
from random import randint
date_list = [(randint(0, 10), randint(0, 10)) for _ in range(100000)]
我们重复这个函数 1'000 次,得到:
>>> timeit(f, number=1000)
51.31010195999988
因此在本地,这适用于每 运行.
51.3 毫秒内的 100'000×2 "matrix"
非 numpy 解决方案:
lst = [(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0), (1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
print(sum(x[0] for x in lst) / sum(x[0] != 0 for x in lst))
# 1636.3333333333333
print(sum(x[1] for x in lst) / sum(x[1] != 0 for x in lst))
# 1639.6666666666667
Numpy 和列表理解是你的朋友。
import numpy as np
date_list = [(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0),
(1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
final_date_begin = np.mean([x for x, y in date_list if not x == 0])
final_date_end = np.mean([y for x, y in date_list if not y == 0])
纯Python
starts = [s for s, e in date_list for if s and e]
ends = [e for s, e in date_list for if s and e]
start_avg = sum(starts) / len(starts)
end_avg = sum(ends) / len(ends)
我正在尝试对来自网络的数据进行一些基本计算。为此,我找到了一些提取伦勃朗作品开始和结束年份的代码。它将它保存在列表中
date_list =[(work['datebegin'], work['dateend']) for work in `rembrandt2_parsed['records']]`
date_list 是一个列表,其中包含哈佛艺术博物馆中一些伦勃朗作品的开始和结束年份的元组。为了完整起见,它看起来像这样:
[(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0), (1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
现在我想做一些基本的计算,我想对这个元组列表求和,并计算它们不为空的年份的平均值。我想到了一个解决方案:
datebegin =0
date_end =0
count_begin =0
count_end =0
for x, y in date_list:
if x !=0:
datebegin +=x
count_begin +=1
if y != 0:
date_end +=y
count_end +=1
final_date_begin = datebegin/count_begin #value = year 1636
final_date_end = date_end/count_end #value = year 1639
但我认为这可以做得更多efficient/pythonic。首先,因为我似乎需要大量代码来完成这样一个简单的任务,其次,因为如果我这样做的话,我需要初始化 4(!) 个全局变量。 有人可以启发我并告诉我解决这个问题的更有效方法吗?
你可以使用numpy
来解决这个问题:
import numpy as np
result = list(np.ma.masked_equal(date_list, 0).mean(axis=0))
这里我们首先将 date_list
存储在一个数组中,接下来我们屏蔽掉零值,然后我们计算第一个轴上的平均值。
对于您的示例数据,我们获得:
>>> list(np.ma.masked_equal(date_list, 0).mean(axis=0))
[1636.3333333333333, 1639.6666666666667]
性能:对于包含 100'000 个二元组的列表,生成方式:
from random import randint
date_list = [(randint(0, 10), randint(0, 10)) for _ in range(100000)]
我们重复这个函数 1'000 次,得到:
>>> timeit(f, number=1000)
51.31010195999988
因此在本地,这适用于每 运行.
51.3 毫秒内的 100'000×2 "matrix"非 numpy 解决方案:
lst = [(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0), (1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
print(sum(x[0] for x in lst) / sum(x[0] != 0 for x in lst))
# 1636.3333333333333
print(sum(x[1] for x in lst) / sum(x[1] != 0 for x in lst))
# 1639.6666666666667
Numpy 和列表理解是你的朋友。
import numpy as np
date_list = [(0, 0), (1648, 1648), (1637, 1647), (1626, 1636), (0, 0),
(1638, 1638), (1635, 1635), (1634, 1634), (0, 0), (0, 0)]
final_date_begin = np.mean([x for x, y in date_list if not x == 0])
final_date_end = np.mean([y for x, y in date_list if not y == 0])
纯Python
starts = [s for s, e in date_list for if s and e]
ends = [e for s, e in date_list for if s and e]
start_avg = sum(starts) / len(starts)
end_avg = sum(ends) / len(ends)