【问题标题】:calculate mean using numpy ndarray使用 numpy ndarray 计算平均值
【发布时间】:2013-11-24 22:02:52
【问题描述】:

文本文件如下所示:

david weight_2005 50
david weight_2012 60
david height_2005 150
david height_2012 160
mark weight_2005 90
mark weight_2012 85
mark height_2005 160
mark height_2012 170

如何计算大卫的体重和身高的平均值并标记如下:

david>> mean(weight_2005 and weight_2012), mean (height_2005 and height_2012)
mark>> mean(weight_2005 and weight_2012), mean (height_2005 and height_2012)

我的不完整代码是:

 import numpy as np
 import csv
 with open ('data.txt','r') as infile:
   contents = csv.reader(infile, delimiter=' ')
   c1,c2,c3 = zip(*contents)
   data = np.array(c3,dtype=float)

那如何申请np.mean??

【问题讨论】:

    标签: python python-2.7 python-3.x numpy


    【解决方案1】:

    我会制作这个社区 wiki,因为它更像是“我认为你应该这样做”而不是“这是你所提问题的答案”。对于这样的事情,我可能会使用pandas 而不是numpy,因为它的分组工具要好得多。与基于numpy 的方法进行比较也很有用。

    import pandas as pd
    df = pd.read_csv("data.txt", sep="[ _]", header=None, 
                     names=["name", "property", "year", "value"])
    means = df.groupby(["name", "property"])["value"].mean()
    

    .. 嗯,就是这样。


    首先,将数据读入DataFrame,让空格或_ 分隔列:

    >>> import pandas as pd
    >>> df = pd.read_csv("data.txt", sep="[ _]", header=None, 
                     names=["name", "property", "year", "value"])
    >>> df
        name property  year  value
    0  david   weight  2005     50
    1  david   weight  2012     60
    2  david   height  2005    150
    3  david   height  2012    160
    4   mark   weight  2005     90
    5   mark   weight  2012     85
    6   mark   height  2005    160
    7   mark   height  2012    170
    

    然后按nameproperty 分组,取value 列,然后计算平均值:

    >>> means = df.groupby(["name", "property"])["value"].mean()
    >>> means
    name   property
    david  height      155.0
           weight       55.0
    mark   height      165.0
           weight       87.5
    Name: value, dtype: float64
    

    .. 好吧,sep="[ _]" 技巧对于真正的代码来说有点太可爱了,尽管它在这里工作得很好。在实践中,我会使用空格分隔符,在第二列中读取为property_year,然后执行

    df["property"], df["year"] = zip(*df["property_year"].str.split("_"))
    del df["property_year"]
    

    允许在其他列中使用下划线。

    【讨论】:

      【解决方案2】:

      您可以直接在 numpy 数组中读取数据:

      data = np.recfromcsv("data.txt", delimiter=" ", names=['name', 'type', 'value'])

      然后您可以使用 np.where 找到合适的索引:

      指数 = np.where((data.name == 'david') * data.type.startswith('height'))

      并对那些指数进行平均:

      np.mean(data.value[indices])

      【讨论】:

      • 如果你能在你的代码中解释 * 的含义会更好@Nicolas Barbey
      • 有一个TypeError:startswith first arg 必须是字节或字节元组,而不是numpy.str_。如何纠正它?@Nicolas Barbey
      • * 只是布尔数组的乘法。
      • 我不明白 TypeError。我在 python 2.7.3 上进行了测试。你的 python 版本是什么?
      • 我正在使用 python 3.2 和 numpy 1.8 @Nicolas Barbey
      【解决方案3】:

      如果您的数据始终采用提供的格式。然后你可以使用数组切片来做到这一点:

      (data[:-1:2] + data[1::2]) / 2
      

      结果:

      [  55.   155.    87.5  165. ]
      

      【讨论】:

        【解决方案4】:

        mean 函数用于计算数字数组的平均值。您需要想出一种方法来选择c3 的值,方法是对c2 应用条件。

        可能更适合您需求的方法是将数据拆分为层次结构,我更喜欢使用字典。类似的东西

        data = {}
        with open('data.txt') as f:
            contents = csv.reader(f, delimiter=' ')
        for (name, attribute, value) in contents:
            data[name] = data.get(name, {})  # Default value is a new dict
            attr_name, attr_year = attribute.split('_')
            attr_year = int(attr_year)
            data[name][attr_name] = data[name].get(attr_name, {})
            data[name][attr_name][attr_year] = value
        

        现在data 看起来像

        {
            "david": {
                "weight": {
                    2005: 50,
                    2012: 60
                },
                "height": {
                    2005: 150,
                    2012: 160
                }
            },
            "mark": {
                "weight": {
                    2005, 90,
                    2012, 85
                },
                "height": {
                    2005: 160,
                    2012: 170
                }
            }
        }
        

        那你能做的是

        david_avg_weight = np.mean(data['david']['weight'].values())
        mark_avg_height = np.mean([v for k, v in data['mark']['height'].iteritems() if 2008 < k])
        

        这里我仍然使用np.mean,但只在普通的 Python 列表中调用它。

        【讨论】:

        • 感谢您的努力,点赞!但我正在寻找更短的方法来主要使用 numpy @bheklilr
        • @nils NumPy 不会让这段代码变得更短。即使在您的示例中,您的代码也都在解析文件。我的只是将文件解析为更有用的数据结构,然后可以对其应用 NumPy 函数。您只需要 NumPy 计算平均值,但是因为您希望能够按条件完成,所以您需要将数据转换为更易于操作的形式。 Pandas 可能是为您执行此操作的一个很好的库,但我个人不明白为什么 9 行代码太长。
        猜你喜欢
        • 1970-01-01
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        • 2014-11-04
        • 2011-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多