python groupby itertools 列表方法
python groupby itertools list methods
我有一个这样的列表:
#[年,日,VALUE1,VALUE2,VALUE3]
[[2014, 1, 10, 20, 30],
[2014, 1, 3, 7, 4],
[2014, 2, 14, 43,5],
[2014, 2, 33, 1, 6]
...
[2013, 1, 34, 54, 3],
[2013, 2, 23, 33, 2],
...]
我需要按年和日分组,以获得类似的信息:
[[2014, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)],
[2014, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)],
....
[2013, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)],
[2013, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)],,
....]
如何使用 itertool 执行此操作?我无法使用 pandas 或 numpy,因为我的系统不支持它。非常感谢您的帮助。
import itertools
import operator
key = operator.itemgetter(0,1)
my_list.sort(key=key)
for (year, day), records in itertools.groupby(my_list, key):
print("Records on", year, day, ":")
for record in records: print(record)
itertools.groupby
不像 SQL 的 GROUPBY
那样工作。它按顺序分组。这意味着如果你有一个未排序的元素列表,你可能会在同一个键上得到多个组。因此,假设您想根据奇偶校验(偶数与奇数)对整数列表进行分组,那么您可以这样做:
L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list
itertools.groupby(L, lambda i:i%2)
现在,如果您来自 SQL 世界,您可能会认为这为您提供了两组 - 一组用于偶数,一组用于奇数。虽然这是有道理的,但这不是 Python 做事的方式。它依次考虑每个元素并检查它是否与前一个元素属于同一组。如果是,则将两个元素都添加到组中;否则,每个元素都有自己的组。
所以根据上面的列表,我们得到:
key: 1
elements: [1]
key: 0
elements[2]
key: 1
elements: [3]
key: 0
elements[4]
key: 1
elements: [5,7] # see what happened here?
因此,如果您希望像 SQL 那样进行分组,那么您需要事先根据要分组的键(标准)对列表进行排序:
L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list
L.sort(key=lambda i:i%2) # now L looks like this: [2,4,1,3,5,7] - the odds and the evens stick together
itertools.groupby(L, lambda i:%2) # this gives two groups containing all the elements that belong to each group
我试图做出一个简短的回答,但我没有成功,但我设法得到了很多 python 涉及的内置模块:
import itertools
import operator
import functools
我将使用 functools.reduce
进行求和,但它需要一个自定义函数:
def sum_sum_sum_counter(res, array):
# Unpack the values of the array
year, day, val1, val2, val3 = array
res[0] += val1
res[1] += val2
res[2] += val3
res[3] += 1 # counter
return res
此函数有一个计数器,因为您想计算平均值,它比 运行 平均值实现更直观。
现在是有趣的部分:我将按前两个元素分组(假设这些元素已排序,否则需要像 lst = sorted(lst, key=operator.itemgetter(0,1))
之前的内容:
result = []
for i, values in itertools.groupby(lst, operator.itemgetter(0,1)):
# Now let's use the reduce function with a start list containing zeros
calc = functools.reduce(sum_sum_sum_counter, values, [0, 0, 0, 0])
# Append year, day and the results.
result.append([i[0], i[1], calc[0], calc[1], calc[2]/calc[3]])
calc[2]/calc[3]
是value3的平均值。请记住 reduce
函数中的最后一个元素是一个计数器!总和除以计数就是平均值。
给我一个结果:
[[2014, 1, 13, 27, 17.0],
[2014, 2, 47, 44, 5.5],
[2013, 1, 34, 54, 3.0],
[2013, 2, 23, 33, 2.0]]
只需使用您提供的那些值。
在真实数据上,分组前排序可能会变得低效:
- 首先,完整的迭代器将被消耗,丢失
函数式编程的一个重要目标,惰性
- 与分组相比,排序的复杂度为 O(n log n)
通过一些谓词分组 SQL + pythonic 方式,一些简单
reduce/accumulate 使用 collection.defaultdict 可以:
from functools import reduce
from collections import defaultdict as DD
def groupby( pred, it ):
return reduce( lambda d,x: d[ pred(x) ].append(x) or d, it, DD(list) )
然后将其与某些谓词函数或 lambda 一起使用:
>>> words = 'your code might become less readable using reduce'.split()
>>> groupby( len, words )[4]
['your', 'code', 'less']
关于惰性,reduce 不会 return 在消耗所有输入之前,
当然也不是。您可以使用 itertools.accumulate,而不是,
始终 return 使用相同的 defaultdict,以懒惰地使用(并处理不断变化的组)并占用很少的内存。
我有一个这样的列表: #[年,日,VALUE1,VALUE2,VALUE3]
[[2014, 1, 10, 20, 30],
[2014, 1, 3, 7, 4],
[2014, 2, 14, 43,5],
[2014, 2, 33, 1, 6]
...
[2013, 1, 34, 54, 3],
[2013, 2, 23, 33, 2],
...]
我需要按年和日分组,以获得类似的信息:
[[2014, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)],
[2014, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)],
....
[2013, 1, sum[all values1 with day=1), sum(all values2 with day =1), avg(all values3 with day=1)],
[2013, 2, sum[all values1 with day=2), sum(all values2 with day =2), avg(all values3 with day=2)],,
....]
如何使用 itertool 执行此操作?我无法使用 pandas 或 numpy,因为我的系统不支持它。非常感谢您的帮助。
import itertools
import operator
key = operator.itemgetter(0,1)
my_list.sort(key=key)
for (year, day), records in itertools.groupby(my_list, key):
print("Records on", year, day, ":")
for record in records: print(record)
itertools.groupby
不像 SQL 的 GROUPBY
那样工作。它按顺序分组。这意味着如果你有一个未排序的元素列表,你可能会在同一个键上得到多个组。因此,假设您想根据奇偶校验(偶数与奇数)对整数列表进行分组,那么您可以这样做:
L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list
itertools.groupby(L, lambda i:i%2)
现在,如果您来自 SQL 世界,您可能会认为这为您提供了两组 - 一组用于偶数,一组用于奇数。虽然这是有道理的,但这不是 Python 做事的方式。它依次考虑每个元素并检查它是否与前一个元素属于同一组。如果是,则将两个元素都添加到组中;否则,每个元素都有自己的组。
所以根据上面的列表,我们得到:
key: 1
elements: [1]
key: 0
elements[2]
key: 1
elements: [3]
key: 0
elements[4]
key: 1
elements: [5,7] # see what happened here?
因此,如果您希望像 SQL 那样进行分组,那么您需要事先根据要分组的键(标准)对列表进行排序:
L = [1,2,3,4,5,7,8] # notice that there's no 6 in the list
L.sort(key=lambda i:i%2) # now L looks like this: [2,4,1,3,5,7] - the odds and the evens stick together
itertools.groupby(L, lambda i:%2) # this gives two groups containing all the elements that belong to each group
我试图做出一个简短的回答,但我没有成功,但我设法得到了很多 python 涉及的内置模块:
import itertools
import operator
import functools
我将使用 functools.reduce
进行求和,但它需要一个自定义函数:
def sum_sum_sum_counter(res, array):
# Unpack the values of the array
year, day, val1, val2, val3 = array
res[0] += val1
res[1] += val2
res[2] += val3
res[3] += 1 # counter
return res
此函数有一个计数器,因为您想计算平均值,它比 运行 平均值实现更直观。
现在是有趣的部分:我将按前两个元素分组(假设这些元素已排序,否则需要像 lst = sorted(lst, key=operator.itemgetter(0,1))
之前的内容:
result = []
for i, values in itertools.groupby(lst, operator.itemgetter(0,1)):
# Now let's use the reduce function with a start list containing zeros
calc = functools.reduce(sum_sum_sum_counter, values, [0, 0, 0, 0])
# Append year, day and the results.
result.append([i[0], i[1], calc[0], calc[1], calc[2]/calc[3]])
calc[2]/calc[3]
是value3的平均值。请记住 reduce
函数中的最后一个元素是一个计数器!总和除以计数就是平均值。
给我一个结果:
[[2014, 1, 13, 27, 17.0],
[2014, 2, 47, 44, 5.5],
[2013, 1, 34, 54, 3.0],
[2013, 2, 23, 33, 2.0]]
只需使用您提供的那些值。
在真实数据上,分组前排序可能会变得低效:
- 首先,完整的迭代器将被消耗,丢失 函数式编程的一个重要目标,惰性
- 与分组相比,排序的复杂度为 O(n log n)
通过一些谓词分组 SQL + pythonic 方式,一些简单 reduce/accumulate 使用 collection.defaultdict 可以:
from functools import reduce
from collections import defaultdict as DD
def groupby( pred, it ):
return reduce( lambda d,x: d[ pred(x) ].append(x) or d, it, DD(list) )
然后将其与某些谓词函数或 lambda 一起使用:
>>> words = 'your code might become less readable using reduce'.split()
>>> groupby( len, words )[4]
['your', 'code', 'less']
关于惰性,reduce 不会 return 在消耗所有输入之前, 当然也不是。您可以使用 itertools.accumulate,而不是, 始终 return 使用相同的 defaultdict,以懒惰地使用(并处理不断变化的组)并占用很少的内存。