python Xarray lenght mismatch - python-3.x

I'm learning the Xarray library and I'm trying to create Xarrays for 3D data. The following snippet does not work:
>>> colx = ['c1', 'c2', 'c3', 'c4']
>>> coly = ['a1', 'a2', 'a3']
>>> colz = ['b1', 'b2']
>>> t = xr.DataArray(np.zeros((4,3,2)),dims = {'x', 'y','z'}, coords={'x':colx, 'y': coly, 'z': colz})
>>> t
ValueError: conflicting sizes for dimension 'x': length 3 on the data but length 4 on coordinate 'x'
The following code works, but I need to permute round the lenghts of the x,y,z dimensions to create the Xarray. The dimensions (4,3,2) get permuted to (3,2,4).
>>> colx = ['c1', 'c2', 'c3', 'c4']
>>> coly = ['a1', 'a2', 'a3']
>>> colz = ['b1', 'b2']
>>> t = xr.DataArray(np.zeros((4,3,2)),dims = {'x', 'y','z'}, coords={'x':coly, 'y': colz, 'z': colx})
>>> t
<xarray.DataArray (z: 4, x: 3, y: 2)>
array([[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]]])
Coordinates:
* x (x) <U2 'a1' 'a2' 'a3'
* y (y) <U2 'b1' 'b2'
* z (z) <U2 'c1' 'c2' 'c3' 'c4'
Is this normal?
Why is this happening?
How do the permutations work for higher-dimensional data?

Specifying dims as a list, e.g. dims=['x', 'y', 'z'], instead of a set does the trick, see comment by spencerclark.

Related

How to evaluate a pyTorch/DGL tensor

