【问题标题】:Using NumPy to Find Median of Second Element of List of Tuples使用 NumPy 查找元组列表的第二个元素的中位数
【发布时间】:2015-08-05 15:26:08
【问题描述】:

假设我有一个元组列表,如下所示:

list = [(a,1), (b,3), (c,5)]

我的目标是使用元组的第二个元素获取元组列表中位数的第一个元素。在上述情况下,我希望输出 b,因为中位数为 3。我尝试使用 NumPy 和以下代码,但无济于事:

import numpy as np

list = [('a',1), ('b',3), ('c',5)]
np.median(list, key=lambda x:x[1])

【问题讨论】:

  • 附带说明,我强烈建议您不要将变量命名为 list,因为这会影响 Python 的内置 list 类型
  • @Cleb:对不起!我实际上最终使用了你的方法,它就像一个魅力。谢谢!

标签: python numpy tuples


【解决方案1】:

你可以这样计算中位数:

np.median(dict(list).values()) 
# in Python 2.7; in Python 3.x it would be `np.median(list(dict(list_of_tuples).values()))`

首先将您的列表转换为字典,然后计算其值的中位数。

当你想得到实际的密钥时,你可以这样做:

dl = dict(list) #{'a': 1, 'b': 3, 'c': 5}

dl.keys()[dl.values().index(np.median(dl.values()))]

这将打印'b'。假设中位数在列表中,如果不是,则将抛出 ValueError。因此,您可以使用@Anand S Kumar 的回答中的示例,像这样使用try/except

import numpy as np

l = [('a',1), ('b',3), ('c',5), ('d',22),('e',11),('f',3)]

# l = [('a',1), ('b',3), ('c',5)]

dl = dict(l)
try:
    print(dl.keys()[dl.values().index(np.median(dl.values()))])
except ValueError:
    print('The median is not in this list. Its value is ',np.median(dl.values()))
    print('The closest key is ', dl.keys()[min(dl.values(), key=lambda x:abs(x-np.median(dl.values())))])

您将获得第一个列表:

中位数不在此列表中。其值为 4.0

最近的键是f

对于您的示例,它只打印:

b

【讨论】:

  • 对于 Python 3.x ,您必须使用 - np.median(list(dict(list_of_tuples).values()))
【解决方案2】:

np.median 不接受任何名为 key 的参数。相反,您可以使用列表推导,仅从内部列表中获取第二个元素。示例 -

In [3]: l = [('a',1), ('b',3), ('c',5)]

In [4]: np.median([x[1] for x in l])
Out[4]: 3.0

In [5]: l = [('a',1), ('b',3), ('c',5), ('d',22),('e',11),('f',3)]

In [6]: np.median([x[1] for x in l])
Out[6]: 4.0

另外,如果不是出于示例目的,请不要使用list 作为变量名,它会隐藏内置函数list

【讨论】:

  • 感谢您的快速回复!不幸的是,我想要的输出是第二个元素的中位数的第一个元素。
  • 如果列表中没有中位数怎么办?就像我给出的第二个例子一样。
  • 这正是我遇到的问题。对我来说困难的部分是提取元组的第一个元素,其第二个元素具有中值。
  • 这似乎是一个糟糕的设计,如果最近有多个元素怎么办?在上面的例子中,有 2 个元素的值为 3 ,一个元素的值为 5 。每个都与中位数相差1(并且是最接近的)。
  • 你能解释一下你到底想解决什么问题吗?
【解决方案3】:

np.median 不接受某种“关键”参数,并且不返回它找到的索引。此外,当项目数为偶数时(沿轴),它返回 2 个中心项目的平均值。

但是median 用于查找中心项目的np.partition 确实采用结构化数组字段名称。因此,如果我们将元组列表转换为结构化数组,我们可以轻松选择中间项。

名单:

In [1001]: ll
Out[1001]: [('a', 1), ('b', 3), ('c', 5)]

作为结构化数组:

In [1002]: la1 = np.array(ll,dtype='a1,i')
In [1003]: la1
Out[1003]: 
array([(b'a', 1), (b'b', 3), (b'c', 5)], 
     dtype=[('f0', 'S1'), ('f1', '<i4')])

我们可以通过:

In [1115]: np.partition(la1, (1), order='f1')[[1]]
Out[1115]: 
array([(b'b', 3)], 
      dtype=[('f0', 'S1'), ('f1', '<i4')])

并允许偶数个项目(代码抄自np.median):

def mymedian1(arr, field):
    # return the middle items of arr, selected by field
    sz = arr.shape[0]  # 1d for now
    if sz % 2 == 0:
        ind = ((sz // 2)-1, sz // 2)
    else:
        ind = ((sz - 1) // 2,)
    return np.partition(arr, ind, order=field)[list(ind)]

对于 3 项数组:

In [1123]: mymedian1(la1,'f1')
Out[1123]: 
array([(b'b', 3)], 
      dtype=[('f0', 'S1'), ('f1', '<i4')])

对于 6 项数组:

In [1124]: la2
Out[1124]: 
array([(b'a', 1), (b'b', 3), (b'c', 5), (b'd', 22), (b'e', 11), (b'f', 3)], 
      dtype=[('f0', 'S1'), ('f1', '<i4')])

In [1125]: mymedian1(la2,'f1')
Out[1125]: 
array([(b'f', 3), (b'c', 5)], 
      dtype=[('f0', 'S1'), ('f1', '<i4')])

使用np.argpartition查看我的早期版本的编辑历史记录。


它甚至适用于第一个字段(字符):

In [1132]: mymedian1(la2,'f0')
Out[1132]: 
array([(b'c', 5), (b'd', 22)], 
      dtype=[('f0', 'S1'), ('f1', '<i4')])

【讨论】:

  • 有趣的想法。那么 AnandSKuma 显示的第二个示例将返回什么,即在实际中位数不在列表中的情况下?
  • np.median,在偶数长度列表的情况下,返回两个中间值的mean。因此,当 2 个值为 3,5 时,4.0 的值。那么在这种情况下,所需的median 是什么。
  • argpartition 路由可以返回 2 个中间元组,而不是尝试对它们进行平均。
  • 如果有 3 和 5,所需的中位数仍然是 4。但由于 4 不在列表中,因此无法返回相应的字母。返回两个中间元组将是一个选项(如果我正确理解上面的 cmets,Wally 似乎也会考虑这个选项)但这将需要再次检查中位数是否在列表中。但是 Wally 需要澄清这一点……顺便说一句:很高兴看到 np.argpartition 在工作;以前没见过。
  • 是的,我确实喜欢返回两个中间元组的选项。
猜你喜欢
  • 2015-01-08
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
相关资源
最近更新 更多