使用NumPy ndarray计算平均值

8
文本文件如下所示:
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和Mark的体重和身高平均值,具体步骤如下:
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函数呢?
4个回答

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

更适合您需求的是将数据拆分成分层结构,我倾向于使用字典。 类似以下:

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 - 2964502
1
@nils NumPy不会让这段代码更短。即使在您的示例中,您的代码仍然在解析文件。而我的代码只是将文件解析为一个更有用的数据结构,该数据结构可以应用NumPy函数。你想要NumPy来计算平均值,但因为你想能够按条件进行计算,所以需要将数据转换为更易于操作的形式。Pandas可能是一个很好的库来为您完成这项工作,但我个人不认为9行代码太长了。 - bheklilr

4

我会将这篇文章设为社区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

然后按照名称属性进行分组,获取列,并计算平均值:

>>> 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找到适当的索引:

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

并对这些索引执行平均值操作:

np.mean(data.value[indices])

最好能够在您的代码中解释 * 的含义 @Nicolas Barbey - 2964502
出现了 TypeError: startswith 的第一个参数必须是字节或字节元组,而不是 numpy.str_。如何进行更正?@Nicolas Barbey - 2964502
2
  • 只是布尔数组的乘法运算。
- Nicolas Barbey
我不理解这个TypeError错误。我在Python 2.7.3上测试了。你用的是什么版本的Python? - Nicolas Barbey
我正在使用Python 3.2和NumPy 1.8 @Nicolas Barbey。 - 2964502
Python 3和NumPy 1.8中产生的类型错误已经被@DSM在https://dev59.com/SnnZa4cB1Zd3GeqPlRLt下解决。 - 2964502

1
如果您的数据始终以提供的格式存在。那么您可以使用数组切片来完成此操作:
(data[:-1:2] + data[1::2]) / 2

结果为:

[  55.   155.    87.5  165. ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接