Affine transformation - graphics
I am trying to solve the below problem. I don't have much knowledge in Affine transformations. Could someone help me answer this question:
Find a 3x3 matrix representing a 2D affine transformation of homogeneous coordinates (i.e. every point [x,y] is represented as a column vector [x, y, 1]), which transforms a square [0,0],[1,0],[1,1],[0,1] into a parallelogram [0,1],[1,1],[2,2],[1,2].
Things I spotted about this question
1) You need to understand homogeneous co-ordinates
2) You need to know the difference between row and column major - read here
3) You need to know the basic affine transformations - rotate, scale/shear and translate and how to represent them in a matrix - read this page
Interestingly, I think the answer only needs a translate and a shear ( no rotation ).
Looking at the source and dest points, it looks like all dest points are translated +1 in y and sheared by 1 in X ( to give the parallelogram, probably best to draw it out to see what I mean )
So start with a 3 * 3 identity matrix which is
1 0 0
0 1 0
0 0 1
The shear will be
1 1 0
0 1 0
0 0 1
The translate will be
1 0 0
0 1 1
0 0 1
So putting it all together should be
1 1 0
0 1 1
0 0 1
I don't normally use column major so probably worth double checking!
Hope that helps
An affine transformation is a transformation of the form x ⟼ Ax + b, where x and b are vectors, and A is a square matrix. Geometrically, affine transformations map parallelograms to parallelograms and preserve relative distances along lines.
To solve a problem like this, we first note that for the origin, we have 0 ⟼ A0 + b = b. Since the problem tells us that [0,0] ⟼ [0,1], we know that b = [0,1].
Next we recall from linear algebra that multiplying a matrix by the standard basis vectors [0,1] and [1,0] simply extracts the first and second columns of the matrix, respectively:
[a b] [1] = [a], [a b] [0] = [b].
[c d] [0] [c] [c d] [1] [d]
We are given that [1,0] ⟼ [1,1] and [0,1] ⟼ [1,2]. From this we obtain
[1,1] = A[1,0] + b = [a,c] + [0,1] ⟹ [a,c] = [1,0],
[1,2] = A[0,1] + b = [b,d] + [0,1] ⟹ [b,d] = [1,1].
This gives us our affine transformation
Ax + b = [1 1] x + [0].
[0 1] [1]
Homogeneous coordinates are a trick which let us write affine transformations as matrices, just with one extra coordinate that is always set to 1. The matrix formula is
[A b] [x] = [Ax+b].
[0 1] [1] [ 1]
Here A is actually a 2×2 matrix, while b and x are 2-vectors, and the 0 in the bottom left is really [0 0]. So overall, we are dealing with a 3×3 matrix and 3-vectors.
So our solution is
[1 1 0]
[0 1 1],
[0 0 1]
and for good measure we check that it works properly for the final point:
[1 1 0] [1] [2]
[0 1 1] [1] = [2].
[0 0 1] [1] [1]
You'll have read the Wikipedia page on the subject, of course.
Once upon an aeon or so ago, I read Foley and van Dam in one of the predecessor versions (this would have been 1983 or 1984), and it covered techniques for manipulating 2D and 3D coordinates with augmented matrices and vectors as described in the question. However, enough time has lapsed since then that I've forgotten all the details (and no longer have the book--too many moves of house). There was also a book by Newman and Sproul, I seem to remember.
A = [ a b c ] B = [ 0 1 1 0 ] C = [ 0 1 2 1 ]
[ d e f ] [ 0 0 1 1 ] [ 1 1 2 2 ]
[ g h 1 ] [ 1 1 1 1 ] [ 1 1 1 1 ]
The columns of B represent the corners of the square; the columns of C represent the corners of the parallelogram; and the matrix equation A x B = C has to be solved. IIRC, the matrix A has a 1 in the bottom right corner; it is possible that the values c, f, g, and h also have presecribed values (they'd probably be zeroes). The non-zero values apply a linear (affine) transform, scaling, shearing and rotating the input shape.
You'd need to look for similar information in a text book. Or in the Wiki page - I didn't look hard at it (the information above is working from ancient memory).
I just wanted to point out that four points over constrain a 2D affine transformation. In the comment of Jonathan Leffler, you can see this from the fact that you would need to invert a non-square matrix. So, either choose three of the points or set up a least-squares system. The over-constrained, least-squares solution could be solved with the following matrices
A = [ a b c ] B = [ 0 1 1 0 ] C = [ 0 1 2 1 ]
[ d e f ] [ 0 0 1 1 ] [ 1 1 2 2 ]
[ g h 1 ] [ 1 1 1 1 ] [ 1 1 1 1 ]
so that solving using the normal equations gives
A B = C
(A B)^T = B^T A^T = C^T
B B^T A^T = B C^T
A^T = (B B^T)^-1 B C^T
undoing that transpose gives
A = ((B B^T)^-1 B C^T)^T
Related
Inverse X.toarray into a CountVectorizer in sklearn
I'm following documentation here: https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html >>> from sklearn.feature_extraction.text import CountVectorizer >>> corpus = [ ... 'This is the first document.', ... 'This document is the second document.', ... 'And this is the third one.', ... 'Is this the first document?', ... ] >>> vectorizer = CountVectorizer() >>> X = vectorizer.fit_transform(corpus) >>> print(vectorizer.get_feature_names()) ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this'] >>> print(X.toarray()) [[0 1 1 1 0 0 1 0 1] [0 2 0 1 0 1 1 0 1] [1 0 0 1 1 0 1 1 1] [0 1 1 1 0 0 1 0 1]] Suppose I already have a term frequency matrix like the one given in X.toarray(), but I didn't use CountVectorizer to obtain it. I want to apply a TfIDF to this matrix. Is there a way for me to take a count array + a dictionary and apply some inverse of this function as a constructor to get a fit_transformed X? I'm looking for... >>> print(X.toarray()) [[0 1 1 1 0 0 1 0 1] [0 2 0 1 0 1 1 0 1] [1 0 0 1 1 0 1 1 1] [0 1 1 1 0 0 1 0 1]] >>> V = CountVectorizerConstructorPrime(array=(X.toarray()), vocabulary=['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']) such that: >>> V == X True
The X constructed by the CountVectorizer is a sparse matrix in SciPy's compressed sparse row (csr) format. So you can construct it directly from any word count matrix with the appropriate SciPy function: from scipy.sparse import csr_matrix V = csr_matrix(X.toarray()) Now V and X are equal, although this may not be obvious, because V == X will give you another sparse matrix (or rather complain that the matrix is not sparse despite the intended format, see this question). But you can check it like this: (V != X).toarray().any() False Note that the word list was not needed, because the matrix only encodes the frequencies of all distinct words, no matter what they are.
Python 3.6 adjacency Matrix: How to obtain it in a better way
The problem starts with a classical csv file. An example can be: date;origing;destiny;minutes;distance 19-02-2020;A;B;36;4 20-02-2020;A;B;33;4 24-02-2020;B;A;37;4 25-02-2020;A;C;20;7 27-02-2020;C;B;20;3 28-02-2020;A;B;37.2;4 28-02-2020;A;Z;44;10 My first idea consist in solving it in a classical programmaing way: Loop + counter variables and represent de counter variables in a matrix like: A B C Z A 0 3 1 1 B 1 0 0 0 C 0 1 0 0 Z 0 0 0 0 My first question is if there is a better automatic way of implementing this in python instead os use classical programming algorithm based on loops and counters. and what about obtaining more complex adjacence matrixes like the one that give you for example and average of times in the values?
There are packages like networkx, but you could use the groupby of pandas. I don't think pandas with groupby is the fastest. I think networkx would be faster, but at least groupby is better than a loop (is my guess). import pandas as pd import numpy as np M = pd.read_csv('../sample_data.csv', sep=';') M['constant'] = 1 print(M) date origing destiny minutes distance constant 0 19-02-2020 A B 36.0 4 1 1 20-02-2020 A B 33.0 4 1 2 24-02-2020 B A 37.0 4 1 3 25-02-2020 A C 20.0 7 1 4 27-02-2020 C B 20.0 3 1 5 28-02-2020 A B 37.2 4 1 6 28-02-2020 A Z 44.0 10 1 With groupby we can get counts; counts = M.groupby(['origing','destiny']).count()[['constant']] counts constant origing destiny A B 3 C 1 Z 1 B A 1 C B 1 And store those values in a zero matrix def key_map(key): a,b = key return (ord(a) - ord('A'),ord(b)-ord('A')) will get the indicis, like counts['constant'].keys().map(key_map).values and we set those indicis to any values, i do the counts here, but you can use the same groupby to aggregate sum,average, or anything from other columns; indici = np.array( [tuple(x) for x in counts['constant'].keys().map(key_map).values] ) indici = tuple(zip(*indici)) and store with Z = np.zeros((26,26)) Z[ indici ] = counts['constant'] I only print first few with print(Z[:3,:3]) [[0. 3. 1.] [1. 0. 0.] [0. 1. 0.]]
How to calculate by rows in J
For example, there are two 164*90 matrixes and a function. beta=: 4 : 0 a=. x cor y b=. sd x c=. sd y a*b%c ) I want to use each row of matrix 1 and each row of matrix 2 into the function. How can I do it at once?
beta=: 4 : 0"1 a=. x cor y b=. sd x c=. sd y a*b%c ) The "1 after the 0 in the definition above makes your verb rank 1 which means that it would take whatever matrices it is given a row at a time. An alternative would be to call your originally defined verb with rank "1 x beta"1 y
All list items up to, and including, the first repeated item
Consider: x =. 0 1 2 3 4 1 3 4 99 v =. [ {.~ (>: # i.&1 # (##~. = #\)) v x NB. => 0 1 2 3 4 1 The behavior is correct. But as you can see, v is shamefully verbose. Is there a better solution?
You want the monad ~: (nub sieve): v =: {.~ 1 + 0 i.~ ~: x =: 0 1 2 3 4 1 3 4 99 v x 0 1 2 3 4 1 Code review: Outside code-golf contexts, don't use #\ in place of i.##. It's too cutesy, hard to maintain, and won't be recognized by the special-code optimizer. Don't assign to the names x, y, u, v, m, or n (except in special circumstances, and always locally in an explicit context).
Spliting a comma delimitted string into several columns and asigning 0 to nospace
In my data.frame a vector x containing text strings (with six values (from 0 to 100) separated by comma inside each string) in this format: x[1] "3,2,4,34,2,9" x[2] "45,,67,,," x[3] ",,,,99," Here is the link to the actual vector I am having problems with: x.cvs x.cvs Unfortunately, the value of "0" is recorded as "an empty no space" between the two commas, or before the first comma, or after the last comma. It would be great first to be able to transform it into: x[1] "3,2,4,34,2,9" x[2] "45,0,67,0,0,0" x[3] "0,0,0,0,99,0" But most importantly, I would like to split this vector into 6 different vectors x1, x2, x3, x4, x5, x6 and each of them to take the value from the string, and replace "no space" between commas with "0", for example, the result should be: x1[3] 0 x6[2] 0 I think the strsplit() would have worked if there has been a value between commas, but since there is no value, not even an empty space, I am not sure what is the right way to proceed, without getting NAs. I tried the following, but it does give me a lot of errors: x<- as.character(x) x <- gsub(",,", ",0,", x) x <- gsub(", ,", ",0,", x) splitx = do.call("rbind", (strsplit(x, ","))) splitx = data.frame(apply(splitx, 2, as.numeric)) names(splitx) = paste("x", 1:6, sep = "") I get errors... In rbind(c("51", "59", "59", "60", "51", "51"), c("51", "59", "59", : number of columns of result is not a multiple of vector length (arg 10994) In apply(splitx, 2, as.numeric) : NAs introduced by coercion
Here are two alternatives to consider, depending on what you are actually expecting as your output. The first option outputs a set of vectors, but I find that to be a little bit unnecessary and can quickly litter your workspace with lots of objects. The second option, which I prefer, creates a convenient data.frame with each row representing one of the items from your vector "x". Sample Data x <- vector() x[1] <- "3,2,4,34,2,9" x[2] <- "45,,67,,," x[3] <- ",,,,99," Option 1 Names <- paste0("A", seq_along(x)) for (i in seq_along(x)) { assign(Names[i], {Z <- scan(text=x[i], sep=","); Z[is.na(Z)] <- 0; Z}) } A1 # [1] 3 2 4 34 2 9 A2 # [1] 45 0 67 0 0 0 A3 # [1] 0 0 0 0 99 0 Option 2 Z <- read.csv(text = x, header = FALSE) Z[is.na(Z)] <- 0 Z # V1 V2 V3 V4 V5 V6 # 1 3 2 4 34 2 9 # 2 45 0 67 0 0 0 # 3 0 0 0 0 99 0 Extracting values from a data.frame is as easy as specifying the desired rows and columns. Z[1, 3] # [1] 4 Z[2, 4] # [1] 0 Z[3, c(1, 3, 5)] # V1 V3 V5 # 3 0 0 99