From a DGL graph I want to see the adjacency matrix with
adjM = g.adjacency_matrix()
adjM
and I get the following which is fine:
tensor(indices=tensor([[0, 0, 0, 1],
[1, 2, 3, 3]]),
values=tensor([1., 1., 1., 1.]),
size=(4, 4), nnz=4, layout=torch.sparse_coo)
Now I want to have the adjacency matrix and the node values each by itself. I imagine something of this kind:
adjMatrix = adjM.indices # or
adjMatrix = adjM[0]
nodeValues = adjM.values # or
nodeValues = adjM[1]
But this form is not estimated by pyTorch/DGL.
My beginner's question:
how to do this correctly and sucsessfully? and
is there a tutorial for a nuby? ( I have searched a lot just for this detail...!)
Click here!
You will find the usage of dgl.adj(). As the doc said, the return is an adjacency matrix, and the return type is the SparseTensor.
I noticed that the output that you post is a SparseTensor.
You can try it as follows then you can get the entire adj_matrix
I create a dgl graph g, get the adjacency matrix as adj
g = dgl.graph(([0, 1, 2], [1, 2, 3]))
adj = g.adj()
adj
output is:
tensor(indices=tensor([[0, 1, 2],
[1, 2, 3]]),
values=tensor([1., 1., 1.]),
size=(4, 4), nnz=3, layout=torch.sparse_coo)
We can find that adj is the presence of sparse, and the sparse type is coo, we can use the following code to verify if adj is a SparseTensor
adj.is_sparse
output :
True
so we can use to_dense() get the original adj matrix
adj.to_dense()
the result is:
tensor([[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
[0., 0., 0., 0.]])
When you have a problem with DGL you can check the Deep Graph Library Tutorials and Documentation.

Creating a distance matrix from a matrix/list

I have created a list from the input and from the list I have created a matrix also.
list-
('A', 'B', 3)
('A', 'D', 4)
('B', 'D', 4)
('B', 'H', 5)
('C', 'L', 2)
('D', 'F', 1)
('F', 'H', 3)
('G', 'H', 2)
('G', 'Y', 2)
('I', 'J', 6)
('I', 'K', 4)
matrix-
['A' 'B' '3']
['A' 'D' '4']
['B' 'D' '4']
['B' 'H' '5']
['C' 'L' '2']
['D' 'F' '1']
['F' 'H' '3']
['G' 'H' '2']
['G' 'Y' '2']
['I' 'J' '6']
['I' 'K' '4']
However I want to create a distance matrix from the above matrix or the list and then print the distance matrix. what will be the correct approach to implement it. In the above matrix the first 2 nodes represent the starting and ending node and the third one is the distance. I am ready to give any further clarification if required.A sample distance matrix is -
[[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]]
I think this question can't be homework because it has a specific format like ("A" , "B" , 3) isn't orthonormal to me, so I decided to help you. But it's better to implement another idea for solving it to help yourself in coding. One approach is to assign a number to each char, then you can specify rows and columns of distance matrix with numbers that are associated with letters! for example impute 'A' to 1, 'B' to 2, and so on:
A┌ 0 3 0 ┐ 1┌ 0 3 0 ┐
B| 3 0 0 |────► 2| 3 0 0 |
C└ 0 0 1 ┘ 3└ 0 0 0 ┘
So in this example, 1 stands for "A" and so on. SO how this is going to help? Example: We have a pattern like ('A', 'B', 3), And I consider it as (1, 2, 3) then I can use the first two values of each tuple for index addressing in a distance matrix:
2
┌─────────────┐
Distance Matrix 1│ 3 ... │
('A', 'B', 3)─────► (1, 2, 3) ───────────────► │. . │
│. . │
│. . │
└─────────────┘
So first of all I'll create an input list as you mentioned. I'll name it lis:
lis = [('A', 'B', 3),
('A', 'D', 4),
('B', 'D', 4),
('B', 'H', 5),
('C', 'L', 2),
('D', 'F', 1),
('F', 'H', 3),
('G', 'H', 2),
('G', 'Y', 2),
('I', 'J', 6),
('I', 'K', 4)]
Then I detect unique letters in lis using set and set.union. consider we have letters in the first and second argument of each tuple:
items = set.union(set([item[0].upper() for item in lis]) , set([item[1].upper() for item in lis]))
Then I'll make a dictionary to assign values to each letter considering the order of English letters:
value = dict(zip(sorted(items), range(26)))
Then I'll create a zero matrix using numpy.zeros:
import numpy as np
dist_matrix = np.zeros((len(items) , len(items)))
The last step is assigning the third value of each tuple, to a related position in the distance matrix:
for i in range(len(lis)):
# for Upper triangular
dist_matrix[value[lis[i][0]] , value[lis[i][1]]] = lis[i][2]
# for lower triangular
dist_matrix[value[lis[i][1]] , value[lis[i][0]]] = lis[i][2]
"""
Example:
[0 3 0]
[3 0 0]
[0 0 0]
"""
dist_matrix
This gives me:
array([[0., 3., 0., 4., 0., 0., 0., 0., 0., 0., 0., 0.],
[3., 0., 0., 4., 0., 0., 5., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 2., 0.],
[4., 4., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 3., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 2., 0., 0., 0., 0., 2.],
[0., 5., 0., 0., 3., 2., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 6., 4., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 6., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 4., 0., 0., 0., 0.],
[0., 0., 2., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 2., 0., 0., 0., 0., 0., 0.]])
Appendix
All code at one glance:
import numpy as np
lis = [('A', 'B', 3),
('A', 'D', 4),
('B', 'D', 4),
('B', 'H', 5),
('C', 'L', 2),
('D', 'F', 1),
('F', 'H', 3),
('G', 'H', 2),
('G', 'Y', 2),
('I', 'J', 6),
('I', 'K', 4)]
items = set.union(set([item[0].upper() for item in lis]) , set([item[1].upper() for item in lis]))
value = dict(zip(sorted(items), range(26)))
dist_matrix = np.zeros((len(items) , len(items)))
for i in range(len(lis)):
# for Upper triangular
dist_matrix[value[lis[i][0]] , value[lis[i][1]]] = lis[i][2]
# for lower triangular
dist_matrix[value[lis[i][1]] , value[lis[i][0]]] = lis[i][2]
"""
Example:
[0 3 0]
[3 0 0]
[0 0 0]
"""
dist_matrix
Since you did not show any attempts, here some ideas to get you started.
Convert a character to a number, e.g. an index location:
ord('C') - ord('A')
Creating a matrix:
If you want to have a fixed size pre-allocated matrix, instead of lists in lists which have flexible size, the library numpy can help you. Then you can access fields and set values while looping through your data.
If you are really interested in analyzing a network, you could have a look into networkx.
Please take these ideas as a starting point and refine your question with more precise obstacles you encounter while trying to solve your problem.

sklearn ndcg_score returned incorrect result

I am working on a project that involves the use of NDCG (normalized distributed cumulative gain), and I understand the method's underlying calculations.
So I imported ndcg_score from sklearn.metrics, and then pass in a ground truth array and another array to the ndcg_score function to calculate their NDCG score. The ground truth array has the values [5, 4, 3, 2, 1] while the other array has the values [5, 4, 3, 2, 0], so only the last element is different in these 2 arrays.
from sklearn.metrics import ndcg_score
user_ndcg = ndcg_score(array([[5, 4, 3, 2, 1]]), array([[5, 4, 3, 2, 0]]))
I was expecting the result to be around 0.96233 (9.88507/10.27192). However, user_ndcg actually returned 1.0, which surprised me. Initially I thought this is due to rounding, but this is not the case because when I did an experiment on another set of array: ndcg_score(array([[5, 4, 3, 2, 1]]), array([[5, 4, 0, 2, 0]])), it correctly returned 0.98898.
Does anyone know whether this could be a bug with the sklearn ndcg_score function, or whether I was doing something wrong with my code?
I am assuming you are trying to predict six different classes for this problem (0, 1, 2, 3, 4 and 5). If you want to evaluate the ndcg for five different observations, you have to pass the function two arrays of shape (5, 6) each.
That is, you have transform your ground truth and predictions to arrays of five rows and six columns per row.
# Current form of ground truth and predictions
y_true = [5, 4, 3, 2, 1]
y_pred = [5, 4, 3, 2, 0]
# Transform ground truth to ndarray
y_true_nd = np.zeros(shape=(5, 6))
y_true_nd[np.arange(5), y_true] = 1
# Transform predictions to ndarray
y_pred_nd = np.zeros(shape=(5, 6))
y_pred_nd[np.arange(5), y_pred] = 1
# Calculate ndcg score
ndcg_score(y_true_nd, y_pred_nd)
> 0.8921866522394966
Here's what y_true_nd and y_pred_nd look like:
y_true_nd
array([[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 1., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 1., 0., 0., 0., 0.]])
y_pred_nd
array([[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 1., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[1., 0., 0., 0., 0., 0.]])

How to map element in pytorch tensor to id?

Given a tensor:
A = torch.tensor([2., 3., 4., 5., 6., 7.])
Then, give each element in A an id:
id = torch.arange(A.shape[0], dtype = torch.int) # tensor([0,1,2,3,4,5])
In other words, id of 2. in A is 0 and id of 3. in A is 1:
2. -> 0
3. -> 1
4. -> 2
5. -> 3
6. -> 4
7. -> 5
Then, I have a new tensor:
B = torch.tensor([3., 6., 6., 5., 4., 4., 4.])
In pytorch, is there any way in Pytorch to map each element in B to id?
In other words, I want to obtain tensor([1, 4, 4, 3, 2, 2, 2]), in which each element is id of the element in B.
What you ask can be done with slowly iterating the whole B matrix and checking each element of it against all elements of A and then retrieving the index of each element:
In [*]: for x in B:
...: print(torch.where(x==A)[0][0])
...:
...:
tensor(1)
tensor(4)
tensor(4)
tensor(3)
tensor(2)
tensor(2)
tensor(2)
Here I used torch.where to find all the True elements in the matrix x==A, where x take the value of each element of matrix B. This is really slow but it allows you to add some functionality to deal with cases where some elements of B do not appear in matrix A
The fast and dirty method to get what you want with linear algebra operations is:
In [*]: (B.view(-1,1) == A).int().argmax(dim=1)
Out[*]: tensor([1, 4, 4, 3, 2, 2, 2])
This trick takes advantage of the fact that argmax returns the first 'max' index of each vector in dim=1.
Big warning here, if the element does not exist in the matrix no error will be raised and the result will silently be 0 for all elements that do not exist in A.
In [*]: C = torch.tensor([100, 1000, 1, 3, 9999])
In [*]: (C.view(-1,1) == A).int().argmax(dim=1)
Out[*]: tensor([0, 0, 0, 1, 0])
I don't think there is such a function in PyTorch to map a tensor.
It seems quite unreasonable to solve this by comparing each value from B to values from B.
Here are two possible solutions to solve this problem.
Using a dictionary as a map
You can use a dictionary. Not so not much of a pure-PyTorch solution but will most probably be the fastest and safest way...
Just create a dict to map each element to an id, then use it to map B:
>>> map = {x.item(): i for i, x in enumerate(A)}
>>> torch.tensor([map[x.item()] for x in B])
tensor([1, 4, 4, 3, 2, 2, 2])
Change of basis approach
An alternative only using torch.Tensors. This will require the values you want to map - the content of A - to be integers because they will be used to index a tensor.
Encode the content of A into one-hot encodings:
>>> A_enc = torch.zeros((int(A.max())+1,)*2)
>>> A_enc[A, torch.arange(A.shape[0])] = 1
>>> A_enc
tensor([[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0.],
[1., 0., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0., 0., 1., 0., 0.]])
We'll use A_enc as our basis to map integers:
>>> v = torch.argmax(A_enc, dim=0)
tensor([0, 0, 0, 1, 2, 3, 4, 5])
Now, given an integer for instance x=3, we can encode it into a one-hot-encoding: x_enc = [0, 0, 0, 1, 0, 0, 0, 0]. Then, use v to map it. With a simple dot product you can get the mapping of x_enc: here <v/x_enc> gives 1 which is the desired result (first element of mapped-B). But instead of giving x_enc, we will compute the matrix multiplication between v and encoded-B. First encode B then compute the matrix multiplcition vxB_enc:
>>> B_enc = torch.zeros(A_enc.shape[0], B.shape[0])
>>> B_enc[B, torch.arange(B.shape[0])] = 1
>>> B_enc
tensor([[0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.],
[1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 1., 0., 0., 0.],
[0., 1., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0.]])
>>> v#B_enc.long()
tensor([1, 4, 4, 3, 2, 2, 2])
Note - you will have to define your tensors with Long type.
There is a similar issue for numpy so my answer is heavily inspired by their solution. I will compare some of the mentioned methods using perfplot. I will also generalize the problem to apply a mapping to a tensor (yours is just a specific case).
For the analysis, I will assume the mapping contains all the unique elements in the tensor and the number of elements to small and constant.
import torch
def apply(a: torch.Tensor, ids: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
mapping = {k.item(): v.item() for k, v in zip(a, ids)}
return b.clone().apply_(lambda x: mapping.__getitem__(x))
def bucketize(a: torch.Tensor, ids: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
mapping = {k.item(): v.item() for k, v in zip(a, ids)}
# From `https://stackoverflow.com/questions/13572448`.
palette, key = zip(*mapping.items())
key = torch.tensor(key)
palette = torch.tensor(palette)
index = torch.bucketize(b.ravel(), palette)
remapped = key[index].reshape(b.shape)
return remapped
def iterate(a: torch.Tensor, ids: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
mapping = {k.item(): v.item() for k, v in zip(a, ids)}
return torch.tensor([mapping[x.item()] for x in b])
def argmax(a: torch.Tensor, ids: torch.Tensor, b: torch.Tensor) -> torch.Tensor:
return (b.view(-1, 1) == a).int().argmax(dim=1)
if __name__ == "__main__":
import perfplot
a = torch.arange(2, 8)
ids = torch.arange(0, 6)
perfplot.show(
setup=lambda n: torch.randint(2, 8, (n,)),
kernels=[
lambda x: apply(a, ids, x),
lambda x: bucketize(a, ids, x),
lambda x: iterate(a, ids, x),
lambda x: argmax(a, ids, x),
],
labels=["apply", "bucketize", "iterate", "argmax"],
n_range=[2 ** k for k in range(25)],
xlabel="len(a)",
)
Running this yields the following plot:
Hence depending on the number of elements in your tensor you can pick either the argmax method (with the caveats mentioned and the restriction that you have to map the values from 0 to N), apply, or bucketize.
Now if we increase the number of elements to be mapped lets say tens of thousands i.e. a = torch.arange(2, 10002) and ids = torch.arange(0, 10000) we get the following results:
This means the speed increase of bucketize will only be visible for a larger array but still outperforms the other methods (the argmax method was killed and therefore I had to remove it).
Last, if we have a mapping that does not have all keys present in the tensor we can just update a dictionary with all unique keys:
mapping = {x.item(): x.item() for x in torch.unique(a)}
mapping.update({k.item(): v.item() for k, v in zip(a, ids)})
Now, if the unique elements you want to map is orders of magnitude larger than the array computing this may shift the value of n for when bucketize is faster than apply (since for apply you can change the mapping.__getitem__(x) for mapping.get(x, x).
I guess there is an easier way. Create an array as mapper, cast your tensor back into np.ndarray first and then address it.
import numpy as np
a_array = A.numpy().astype(int)
b_array = B.numpy().astype(int)
mapper = np.zeros(10)
for i, x in enumerate(a_array):
mapper[x] = i
out = torch.Tensor(mapper[b_array])

How to multiply torch[N,1] and torch[1,N]?

I'd like to calculate a matrix (shape[N,N]) by multiplying 2 torch vectors A(shape[N,1]) and B=A'(shape[1,N]).
When I use torch.matmul or torch.mm, I got errors or A'A(shape[1,1]).
If A is denoted as
A = [a_1, a_2, ..., a_N]', I want to calculate a matrix C whose (i,j)element is
for i in range(N):
for j in range(N):
C(i,j) = a_i * a_j
I'd like to calculate this quickly. Do you have any ideas?
thank you for your help!
If I understood you correctly you can do something like this :
A = torch.randint(0,5,(5,))
C = (A.view(1, -1) * A.view(-1, 1)).to(torch.float)
it produces :
tensor([[ 1., 4., 3., 3., 0.],
[ 4., 16., 12., 12., 0.],
[ 3., 12., 9., 9., 0.],
[ 3., 12., 9., 9., 0.],
[ 0., 0., 0., 0., 0.]])
which is equivalent to writting :
D = torch.zeros((5,5))
for i in range(5):
for j in range(5):
D[i][j] = A[i] * A[j]
which results in :
tensor([[ 1., 4., 3., 3., 0.],
[ 4., 16., 12., 12., 0.],
[ 3., 12., 9., 9., 0.],
[ 3., 12., 9., 9., 0.],
[ 0., 0., 0., 0., 0.]])
You could simply do the following:
import torch
A = torch.randint(0, 5, (3, 2))
B = torch.randint(0, 5, (2, 3))
A:
tensor([[1, 3],
[2, 1],
[1, 3]])
B:
tensor([[1, 0, 3],
[3, 4, 1]])
C = A # B # python 3.5+
C:
tensor([[10, 12, 6],
[ 5, 4, 7],
[10, 12, 6]])

Resources