Matft 是 Swift 中类似 Numpy 的库。 函数名称和用法与 Numpy 相似。
信息: 支持复数!!
多种类型
美观打印
索引
切片
视图
转换
通用函数归约
数学
复数
图像转换
...等等。
查看 函数列表 获取所有函数。
MfArray 类似于 numpy.ndarray
let a = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]])
let aa = Matft.arange(start: -8, to: 8, by: 1, shape: [2,2,4])
print(a)
print(aa)
/*
mfarray =
[[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], type=Int, shape=[2, 2, 4]
mfarray =
[[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], type=Int, shape=[2, 2, 4]
*/
你可以将 MfType 作为 MfArray 的参数 mftype: .Hoge
传递。 它类似于 dtype
。
※注意,即使你设置 MfType.Int,存储的数据类型也只会是 Float 或 Double。 因此,如果你将大数字输入到 MfArray 中,可能会导致溢出或任何计算(+、-、*、/,... 等)中出现奇怪的结果。 但我相信这在实际使用中不是问题。
MfType 的列表如下
public enum MfType: Int{
case None // Unsupportted
case Bool
case UInt8
case UInt16
case UInt32
case UInt64
case UInt
case Int8
case Int16
case Int32
case Int64
case Int
case Float
case Double
case Object // Unsupported
}
此外,你可以使用 astype
轻松转换 MfType
let a = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]])
print(a)//See above. if mftype is not passed, MfArray infer MfType. In this example, it's MfType.Int
let a = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], mftype: .Float)
print(a)
/*
mfarray =
[[[ -8.0, -7.0, -6.0, -5.0],
[ -4.0, -3.0, -2.0, -1.0]],
[[ 0.0, 1.0, 2.0, 3.0],
[ 4.0, 5.0, 6.0, 7.0]]], type=Float, shape=[2, 2, 4]
*/
let aa = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], mftype: .UInt)
print(aa)
/*
mfarray =
[[[ 4294967288, 4294967289, 4294967290, 4294967291],
[ 4294967292, 4294967293, 4294967294, 4294967295]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], type=UInt, shape=[2, 2, 4]
*/
//Above output is same as numpy!
/*
>>> np.arange(-8, 8, dtype=np.uint32).reshape(2,2,4)
array([[[4294967288, 4294967289, 4294967290, 4294967291],
[4294967292, 4294967293, 4294967294, 4294967295]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], dtype=uint32)
*/
print(aa.astype(.Float))
/*
mfarray =
[[[ -8.0, -7.0, -6.0, -5.0],
[ -4.0, -3.0, -2.0, -1.0]],
[[ 0.0, 1.0, 2.0, 3.0],
[ 4.0, 5.0, 6.0, 7.0]]], type=Float, shape=[2, 2, 4]
*/
你可以将 MfSlice (参见下面的列表)设置为下标。
MfSlice(start: Int? = nil, to: Int? = nil, by: Int = 1)
Matft.newaxis
~< //this is prefix, postfix and infix operator. same as python's slice, ":"
Matft.all // same as python's slice :, matft's 0~<
Matft.reverse // same as python's slice ::-1, matft's ~<<-1
普通索引
let a = Matft.arange(start: 0, to: 27, by: 1, shape: [3,3,3])
print(a)
/*
mfarray =
[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]]], type=Int, shape=[3, 3, 3]
*/
print(a[2,1,0])
// 21
注意
MfArray 符合 Collection 协议,因此 1D MfArray 返回 MfArray! 使用 item
作为替代下标的解决方法,例如
let a = Matft.arange(start: 0, to: 27, by: 1, shape: [27])
print(a[0])
/*
0 // a[0] is MfArray!! Nevertheless, The scalar is printed (I don't know why...)
*/
print(a[0] + 4)
/*
mfarray =
[ 4], type=Int, shape=[1]
*/
// Workaround
print(a.item(index: 0, type: Int.self))
/*
0
*/
print(a.item(index: 0, type: Int.self) + 4)
/*
4
*/
如果将 :
替换为 ~<
,则可以获取切片的 mfarray。 请注意,使用 a[0~<]
而不是 a[:]
来获取沿轴的所有元素。
print(a[~<1]) //same as a[:1] for numpy
/*
mfarray =
[[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]]], type=Int, shape=[1, 3, 3]
*/
print(a[1~<3]) //same as a[1:3] for numpy
/*
mfarray =
[[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]]], type=Int, shape=[2, 3, 3]
*/
print(a[~<~<2]) //same as a[::2] for numpy
//print(a[~<<2]) //alias
/*
mfarray =
[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]]], type=Int, shape=[2, 3, 3]
*/
print(a[Matft.all, 0]) //same as a[:, 0] for numpy
/*
mfarray =
[[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]], type=Int, shape=[3, 3]
*/
负索引也可用。 这是我实现起来最困难的部分...
print(a[~<-1])
/*
mfarray =
[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]]], type=Int, shape=[2, 3, 3]
*/
print(a[-1~<-3])
/*
mfarray =
[], type=Int, shape=[0, 3, 3]
*/
print(a[Matft.reverse])
//print(a[~<~<-1]) //alias
//print(a[~<<-1]) //alias
/*
mfarray =
[[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]],
[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]]], type=Int, shape=[3, 3, 3]*/
你可以使用布尔索引。
注意! 我没有检查性能,因此此布尔索引可能很慢
不幸的是,Matft 比 numpy 慢太多了...
(numpy 是 1ms,Matft 是 7ms...)
let img = MfArray([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], mftype: .UInt8)
img[img > 3] = MfArray([10], mftype: .UInt8)
print(img)
/*
mfarray =
[[ 1, 2, 3],
[ 10, 10, 10],
[ 10, 10, 10]], type=UInt8, shape=[3, 3]
*/
你可以使用花式索引!!!
let a = MfArray([[1, 2], [3, 4], [5, 6]])
a[MfArray([0, 1, 2]), MfArray([0, -1, 0])] = MfArray([999,888,777])
print(a)
/*
mfarray =
[[ 999, 2],
[ 3, 888],
[ 777, 6]], type=Int, shape=[3, 2]
*/
a.T[MfArray([0, 1, -1]), MfArray([0, 1, 0])] = MfArray([-999,-888,-777])
print(a)
/*
mfarray =
[[ -999, -777],
[ 3, -888],
[ 777, 6]], type=Int, shape=[3, 2]
*/
请注意,返回的下标 mfarray 将具有 base
属性(类似于 Numpy 中的 view
)。 有关详细信息,请参见 numpy 文档。
let a = Matft.arange(start: 0, to: 4*4*2, by: 1, shape: [4,4,2])
let b = a[0~<, 1]
b[~<<-1] = MfArray([9999]) // cannot pass Int directly such like 9999
print(a)
/*
mfarray =
[[[ 0, 1],
[ 9999, 9999],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[ 9999, 9999],
[ 12, 13],
[ 14, 15]],
[[ 16, 17],
[ 9999, 9999],
[ 20, 21],
[ 22, 23]],
[[ 24, 25],
[ 9999, 9999],
[ 28, 29],
[ 30, 31]]], type=Int, shape=[4, 4, 2]
*/
Matft 支持复数!!
但这只是测试版。 因此,可能会发生任何错误。
请通过 issue 向我报告!(Progres
TODO
sin,cos,tan,exp,log
)let real = Matft.arange(start: 0, to: 16, by: 1).reshape([2,2,4])
let imag = Matft.arange(start: 0, to: -16, by: -1).reshape([2,2,4])
let a = MfArray(real: real, imag: imag)
print(a)
/*
mfarray =
[[[ 0 +0j, 1 -1j, 2 -2j, 3 -3j],
[ 4 -4j, 5 -5j, 6 -6j, 7 -7j]],
[[ 8 -8j, 9 -9j, 10 -10j, 11 -11j],
[ 12 -12j, 13 -13j, 14 -14j, 15 -15j]]], type=Int, shape=[2, 2, 4]
*/
print(a+a)
/*
mfarray =
[[[ 0 +0j, 2 -2j, 4 -4j, 6 -6j],
[ 8 -8j, 10 -10j, 12 -12j, 14 -14j]],
[[ 16 -16j, 18 -18j, 20 -20j, 22 -22j],
[ 24 -24j, 26 -26j, 28 -28j, 30 -30j]]], type=Int, shape=[2, 2, 4]
*/
print(Matft.complex.angle(a))
/*
mfarray =
[[[ -0.0, -0.7853982, -0.7853982, -0.7853982],
[ -0.7853982, -0.7853982, -0.7853982, -0.7853982]],
[[ -0.7853982, -0.7853982, -0.7853982, -0.7853982],
[ -0.7853982, -0.7853982, -0.7853982, -0.7853982]]], type=Float, shape=[2, 2, 4]
*/
print(Matft.complex.conjugate(a))
/*
mfarray =
[[[ 0 +0j, 1 +1j, 2 +2j, 3 +3j],
[ 4 +4j, 5 +5j, 6 +6j, 7 +7j]],
[[ 8 +8j, 9 +9j, 10 +10j, 11 +11j],
[ 12 +12j, 13 +13j, 14 +14j, 15 +15j]]], type=Int, shape=[2, 2, 4]
*/
你可以使用 Matft 完成图像处理!(测试版)请参阅此处的示例。
@IBOutlet weak var originalImageView: UIImageView!
@IBOutlet weak var reverseImageView: UIImageView!
@IBOutlet weak var swapImageView: UIImageView!
func reverse(){
var image = Matft.image.cgimage2mfarray(self.reverseImageView.image!.cgImage!)
// reverse
image = image[Matft.reverse] // same as image[~<<-1]
self.reverseImageView.image = UIImage(cgImage: Matft.image.mfarray2cgimage(image))
}
func swapchannel(){
var image = Matft.image.cgimage2mfarray(self.swapImageView.image!.cgImage!)
// swap channel
image = image[Matft.all, Matft.all, MfArray([1,0,2,3])] // same as image[0~<, 0~<, MfArray([1,0,2,3])]
self.swapImageView.image = UIImage(cgImage: Matft.image.mfarray2cgimage(image))
}
对于更复杂的转换,请参阅 OpenCV 代码。
下面是 Matft 的函数列表。 正如我上面提到的,几乎所有函数都类似于 Numpy。 此外,这些函数在内部使用 Accelerate 框架,性能可能会保持很高。
*
表示也存在方法函数。 简而言之,你可以使用 a.shallowcopy()
,其中 a
是 MfArray
。
^
表示仅方法函数。 简而言之,你可以使用 a.tolist()
,而不是 Matft.tolist
,其中 a
是 MfArray
。
#
表示支持复数运算
Matft | Numpy |
---|---|
*#Matft.shallowcopy | *numpy.copy |
*#Matft.deepcopy | copy.deepcopy |
Matft.nums | numpy.ones * N |
Matft.nums_like | numpy.ones_like * N |
Matft.arange | numpy.arange |
Matft.eye | numpy.eye |
Matft.diag | numpy.diag |
Matft.vstack | numpy.vstack |
Matft.hstack | numpy.hstack |
Matft.concatenate | numpy.concatenate |
*Matft.append | numpy.append |
*Matft.insert | numpy.insert |
*Matft.take | numpy.take |
^MfArray.item | ^numpy.ndarray.item |
Matft | Numpy |
---|---|
*#Matft.astype | *numpy.astype |
*#Matft.transpose | *numpy.transpose |
*#Matft.expand_dims | *numpy.expand_dims |
*#Matft.squeeze | *numpy.squeeze |
*#Matft.broadcast_to | *numpy.broadcast_to |
*#Matft.to_contiguous | *numpy.ascontiguousarray |
*#Matft.flatten | *numpy.flatten |
*#Matft.flip | *numpy.flip |
*#Matft.clip | *numpy.clip |
*#Matft.swapaxes | *numpy.swapaxes |
*#Matft.moveaxis | *numpy.moveaxis |
*Matft.roll | numpy.roll |
*Matft.sort | *numpy.sort |
*Matft.argsort | *numpy.argsort |
^MfArray.toArray | ^numpy.ndarray.tolist |
^MfArray.toFlattenArray | 不适用 |
^MfArray.toMLMultiArray | 不适用 |
*Matft.orderedUnique | numpy.unique |
Matft | Numpy |
---|---|
Matft.file.loadtxt | numpy.loadtxt |
Matft.file.genfromtxt | numpy.genfromtxt |
Matft.file.savetxt | numpy.savetxt |
运算
第 2 行是中缀(前缀)运算符。
Matft | Numpy |
---|---|
#Matft.add + |
numpy.add + |
#Matft.sub - |
numpy.sub - |
#Matft.div / |
numpy.div . |
#Matft.mul * |
numpy.multiply * |
Matft.inner *+ |
numpy.inner 不适用 |
Matft.cross *^ |
numpy.cross 不适用 |
Matft.matmul *& |
numpy.matmul @ |
Matft.dot | numpy.dot |
Matft.equal === |
numpy.equal == |
Matft.not_equal !== |
numpy.not_equal != |
Matft.less < |
numpy.less < |
Matft.less_equal <= |
numpy.less_equal <= |
Matft.greater > |
numpy.greater > |
Matft.greater_equal >= |
numpy.greater_equal >= |
#Matft.allEqual == |
numpy.array_equal 不适用 |
#Matft.neg - |
numpy.negative - |
Matft | Numpy |
---|---|
*#Matft.ufuncReduce 例如) Matft.ufuncReduce(a, Matft.add) |
numpy.add.reduce 例如) numpy.add.reduce(a) |
*#Matft.ufuncAccumulate 例如) Matft.ufuncAccumulate(a, Matft.add) |
numpy.add.accumulate 例如) numpy.add.accumulate(a) |
Matft | Numpy |
---|---|
#Matft.math.sin | numpy.sin |
Matft.math.asin | numpy.asin |
Matft.math.sinh | numpy.sinh |
Matft.math.asinh | numpy.asinh |
#Matft.math.cos | numpy.cos |
Matft.math.acos | numpy.acos |
Matft.math.cosh | numpy.cosh |
Matft.math.acosh | numpy.acosh |
#Matft.math.tan | numpy.tan |
Matft.math.atan | numpy.atan |
Matft.math.tanh | numpy.tanh |
Matft.math.atanh | numpy.atanh |
Matft.math.sqrt | numpy.sqrt |
Matft.math.rsqrt | numpy.rsqrt |
#Matft.math.exp | numpy.exp |
#Matft.math.log | numpy.log |
Matft.math.log2 | numpy.log2 |
Matft.math.log10 | numpy.log10 |
*Matft.math.ceil | numpy.ceil |
*Matft.math.floor | numpy.floor |
*Matft.math.trunc | numpy.trunc |
*Matft.math.nearest | numpy.nearest |
*Matft.math.round | numpy.round |
#Matft.math.abs | numpy.abs |
Matft.math.reciprocal | numpy.reciprocal |
#Matft.math.power | numpy.power |
Matft.math.arctan2 | numpy.arctan2 |
Matft.math.square | numpy.square |
Matft.math.sign | numpy.sign |
Matft | Numpy |
---|---|
*Matft.stats.mean | *numpy.mean |
*Matft.stats.max | *numpy.max |
*Matft.stats.argmax | *numpy.argmax |
*Matft.stats.min | *numpy.min |
*Matft.stats.argmin | *numpy.argmin |
*Matft.stats.sum | *numpy.sum |
Matft.stats.maximum | numpy.maximum |
Matft.stats.minimum | numpy.minimum |
*Matft.stats.sumsqrt | 不适用 |
*Matft.stats.squaresum | 不适用 |
*Matft.stats.cumsum | *numpy.cumsum |
Matft | Numpy |
---|---|
Matft.random.rand | numpy.random.rand |
Matft.random.randint | numpy.random.randint |
Matft | Numpy |
---|---|
Matft.linalg.solve | numpy.linalg.solve |
Matft.linalg.inv | numpy.linalg.inv |
Matft.linalg.det | numpy.linalg.det |
Matft.linalg.eigen | numpy.linalg.eig |
Matft.linalg.svd | numpy.linalg.svd |
Matft.linalg.pinv | numpy.linalg.pinv |
Matft.linalg.polar_left | scipy.linalg.polar |
Matft.linalg.polar_right | scipy.linalg.polar |
Matft.linalg.normlp_vec | scipy.linalg.norm |
Matft.linalg.normfro_mat | scipy.linalg.norm |
Matft.linalg.normnuc_mat | scipy.linalg.norm |
Matft | Numpy |
---|---|
Matft.complex.angle | numpy.angle |
Matft.complex.conjugate | numpy.conj / numpy.conjugate |
Matft.complex.abs | numpy.abs / numpy.absolute |
Matft | Numpy |
---|---|
Matft.fft.rfft | numpy.fft.rfft |
Matft.fft.irfft | numpy.fft.irfft |
Matft 仅支持自然三次样条。 我稍后将实现其他边界条件。
Matft | Scipy |
---|---|
Matft.interp1d.cubicSpline | scipy.interpolation.CubicSpline |
Matft | Numpy |
---|---|
Matft.image.cgimage2mfarray | 不适用 |
Matft.image.mfarray2cgimage | 不适用 |
Matft | OpenCV |
---|---|
Matft.image.color | cv2.cvtColor |
Matft.image.resize | cv2.resize |
Matft.image.warpAffine | cv2.warpAffine |
我使用 Accelerate
框架,因此所有 MfArray 操作可能会保持高性能。
let a = Matft.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let aneg = Matft.arange(start: 0, to: -10*10*10*10*10*10, by: -1, shape: [10,10,10,10,10,10])
let aT = a.T
let b = a.transpose(axes: [0,3,4,2,1,5])
let c = a.transpose(axes: [1,2,3,4,5,0])
let posb = a > 0
import numpy as np
a = np.arange(10**6).reshape((10,10,10,10,10,10))
aneg = np.arange(0, -10**6, -1).reshape((10,10,10,10,10,10))
aT = a.T
b = a.transpose((0,3,4,2,1,5))
c = a.transpose((1,2,3,4,5,0))
posb = a > 0
Matft | 时间 | Numpy | 时间 |
---|---|---|---|
let _ = a+aneg |
596μs |
a+aneg |
1.04ms |
let _ = b+aT |
4.46ms |
b+aT |
4.31ms |
let _ = c+aT |
5.31ms |
c+aT |
2.92ms |
Matft | 时间 | Numpy | 时间 |
---|---|---|---|
let _ = Matft.math.sin(a) |
2.14ms |
np.sin(a) |
14.7ms |
let _ = Matft.math.sin(b) |
7.02ms |
np.sin(b) |
15.8ms |
let _ = Matft.math.sign(a) |
3.09ms |
np.sign(a) |
1.37ms |
let _ = Matft.math.sign(b) |
8.33ms |
np.sign(b) |
1.42ms |
Matft | 时间 | Numpy | 时间 |
---|---|---|---|
let _ = a > 0 |
4.63ms |
a > 0 |
855μs |
let _ = a > b |
17.8ms |
a > b |
1.83ms |
let _ = a === 0 |
4.65ms |
a == 0 |
603μs |
let _ = a === b |
19.7ms |
a == b |
1.78ms |
Matft | 时间 | Numpy | 时间 |
---|---|---|---|
let _ = a[posb] |
1.21ms |
a[posb] |
1.29ms |
Matft 实现了与 Numpy 几乎相同的性能!!!
※Swift 的性能测试是在发布模式下进行的
但是,正如你从上表中所看到的,Matft 的布尔运算太慢了...(Issue #18)
所以,非常欢迎 pull request!!
重要!!! 下面的安装方式已过时。 请通过 swiftPM 安装 Matft!!!
设置 Cartfile
echo 'github "jjjkkkjjj/Matft"' > Cartfile
carthage update ###or append '--platform ios'
将上述过程生成的 Matft.framework 导入到你的项目中
创建 Podfile(如果已经完成,请跳过)
pod init
在 Podfile 中写入 pod 'Matft'
,如下所示
target 'your project' do
pod 'Matft'
end
安装 Matft
pod install
随时通过 junnosuke.kado.git@gmail.com 询问有关此项目或任何问题