Reverse operation of torch.unique - pytorch

In pytorch , unique (with return_count is True) operation do like this
[1,1,2,2,3,3] => ([1,2,3],[2,2,2])
Are there any reverse operations of torch.unique() ?
i.e Given a unique list and its count , return the original list like
([1,2,3],[2,2,2]) = > [1,1,2,2,3,3]

If you include the return inverse parameter it will return the indices for where elements in the original input ended up in the returned unique list. Then you can use take to create a new tensor.
test_tensor = torch.tensor([1,1,2,2,3,3])
items, inverse, counts = test_tensor.unique(return_counts=True, return_inverse=True)
new_tensor = torch.take(items, inverse)
assert new_tensor.eq(test_tensor).all() # true
EDIT:
If you only have a list and the counts this code should give you what you want using repeat. Not sure if a pure pytorch function exists.
test_tensor = torch.tensor([1,1,2,2,3,3])
items, counts = test_tensor.unique(return_counts=True)
new_tensor = torch.tensor([], dtype=torch.int64)
for item, count in zip(items, counts):
new_tensor = torch.cat((new_tensor, item.repeat(count)))
assert new_tensor.eq(test_tensor).all() # true

You probably want torch.repeat_interleave(). You can use it like this:
>>> x = torch.tensor([1, 1, 2, 3, 3, 3])
>>> v, c = torch.unique(x, return_counts=True)
>>> v, c
(tensor([1, 2, 3]), tensor([2, 1, 3]))
>>> torch.repeat_interleave(v, c)
tensor([1, 1, 2, 3, 3, 3])

Related

Selection sort using python3

def selection_sort(li):
new_list = []
a = li[0]
for x in range(1, len(li)):
if li[x] < a:
a = li[x]
new_list = a
print(new_list)
b = [1, 2, 5, 3, 7, 4]
selection_sort(b)
Why does the above code returns empty list.
Thank you
Learn what is selection sort using visualization. Do follow the steps how to use selection sort
def selection_sort(li):
for i in range(len(li)):
min_idx = i
for j in range(i+1, len(li)):
if li[min_idx] > li[j]:
min_idx = j
li[i], li[min_idx] = li[min_idx], li[i]
print(li)
b = [1, 2, 5, 3, 7, 4]
selection_sort(b)
Now, from your code perspective, your selection sort algorithm isn't correct. Furthermore, you don't need to initialize another list to store sort element rather your function parameter list is kind enough to store the sort element.

Finding overlap of given list

Find overlap which given list, a list of intervals like [2, 4], returns whether any two intervals overlap. Boundary overlaps don't count.
Example:
`>>> check_overlap(li=[[1,5], [8,9], [3,6]])
True
>>> check_overlap(li=[[1,5], [5,6]])
False`
data= [[1, 5], [8, 9], [3, 6]]
values = [[value for value in range(elem[0], elem[1])]for elem in data]
print(values)
[[1, 2, 3, 4], [8], [3, 4, 5]]
After that i want to know how to check with each element in a list whether any two intervals overlapping.
For checking the overlap, I would sort the bigger list with first element of the sublists, and check the 2nd element of a sublist is bigger than the 1st element of the next sublist.
def overlap(li):
li.sort(key=lambda x: x[0])
for i in range(len(li)-1):
if li[i][1] > li[i+1][0]:
return True
return False
print(overlap([[1,5], [8,9], [3,6]]))
print(overlap([[1,5], [5,6]]))
True
False
I would use the itertools.combinations function as such:
from itertools import combinations
def check_overlap(li):
lists = [list(range(a, b)) for a, b in li] # Shorter way of your values = ... line
for l1, l2 in combinations(lists, 2):
if any(l in l2 for l in l1):
return True
return False
The combinations(lists, 2) call gives you all possible unique combinations of different elements.
Next, the any() function takes any iterable and returns True if any of the elements in the iterable are True (or rather 'truthy'). In this case, the l in l2 for l in l1 is a generator expression, but would work the same with square brackets around it to explicitly make it into a list first.
You can create sets and check for intersection -
data= [[1, 5], [8, 9], [3, 6]]
sets_from_data = [set(range(*l)) for l in data]
intersection_exists = bool(max([len(a.intersection(b)) for a in sets_from_data for b in sets_from_data if a != b]) > 0)
intersection_exists
# True
If you only have integers you can indeed use range to do this test:
def check_overlap(li):
ranges = [range(r[0]+1, r[1]-1) for r in li]
return any(any(e-1 in r for r in ranges) for l in li for e in l)
On the other hand, if you have floating point values you'll have to tests both bounds of the interval individually (using < and >):
def is_in_range(value, boundaries):
m, M = boundaries
return value > m+1 and value < M-1
def check_overlap(li):
return any(any(is_in_range(e, r) for r in li) for l in li for e in l)

