python - Ruby 数组函数的 Numpy 等价物
问题描述
我正在做一个练习数据预处理的作业,在这种情况下是等宽分箱,但我不熟悉这些 numpy 函数,所以我的 python 代码有点难看:
def eq_width_bin(data, bins):
bin_edge = np.linspace(np.min(data), np.max(data), bins+1)
bin_edge[-1] += 1
re = []
for i in data:
for j in bin_edge:
if i < j:
re.append(int(np.argwhere(bin_edge==j))-1)
break
return re
data = np.array([80, 95, 70, 30, 20, 10, 75, 65, 98, 103, 130, 70])
print("After equal width binning:\n{}".format(eq_width_bin(data, 3)))
但是在 ruby 中,我可以用不到 10 行来完成(尽管这有点慢):
def eq_width_bin(data, bins)
bin_edge = bins.times.collect{|i| data.min + (data.max - data.min) / bins * i} << data.max + 1
return data.collect{|i| bin_edge.index{|j| i < j} - 1}
end
data = [80, 95, 70, 30, 20, 10, 75, 65, 98, 103, 130, 70]
puts "After equal width binning:\n#{eq_width_bin(data, 3)}"
我经常用.select
.collect
.inject
.sort_by
ruby 处理数组,那么有没有任何 numpy 函数可以用来“美化”我上面的 python 代码?(特别是知道 numpy 的内置函数比在 pyhton 中执行要快得多)
解决方案
最初这看起来像bincount
or histogram
,但输出是每个值适合的箱,而不是每个箱的项目数:
In [3]: eq_width_bin(data,3)
Out[3]: [1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1]
你的垃圾箱:
In [10]: np.linspace(np.min(data),np.max(data),4)
Out[10]: array([ 10., 50., 90., 130.])
我们可以通过简单的整数除法来识别每个值的 bin:
In [12]: (data-10)//40
Out[12]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 3, 1])
并用以下方法纠正3:
In [16]: np.minimum((data-10)//40,2)
Out[16]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1])
但这并不能回答您关于.select .collect .inject .sort_by
. 我不熟悉那些(尽管我Squeak
多年前是粉丝,并且涉足Ruby
了一点)。它们听起来更像迭代器,例如收集在itertools
.
numpy
我们通常不采用迭代方法。相反,我们尝试将数组视为一个整体,对整个事物进行除法和最小/最大值之类的操作。
===
searchsorted
也适用于这个问题:
In [19]: np.searchsorted(Out[10],data)
Out[19]: array([2, 3, 2, 1, 1, 0, 2, 2, 3, 3, 3, 2])
In [21]: np.maximum(0,np.searchsorted(Out[10],data)-1)
Out[21]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1])
Python 循环的(可能)更简洁的表达式:
def foo(i, edges):
for j,n in enumerate(edges):
if i<n:
return j-1
return j-1
In [34]: edges = np.linspace(np.min(data),np.max(data),4).tolist()
In [35]: [foo(i,edges) for i in data]
Out[35]: [1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1]
我转换edges
为列表,因为以这种方式迭代更快。
与itertools
:
In [55]: [len(list(itertools.takewhile(lambda x: x<i,edges)))-1 for i in data]
Out[55]: [1, 2, 1, 0, 0, -1, 1, 1, 2, 2, 2, 1]
===
另一种方法
In [45]: edges = np.linspace(np.min(data),np.max(data),4)
In [46]: data[:,None]<-edges
Out[46]:
array([[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
In [47]: np.argmax(data[:,None]<edges, axis=1)-1
Out[47]: array([ 1, 2, 1, 0, 0, 0, 1, 1, 2, 2, -1, 1])
这-1
需要清理(没有 True 的行)。
编辑
列表有index
方法;有了它,我们可以得到一个很像你最后Ruby
一行的表达式。看起来列表理解很像 Ruby collect
:
In [88]: [[i<j for i in edges].index(False)-1 for j in data]
Out[88]: [1, 2, 1, 0, 0, -1, 1, 1, 2, 2, 2, 1]
推荐阅读
- ios - 如何修改现有函数以将数据返回到变量
- c++ - 迭代对向量并访问第一个和第二个元素
- android - 如何在对话框中输入 Intent 命令?
- mysql - 如何 ORDER BY 临时表
- javascript - 如何使用“react-testing-library”对 React 组件进行单元测试
- ios - 如果数据类型为 URL 的变量为空,如何在 Swift 中检查?
- javascript - 为什么每次我进入路由时组件都会复制自己?
- java - 如何通过单击通过适配器的列表中的项目来调用插页式广告?
- c# - 会话变量立即为空..ASP.net Core
- suitecrm - 如何在 SuiteCRM 中获取链接 bean 功能