元组列表(开始、结束)到索引范围(将 pandas.IntervalArray 转换为 numpy 数组?)
List of tuples (begin, end) to index range (convert a pandas.IntervalArray to a numpy array?)
目标
我有一个值数组和一个元组列表,表示需要从该数组中选择哪些索引。 (想想表示音频数组的哪一部分是语音的元组。)我正在考虑使用选择掩码:
import numpy as np
# sample data
arr = np.array([.3, .4, .5, -.2, -.1, .7, .9])
selection_idx = [(0, 3), (5,7)]
# unknown: how to efficiently selection_idx -> mask?
mask = [0, 1, 2, 5, 6] # or
mask = [True, True, True, False, False, True, True]
# desired result 1
arr[mask]
# Out: array([0.3, 0.4, 0.5, 0.7, 0.9])
Pandas掩码的IntervalArray方法
Numpy 本身限制为 numpy.arange
(from what I could find) to generate regular Interval sequences. Pandas however has the pandas.IntervalArray
object, which can be created with useful functions such as .from_tuples
。
用代码术语来说就是:
import pandas as pd
pd.arrays.IntervalArray.from_tuples(selection)
# Out:
# <IntervalArray>
# [(0, 3], (5, 7]]
# Length: 2, closed: right, dtype: interval[int64]
问题
- 由于我的用例在 Pandas 域之外,我想知道是否可以将此
IntervalArray
对象转换为 numpy 数组(导致 mask
在目标)?
- 如果 Pandas
IntervalArray
不能用于我的用例,还有什么其他方法? (在我的真实情况下,不规则元组的列表每个数组超过 1000 个(具有 >10.000 个数组),所以我正在寻找比循环和 numpy.append
) 更有效的方法
这可以解决您的问题,尽管我相信 Numpy 中可能存在我不知道的语法:
from itertools import chain
arr = np.array([.3, .4, .5, -.2, -.1, .7, .9])
selection_idx = [(0, 3), (5,7)]
m = list(chain.from_iterable(range(a,b) for a,b in selection_idx))
print(m)
# [0, 1, 2, 5, 6]
arr[m]
array([0.3, 0.4, 0.5, 0.7, 0.9])
基本上,它通过解压每个元组并使用 itertool 的 chain.from_iterable 将所有内容合并为一个来获取列表。剩下的就是使用 numpy 的索引来获取你的结果。
请注意,如果您有布尔值,则可以使用 numpy 的 compress 来获取输出:
mask = [True, True, True, False, False, True, True]
np.compress(mask, arr)
一个想法是使用带有扁平化的列表理解:
mask = [c for a,b in selection_idx for c in range(a,b)]
print(arr[mask])
[0.3 0.4 0.5 0.7 0.9]
很容易加入各自的 aranges
:
In [14]: np.r_[0:3,5:7]
Out[14]: array([0, 1, 2, 5, 6])
In [15]: np.concatenate([np.arange(i,j) for i,j in selection_idx])
Out[15]: array([0, 1, 2, 5, 6])
我没有看到 pandas
构造提供任何性能优势的任何证据。显示看起来就像输入元组中经过轻微处理的属性。
===
这是一种构造掩码的方法,无需对迭代进行循环。对于这个小案例,它可能比我的 concatenate
慢,但对于许多元组,它可能会更快:
In [42]: idx=np.array(selection_idx)
In [43]: idx
Out[43]:
array([[0, 3],
[5, 7]])
In [44]: l0=idx[:,[0]]<=np.arange(7)
In [45]: l1=idx[:,[1]]>np.arange(7)
In [46]: l0 & l1
Out[46]:
array([[ True, True, True, False, False, False, False],
[False, False, False, False, False, True, True]])
In [47]: np.any(l0&l1, axis=0)
Out[47]: array([ True, True, True, False, False, True, True])
受其他答案的启发,仅使用 1 个 for 循环来创建布尔掩码的列表理解:
selection_arr = np.array(selection_idx) # convert tuples to numpy array
mask = np.full(len(arr), False) # initialize a Boolean numpy array set to False
for b, e in selection_arr:
mask[b:e] = True
mask
# Out: array([ True, True, True, False, False, True, True])
arr[mask]
# Out: array([0.3, 0.4, 0.5, 0.7])
目标
我有一个值数组和一个元组列表,表示需要从该数组中选择哪些索引。 (想想表示音频数组的哪一部分是语音的元组。)我正在考虑使用选择掩码:
import numpy as np
# sample data
arr = np.array([.3, .4, .5, -.2, -.1, .7, .9])
selection_idx = [(0, 3), (5,7)]
# unknown: how to efficiently selection_idx -> mask?
mask = [0, 1, 2, 5, 6] # or
mask = [True, True, True, False, False, True, True]
# desired result 1
arr[mask]
# Out: array([0.3, 0.4, 0.5, 0.7, 0.9])
Pandas掩码的IntervalArray方法
Numpy 本身限制为 numpy.arange
(from what I could find) to generate regular Interval sequences. Pandas however has the pandas.IntervalArray
object, which can be created with useful functions such as .from_tuples
。
用代码术语来说就是:
import pandas as pd
pd.arrays.IntervalArray.from_tuples(selection)
# Out:
# <IntervalArray>
# [(0, 3], (5, 7]]
# Length: 2, closed: right, dtype: interval[int64]
问题
- 由于我的用例在 Pandas 域之外,我想知道是否可以将此
IntervalArray
对象转换为 numpy 数组(导致mask
在目标)? - 如果 Pandas
IntervalArray
不能用于我的用例,还有什么其他方法? (在我的真实情况下,不规则元组的列表每个数组超过 1000 个(具有 >10.000 个数组),所以我正在寻找比循环和numpy.append
) 更有效的方法
这可以解决您的问题,尽管我相信 Numpy 中可能存在我不知道的语法:
from itertools import chain
arr = np.array([.3, .4, .5, -.2, -.1, .7, .9])
selection_idx = [(0, 3), (5,7)]
m = list(chain.from_iterable(range(a,b) for a,b in selection_idx))
print(m)
# [0, 1, 2, 5, 6]
arr[m]
array([0.3, 0.4, 0.5, 0.7, 0.9])
基本上,它通过解压每个元组并使用 itertool 的 chain.from_iterable 将所有内容合并为一个来获取列表。剩下的就是使用 numpy 的索引来获取你的结果。
请注意,如果您有布尔值,则可以使用 numpy 的 compress 来获取输出:
mask = [True, True, True, False, False, True, True]
np.compress(mask, arr)
一个想法是使用带有扁平化的列表理解:
mask = [c for a,b in selection_idx for c in range(a,b)]
print(arr[mask])
[0.3 0.4 0.5 0.7 0.9]
很容易加入各自的 aranges
:
In [14]: np.r_[0:3,5:7]
Out[14]: array([0, 1, 2, 5, 6])
In [15]: np.concatenate([np.arange(i,j) for i,j in selection_idx])
Out[15]: array([0, 1, 2, 5, 6])
我没有看到 pandas
构造提供任何性能优势的任何证据。显示看起来就像输入元组中经过轻微处理的属性。
===
这是一种构造掩码的方法,无需对迭代进行循环。对于这个小案例,它可能比我的 concatenate
慢,但对于许多元组,它可能会更快:
In [42]: idx=np.array(selection_idx)
In [43]: idx
Out[43]:
array([[0, 3],
[5, 7]])
In [44]: l0=idx[:,[0]]<=np.arange(7)
In [45]: l1=idx[:,[1]]>np.arange(7)
In [46]: l0 & l1
Out[46]:
array([[ True, True, True, False, False, False, False],
[False, False, False, False, False, True, True]])
In [47]: np.any(l0&l1, axis=0)
Out[47]: array([ True, True, True, False, False, True, True])
受其他答案的启发,仅使用 1 个 for 循环来创建布尔掩码的列表理解:
selection_arr = np.array(selection_idx) # convert tuples to numpy array
mask = np.full(len(arr), False) # initialize a Boolean numpy array set to False
for b, e in selection_arr:
mask[b:e] = True
mask
# Out: array([ True, True, True, False, False, True, True])
arr[mask]
# Out: array([0.3, 0.4, 0.5, 0.7])