Python slice/subset 不同数据类型的数组
Python slice/subset array with different data type
作为模拟的结果,我有一堆用空格分隔的 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.
谢谢
您可能想使用 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
我尝试使用 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
如果你愿意,你可以稍微清理一下以制作一个通用的 "grouping" 函数,但我认为这应该能满足你的需要。
如果我把你的样本放在一个文件中,我可以将它加载到一个结构化的 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'
.
我可以按字段名访问字段(列),并用它们进行各种过滤和数学运算。例如:
字段,其中 Type
是 b'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
有。
作为模拟的结果,我有一堆用空格分隔的 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.
谢谢
您可能想使用 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
我尝试使用 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
如果你愿意,你可以稍微清理一下以制作一个通用的 "grouping" 函数,但我认为这应该能满足你的需要。
如果我把你的样本放在一个文件中,我可以将它加载到一个结构化的 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'
.
我可以按字段名访问字段(列),并用它们进行各种过滤和数学运算。例如:
字段,其中 Type
是 b'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
有。