具有不同数据类型的Python切片/子集数组

时间:2016-07-09 18:52:09

标签: python arrays numpy slice

作为模拟的结果,我有一堆csv文件除以空格。见下面的例子:

Time  Node  Type  Metric 1  Metric 2
0.00   1    Abcd  1234.5678 9012.3456
0.00   1    Efgh  1234.5678 9012.3456
0.01   2    Abcd  1234.5678 9012.3456
0.01   2    Efgh  1234.5678 9012.3456
0.02   3    Abcd  1234.5678 9012.3456
0.02   3    Efgh  1234.5678 9012.3456
0.03   1    Abcd  1234.5678 9012.3456
0.03   1    Efgh  1234.5678 9012.3456
0.04   2    Abcd  1234.5678 9012.3456
0.04   2    Efgh  1234.5678 9012.3456
...

要使用我需要的指标按节点数和类型过滤文件,即节点1的平均值,键入Abcd;节点1的平均值,类型为Efgh;等

我知道Numpy对处理数组非常有用,但它只接受一种数据类型。我当前的代码看起来像这样(现在只打印文件的内容):

import sys

filename = sys.argv[1]
# read file
with open(filename, 'r') as f:
    for line in f:
       print line

# TO DO
# Slice file into different 'Node' number

# Slice subfile into different 'Type'

# Calculate metrics (mean, max, min, and others)
# which is fine once I have the sliced arrays

# Plot graphs

有人知道如何以有效的方式做到这一点吗?

PS:我使用的是Python 2.7。

由于

3 个答案:

答案 0 :(得分:2)

您可能希望使用pandas而不是numpy。假设你有一个制表符分隔的文件,代码就像这样简单:

import pandas as pd
data = pd.read_csv("abc.csv", delimiter="\t")
result = data.groupby("Node").mean()

并得出以下结果:

Time    Metric 1    Metric 2
Node            
1   0.015   1234.5678   9012.3456
2   0.025   1234.5678   9012.3456
3   0.020   1234.5678   9012.3456

答案 1 :(得分:1)

如果我将您的样本放入文件中,我可以将其加载到带有

的结构化numpy数组中
In [45]: names=['Time','Node','Type','Metric_1','Metric_2']
In [46]: data = np.genfromtxt('stack38285208.txt', dtype=None, names=names, skip_header=1)
In [47]: data
Out[47]: 
array([(0.0, 1, b'Abcd', 1234.5678, 9012.3456),
       (0.0, 1, b'Efgh', 1234.5678, 9012.3456),
       (0.01, 2, b'Abcd', 1234.5678, 9012.3456),
       (0.01, 2, b'Efgh', 1234.5678, 9012.3456),
       (0.02, 3, b'Abcd', 1234.5678, 9012.3456),
       (0.02, 3, b'Efgh', 1234.5678, 9012.3456),
       (0.03, 1, b'Abcd', 1234.5678, 9012.3456),
       (0.03, 1, b'Efgh', 1234.5678, 9012.3456),
       (0.04, 2, b'Abcd', 1234.5678, 9012.3456),
       (0.04, 2, b'Efgh', 1234.5678, 9012.3456)], 
      dtype=[('Time', '<f8'), ('Node', '<i4'), ('Type', 'S4'), ('Metric_1', '<f8'), ('Metric_2', '<f8')])

我无法使用names=True因为您有Metric 1之类的名称,它会将其解释为2列名称。因此,单独的names列表和skip_header。我正在使用Python3,因此S4格式的字符串显示为b'Efgh'

我可以按字段名称访问字段(列),并对其进行各种过滤和数学运算。例如:

Typeb'Abcd'的字段:

In [63]: data['Type']==b'Abcd'
Out[63]: array([ True, False,  True, False,  True, False,  True, False,  True, False], dtype=bool)

Node为1:

In [64]: data['Node']==1
Out[64]: array([ True,  True, False, False, False, False,  True,  True, False, False], dtype=bool)

和在一起:

In [65]: (data['Node']==1)&(data['Type']==b'Abcd')
Out[65]: array([ True, False, False, False, False, False,  True, False, False, False], dtype=bool)
In [66]: ind=(data['Node']==1)&(data['Type']==b'Abcd')
In [67]: data[ind]
Out[67]: 
array([(0.0, 1, b'Abcd', 1234.5678, 9012.3456),
       (0.03, 1, b'Abcd', 1234.5678, 9012.3456)], 
      dtype=[('Time', '<f8'), ('Node', '<i4'), ('Type', 'S4'), ('Metric_1', '<f8'), ('Metric_2', '<f8')])

我可以从这个记录子集中获取任何数字字段的mean

In [68]: data[ind]['Metric_1'].mean()
Out[68]: 1234.5678
In [69]: data[ind]['Metric_2'].mean()
Out[69]: 9012.3456000000006

我还可以将这些字段分配给变量并直接使用这些字段

In [70]: nodes=data['Node']
In [71]: types=data['Type']
In [72]: nodes
Out[72]: array([1, 1, 2, 2, 3, 3, 1, 1, 2, 2])
In [73]: types
Out[73]: 
array([b'Abcd', b'Efgh', b'Abcd', b'Efgh', b'Abcd', b'Efgh', b'Abcd',
       b'Efgh', b'Abcd', b'Efgh'], 
      dtype='|S4')

2个浮点字段,显示为2列数组:

In [78]: metrics = data[['Metric_1','Metric_2']].view(('float',(2)))
In [79]: metrics
Out[79]: 
array([[ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456]])

metrics其中nodes为1

In [83]: metrics[nodes==1,:]
Out[83]: 
array([[ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456],
       [ 1234.5678,  9012.3456]])
In [84]: metrics[nodes==1,:].mean(axis=0)    # column mean
Out[84]: array([ 1234.5678,  9012.3456])

numpy没有整洁的groupby功能,但Pandas和itertools会这样做。

答案 2 :(得分:0)

我尝试使用itertools。基本上,这利用了groupby方法,该方法允许您通过lambda函数将连续的数据分组在一起。如果在使用groupby之前对数据集进行排序,则可以基本上按任意键对数据集进行分组。

不确定您的数据集有多大,但如果它不是太大,这应该可以解决问题。

from itertools import groupby
import sys

filename = sys.argv[1]

def parse_data(line):
    # converts a single entry in the csv to a list of values
    return [
            val for val in line.split(' ') if val != ''
    ]


with open(filename, 'r') as input:
    keys = input.readline().split()

    dataset = [
       parse_data(line)
       for line in input.readlines()
    ]

    # group dataset by node
    dataset_grouped_by_node = groupby(
        sorted(dataset, key=lambda x: x[1]), lambda x: x[1]
    )

    for node, node_group in dataset_grouped_by_node:
        # group each of those subgroups by type
        group_sorted_by_type = groupby(
            sorted(node_group, key=lambda x: x[2]), lambda x: x[2]
        )

        for type, type_group in group_sorted_by_type:
            print type, node

            for item in type_group:
                print item

                # calculate statistics on these subgroups

如果你愿意的话,你可以将它清理一下以制作一个通用的“分组”功能,但我认为这应该可以满足你的需要。