Nested loop over the elements of the same array

I have a numpy array:
a = np.array([0, 1, 2, 3, 4, 5])
I would like to iterate over each element and compute a statistic using all the elements except the one at the current index. Statistic would require looping over each element.
stats = np.array([])
for ind1,x in enumerate(a):
s = 0
for ind2,y in enumerate(a):
if ind2 != ind1:
s = s + compute_stat(y)
stats[ind1] = s
It looks like I might mask the current index, however, I would then need to reset the mask within each loop.
a = np.array([0, 1, 2, 3, 4, 5])
a = np.ma.array(a)
for ind1,x in enumerate(a):
a[ind1] = np.ma.masked
What is the best way to use a nested loop in this case to iterate a computation over (n-1) elements of the same array?
Thank you

Join two python arrays via index

i have a problem in Python. I am creating two numpy arrays from dict entries. I want to join those two numpy arrays in a specific way like this:
# create array with classes
probVec = filePickle['classID']
a = np.empty([0, 1])
for x in np.nditer(probVec):
a = np.append(a,x)
timeVec = filePickle['start']
timeVec = np.asarray(timeVec)
b = np.empty([0, 1])
for x in np.nditer(timeVec):
b = np.append(b,x)
# create input-vectors for clustering
c = np.vstack((b,a)).transpose()
Now, if i want to join them in a more specific way, like taking only specific items of array "probVec" to join them with the corresponding entry of array "timeVec" like this:
for x in np.nditer(probVec):
if x == 3.0:
a = np.append(a,x)
for x in np.nditer(timeVec):
b = append with x values that have the same indices as the ones appended in the first loop
Because both arrays contain values corresponding to each other they have the same length. So my goal is something like this:
probVec = [2.0, 1.0, 3.0, 3.0, 4.0, 3.0...]
timeVec = [t1, t2, t3, t4, t5, t6...]
c = [[3.0 t3]
[3.0 t4]
[3.0 t6]
.
.
.
]
I just don't know what's the best way to realize that.
Using a comparison operator on an array, like a == 3.0, you get a boolean array that can be used for indexing, selecting the rows where the condition is true.
In [87]: a = np.random.randint(low=1, high=4, size=10) # example data
In [88]: a
Out[88]: array([3, 1, 3, 1, 1, 3, 2, 2, 2, 2])
In [89]: b = np.arange(10)
In [90]: c = np.column_stack((a, b))
In [91]: c[a == 3]
Out[91]:
array([[3, 0],
[3, 2],
[3, 5]])

List Comprehensions to replace element

for i in range(1, len(A)):
A[i] = A[i-1] + A[i]
You can't do that with a list comprehension as they don't allow assignments.
You can use a simple generator function:
def func(lis):
yield lis[0]
for i,x in enumerate(lis[1:],1):
lis[i] = lis[i-1] + x
yield lis[i]
>>> A = [1, 2, 3, 4, 5, 6, 7]
>>> list(func(A))
[1, 3, 6, 10, 15, 21, 28]
though less efficient, this does give the desired output. But I think I'm getting closer to O(n**2) on this one.
A = [sum(A[:i+1]) for i, _ in enumerate(A)]
afaik this can't be done with a list comprehension the way you want to. I would suggest using the for loop version you've provided. Even if it was possible with a list comprehension, there's no point when you can just modify the list in place.
Use B (another temporary variable).
This should do the trick.
def func(L):
it = iter(L)
v = it.next()
yield v
for x in it:
v += x
yield v
A = [1, 2, 3, 4, 5, 6, 7]
print list(func(A))
This creates an iterator that returns one value at the time. To get the full new list at once you need to use a list() call around the function call, like:
list(func(A))
This generator function should work on any iterable (also those that don't support getting value based on index, like L[0])
I don't think there's an efficient way to do this with a comprehension list.
A one-line solution use reduce:
>>> the_list = [1,2,3,4,5]
>>> reduce(lambda result, x: result+[result[-1] + x] ,the_list, [0])[1:]
[1, 3, 6, 10, 15]

Resources