Есть ли какой-нибудь pythonic способ найти среднее значение определенных элементов кортежа в массиве? - PullRequest
23 голосов
/ 25 апреля 2019

Я хочу написать этот код как pythonic. Мой настоящий массив намного больше, чем этот пример.

(5 + 10 + 20 + 3 + 2) / 5

print (np.mean (массив, ключ = лямбда x: x [1])) TypeError: mean () получил неожиданный аргумент ключевого слова 'key'

array = [('a', 5) , ('b', 10), ('c', 20), ('d', 3), ('e', 2)]

sum = 0
for i in range(len(array)):
    sum = sum + array[i][1]

average = sum / len(array)
print(average)

import numpy as np
print(np.mean(array,key=lambda x:x[1]))

Как этого избежать? Я хочу использовать второй пример.

Я использую Python 3.7

Ответы [ 9 ]

26 голосов
/ 25 апреля 2019

Если вы используете Python 3.4 или выше, вы можете использовать модуль statistics:

from statistics import mean

average = mean(value[1] for value in array)

Или если вы используете версиюPython старше 3.4:

average = sum(value[1] for value in array) / len(array)

Оба этих решения используют приятную особенность Python, называемую выражением генератора.Цикл

value[1] for value in array

создает новую последовательность своевременно и эффективно использует память.См. PEP 289 - Выражения генератора .

Если вы используете Python 2 и суммируете целые числа, у нас будет целочисленное деление, которое будет усекать результат, например:

>>> 25 / 4
6

>>> 25 / float(4)
6.25

Чтобы гарантировать, что у нас нет целочисленного деления, мы можем установить начальное значение sum равным float значению 0.0.Однако это также означает, что мы должны сделать выражение генератора явным образом с круглыми скобками, в противном случае это синтаксическая ошибка, и она менее привлекательна, как отмечено в комментариях:

average = sum((value[1] for value in array), 0.0) / len(array)

Вероятно, лучше использовать fsum из math модуля, который вернет float:

from math import fsum

average = fsum(value[1] for value in array) / len(array)
3 голосов
/ 25 апреля 2019

Если вы хотите использовать numpy, приведите его к numpy.array и выберите нужную ось, используя numpy индексирование:

import numpy as np

array = np.array([('a', 5) , ('b', 10), ('c', 20), ('d', 3), ('e', 2)])
print(array[:,1].astype(float).mean())
# 8.0

Приведение к числовому типу необходимо, потому чтоисходный массив содержит как строки, так и числа и поэтому имеет тип object.В этом случае вы можете использовать float или int, это не имеет значения.

2 голосов
/ 26 апреля 2019

Если вы открыты для более похожих на гольф решений, вы можете перенести свой массив с помощью vanilla python, получить список только чисел и рассчитать среднее с помощью

sum(zip(*array)[1])/len(array)
2 голосов
/ 25 апреля 2019

вы можете использовать map вместо понимания списка

sum(map(lambda x:int(x[1]), array)) / len(array)

или functools.reduce (если вы используете Python2.X просто reduce, а не functools.reduce)

import functools
functools.reduce(lambda acc, y: acc + y[1], array, 0) / len(array)
2 голосов
/ 25 апреля 2019

С чистым Python:

from operator import itemgetter

acc = 0
count = 0

for value in map(itemgetter(1), array):
    acc += value
    count += 1

mean = acc / count

Итеративный подход может быть предпочтительнее, если ваши данные не могут поместиться в памяти как list (так как вы сказали, что это большой).Если это возможно, предпочтите декларативный подход:

data = [sub[1] for sub in array]
mean = sum(data) / len(data)

Если вы открыты для использования numpy, я найду этот очиститель:

a = np.array(array)

mean = a[:, 1].astype(int).mean()
2 голосов
/ 25 апреля 2019

Вы можете просто использовать:

print(sum(tup[1] for tup in array) / len(array))

Или для Python 2:

print(sum(tup[1] for tup in array) / float(len(array)))

Или немного более кратко для Python 2:

from math import fsum

print(fsum(tup[1] for tup in array) / len(array))
0 голосов
/ 26 апреля 2019

Проблема здесь в том, что вы не можете напрямую вычислить среднее значение списка кортежей как ndarray, потому что все значения будут преобразованы в str.

Однако, в противном случае можно определить структурированный массив из списка кортежей, чтобы вы могли связать разные типы данных с каждым элементом в кортежах.

Таким образом, вы можете определить структурированный массив из списка кортежей с помощью:

l = [('a', 5) , ('b', 10), ('c', 20), ('d', 3), ('e', 2)]
a = np.array(l, dtype=([('str', '<U1'), ('num', '<i4')]))

А затем просто возьмите np.mean числового поля, то есть второй элемент в кортежах:

np.mean(a['num'])
# 8.0
0 голосов
/ 25 апреля 2019

Просто найдите среднее значение, используя сумму и количество элементов списка.

array = [('a', 5) , ('b', 10), ('c', 20), ('d', 3), ('e', 2)]
avg = float(sum(value[1] for value in array)) / float(len(array))
print(avg)
#8.0
0 голосов
/ 25 апреля 2019

Вы можете использовать map:

np.mean(list(map(lambda x: x[1], array)))

...