npy 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +20 -1
- data/lib/npy.rb +93 -38
- data/lib/npy/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e81a0b6a617c8f05e1e62f88c05996891328ef154cd4c60d49d233b41b99748
|
4
|
+
data.tar.gz: 4f8c8cc599e2bae978b1cc6dabcadb2dd6aab1dec96c1f5f3e07a8a4303f1a24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82babeb75230ec73cb0870b42716589bc2bf9a460ff9943606792b9fe3dfa941f5892c4de1ba7b719afe2fa0e3726b2f5ca5ca268224afe2273c5c66af881cba
|
7
|
+
data.tar.gz: 700466088d563a0a8f4ccebce9506d91675b41bc1f47525756637b49218c533bfeef5364f3dea5b71328d690589643947273db00b44b7af8f86a77acdaf59ce3
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# Npy
|
2
2
|
|
3
|
-
|
3
|
+
Save and load NumPy `npy` and `npz` files in Ruby - no Python required
|
4
4
|
|
5
5
|
:fire: Uses [Numo::NArray](https://github.com/ruby-numo/numo-narray) for blazing performance
|
6
6
|
|
7
|
+
[![Build Status](https://travis-ci.org/ankane/npy.svg?branch=master)](https://travis-ci.org/ankane/npy)
|
8
|
+
|
7
9
|
## Installation
|
8
10
|
|
9
11
|
Add this line to your application’s Gemfile:
|
@@ -18,6 +20,13 @@ gem 'npy'
|
|
18
20
|
|
19
21
|
`npy` files contain a single array
|
20
22
|
|
23
|
+
Save an array
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
arr = Numo::Int32[0...10]
|
27
|
+
Npy.save("x.npy", arr)
|
28
|
+
```
|
29
|
+
|
21
30
|
Load an `npy` file
|
22
31
|
|
23
32
|
```ruby
|
@@ -35,6 +44,14 @@ arr = Npy.load_string(byte_str)
|
|
35
44
|
|
36
45
|
`npz` files contain multiple arrays
|
37
46
|
|
47
|
+
Save multiple arrays
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
x = Numo::Int32[0...10]
|
51
|
+
y = x * 2
|
52
|
+
Npy.save_npz("mnist.npz", x: x, y: y)
|
53
|
+
```
|
54
|
+
|
38
55
|
Load an `npz` file
|
39
56
|
|
40
57
|
```ruby
|
@@ -58,6 +75,8 @@ Arrays are lazy loaded for performance
|
|
58
75
|
## Resources
|
59
76
|
|
60
77
|
- [npy format](https://docs.scipy.org/doc/numpy/reference/generated/numpy.lib.format.html#module-numpy.lib.format)
|
78
|
+
- [NumPy data types](https://docs.scipy.org/doc/numpy/user/basics.types.html)
|
79
|
+
- [Numo::NArray docs](https://ruby-numo.github.io/narray/narray/Numo/NArray.html)
|
61
80
|
|
62
81
|
## History
|
63
82
|
|
data/lib/npy.rb
CHANGED
@@ -11,6 +11,21 @@ module Npy
|
|
11
11
|
|
12
12
|
MAGIC_STR = "\x93NUMPY".b
|
13
13
|
|
14
|
+
TYPE_MAP = {
|
15
|
+
"|i1" => Numo::Int8,
|
16
|
+
"<i2" => Numo::Int16,
|
17
|
+
"<i4" => Numo::Int32,
|
18
|
+
"<i8" => Numo::Int64,
|
19
|
+
"|u1" => Numo::UInt8,
|
20
|
+
"<u2" => Numo::UInt16,
|
21
|
+
"<u4" => Numo::UInt32,
|
22
|
+
"<u8" => Numo::UInt64,
|
23
|
+
"<f4" => Numo::SFloat,
|
24
|
+
"<f8" => Numo::DFloat,
|
25
|
+
"<c8" => Numo::SComplex,
|
26
|
+
"<c16" => Numo::DComplex
|
27
|
+
}
|
28
|
+
|
14
29
|
class << self
|
15
30
|
def load(path)
|
16
31
|
with_file(path) do |f|
|
@@ -37,54 +52,90 @@ module Npy
|
|
37
52
|
magic = io.read(6)
|
38
53
|
raise Error, "Invalid npy format" unless magic&.b == MAGIC_STR
|
39
54
|
|
40
|
-
|
41
|
-
minor_version = io.read(1)
|
42
|
-
raise Error, "Unsupported version" unless major_version == "\x01".b
|
55
|
+
version = io.read(2)
|
43
56
|
|
44
|
-
header_len =
|
57
|
+
header_len =
|
58
|
+
case version
|
59
|
+
when "\x01\x00".b
|
60
|
+
io.read(2).unpack1("S<")
|
61
|
+
when "\x02\x00".b, "\x03\x00".b
|
62
|
+
io.read(4).unpack1("I<")
|
63
|
+
else
|
64
|
+
raise Error, "Unsupported version"
|
65
|
+
end
|
45
66
|
header = io.read(header_len)
|
46
67
|
descr, fortran_order, shape = parse_header(header)
|
47
68
|
raise Error, "Fortran order not supported" if fortran_order
|
48
69
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
Numo::Int8
|
53
|
-
when "<i2"
|
54
|
-
Numo::Int16
|
55
|
-
when "<i4"
|
56
|
-
Numo::Int32
|
57
|
-
when "<i8"
|
58
|
-
Numo::Int64
|
59
|
-
when "|u1"
|
60
|
-
Numo::UInt8
|
61
|
-
when "<u2"
|
62
|
-
Numo::UInt16
|
63
|
-
when "<u4"
|
64
|
-
Numo::UInt32
|
65
|
-
when "<u8"
|
66
|
-
Numo::UInt64
|
67
|
-
when "<f4"
|
68
|
-
Numo::SFloat
|
69
|
-
when "<f8"
|
70
|
-
Numo::DFloat
|
71
|
-
when "<c8"
|
72
|
-
Numo::SComplex
|
73
|
-
when "<c16"
|
74
|
-
Numo::DComplex
|
75
|
-
else
|
76
|
-
raise Error, "Type not supported: #{descr}"
|
77
|
-
end
|
70
|
+
# numo can't handle empty shapes
|
71
|
+
empty_shape = shape.empty?
|
72
|
+
shape = [1] if empty_shape
|
78
73
|
|
79
|
-
klass
|
74
|
+
klass = TYPE_MAP[descr]
|
75
|
+
raise Error, "Type not supported: #{descr}" unless klass
|
76
|
+
|
77
|
+
# use from_string instead of from_binary for max compatibility
|
78
|
+
# from_binary introduced in 0.9.0.4
|
79
|
+
result = klass.from_string(io.read, shape)
|
80
|
+
result = result[0] if empty_shape
|
81
|
+
result
|
80
82
|
end
|
81
83
|
|
82
84
|
def load_npz_io(io)
|
83
85
|
File.new(io)
|
84
86
|
end
|
85
87
|
|
88
|
+
def save(path, arr)
|
89
|
+
::File.open(path, "wb") do |f|
|
90
|
+
save_io(f, arr)
|
91
|
+
end
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
def save_npz(path, **arrs)
|
96
|
+
# use File.open instead passing path to zip file
|
97
|
+
# so it overrides instead of appends
|
98
|
+
::File.open(path, "wb") do |f|
|
99
|
+
Zip::File.open(f, Zip::File::CREATE) do |zipfile|
|
100
|
+
arrs.each do |k, v|
|
101
|
+
zipfile.get_output_stream("#{k}.npy") do |f2|
|
102
|
+
save_io(f2, v)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
86
110
|
private
|
87
111
|
|
112
|
+
def save_io(f, arr)
|
113
|
+
empty_shape = arr.is_a?(Numeric)
|
114
|
+
arr = Numo::NArray.cast([arr]) if empty_shape
|
115
|
+
arr = Numo::NArray.cast(arr) if arr.is_a?(Array)
|
116
|
+
|
117
|
+
# desc
|
118
|
+
descr = TYPE_MAP.find { |k, v| arr.is_a?(v) }
|
119
|
+
raise Error, "Unsupported type: #{arr.class.name}" unless descr
|
120
|
+
|
121
|
+
# shape
|
122
|
+
shape = arr.shape
|
123
|
+
shape << "" if shape.size == 1
|
124
|
+
shape = [] if empty_shape
|
125
|
+
|
126
|
+
# header
|
127
|
+
header = "{'descr': '#{descr[0]}', 'fortran_order': False, 'shape': (#{shape.join(", ")}), }".b
|
128
|
+
padding_len = 64 - (11 + header.length) % 64
|
129
|
+
padding = "\x20".b * padding_len
|
130
|
+
header = "#{header}#{padding}\n"
|
131
|
+
|
132
|
+
f.write(MAGIC_STR)
|
133
|
+
f.write("\x01\x00".b)
|
134
|
+
f.write([header.bytesize].pack("S<"))
|
135
|
+
f.write(header)
|
136
|
+
f.write(arr.to_string)
|
137
|
+
end
|
138
|
+
|
88
139
|
def with_file(path)
|
89
140
|
::File.open(path, "rb") do |f|
|
90
141
|
yield f
|
@@ -93,17 +144,21 @@ module Npy
|
|
93
144
|
|
94
145
|
# header is Python dict, so use regex to parse
|
95
146
|
def parse_header(header)
|
147
|
+
# sanity check
|
148
|
+
raise Error, "Bad header" if !header || header[-1] != "\n"
|
149
|
+
|
96
150
|
# descr
|
97
|
-
m = /'descr': '([^']+)'/.match(header)
|
151
|
+
m = /'descr': *'([^']+)'/.match(header)
|
98
152
|
descr = m[1]
|
99
153
|
|
100
154
|
# fortran_order
|
101
|
-
m = /'fortran_order': ([^,]+)/.match(header)
|
155
|
+
m = /'fortran_order': *([^,]+)/.match(header)
|
102
156
|
fortran_order = m[1] == "True"
|
103
157
|
|
104
158
|
# shape
|
105
|
-
m = /'shape':
|
106
|
-
|
159
|
+
m = /'shape': *\(([^)]*)\)/.match(header)
|
160
|
+
# no space in split for max compatibility
|
161
|
+
shape = m[1].split(",").map(&:to_i)
|
107
162
|
|
108
163
|
[descr, fortran_order, shape]
|
109
164
|
end
|
data/lib/npy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: npy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|
@@ -114,5 +114,5 @@ requirements: []
|
|
114
114
|
rubygems_version: 3.0.3
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
|
-
summary:
|
117
|
+
summary: Save and load NumPy npy and npz files in Ruby
|
118
118
|
test_files: []
|