Есть ли какой-нибудь питонический способ найти среднее значение определенных элементов кортежа в массиве?

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

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

print(np.mean(array,key=lambda x:x[1])) TypeError: mean() got an unexpected keyword argument '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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
23
0
4 029
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

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))

Поскольку это Python 3, просто используйте statistics.mean.

Peter Wood 25.04.2019 13:09

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

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

С чистым 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()
Ответ принят как подходящий

Если вы используете 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)

Я понял, что есть лучшие способы сделать код Python 2. sum принимает аргумент для начального значения. Если вы передадите 0.0 ему, то числитель всегда будет с плавающей запятой, не о чем беспокоиться. Кроме того, в модуле math есть функция fsum.

Peter Wood 25.04.2019 10:00

Я бы сказал, что способ приведения float немного более понятен, чем передача странного аргумента значения 0.0 для sum.

ruohola 25.04.2019 10:55

@ruohola Я думаю, что использование fsum, вероятно, лучше всего подходит для Python 2.

Peter Wood 25.04.2019 11:09

Не можешь from __future__ import division?

DanielSank 25.04.2019 22:55

@DanielSank да, это еще один вариант. Еще одно преимущество использования fsum, если вы суммируете числа с плавающей запятой, заключается в том, что он отслеживает частичные суммы, что компенсирует отсутствие точности в представлении с плавающей запятой. Итак, если мы продолжим использовать fsum, нам вообще не нужно думать о целочисленном делении, и, как правило, это лучшее решение. См. мой ответ о Суммирование Кахана в С++.

Peter Wood 25.04.2019 23:41

Я не понимаю: «Однако это также означает, что мы должны сделать цикл по значениям в массиве в выражение понимания» ... вы имеете в виду добавление явных круглых скобок, которые преобразуют выражение в genexp? Поскольку все предыдущие варианты вашего решения используют genexps, только без явных скобок, потому что это не нужно, если у функции нет других аргументов.

cs95 26.04.2019 06:46

@ cs95 да, я это и имел в виду. Я попытался улучшить ответ, спасибо.

Peter Wood 26.04.2019 08:43

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

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

вы можете использовать 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)

первый выдает эту ошибку: объект 'int' не вызывается

Şevval Kahraman 25.04.2019 09:46

@ŞevvalKahraman, если массив определен, как показано в вашем вопросе, первый дает 8.0 (проверено и проверено на той же версии). Таким образом, либо используемый вами массив имеет другое значение, либо вы сделали опечатку.

LinkBerest 25.04.2019 14:06
x[1] уже является целым числом, зачем вам вызывать int()?
Barmar 25.04.2019 18:53

Использование лямбды на 30% медленнее, чем понимание генератора. Но если вы предпочитаете map, я рекомендую использовать operator.itemgetter(1) вместо лямбда.

Mateen Ulhaq 26.04.2019 00:52

Точно так же functools.reduce на 72% медленнее, чем понимание генератора и sum.

Mateen Ulhaq 26.04.2019 00:54

Если вы хотите использовать 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, это не имеет значения.

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

sum(zip(*array)[1])/len(array)

Другие вопросы по теме