npy 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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: []
|