1

I have a list of tuples (eigenvalue, eigenvector) from which I have to extract the first 60 eigenvectors and stack them horizontally into a matrix. I am using this code:

matrix_60 = np.hstack((eig_pairs[:60][1]).reshape(samples,1))

The code is not working properly (I understand that tuple does not have attribute reshape) but I can't figure out the correct syntax. The expected result is to get the first 60 eigenvectors and stack them column-wise (so the matrix will have N rows by 60 columns).

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
matteof93
  • 43
  • 9
  • Is the list of tuples a python list? If so, you can't slice it in the numpy way. Also, are the eigenvalues a numpy array or python list? – overfull hbox Dec 26 '18 at 16:22
  • Question has actually nothing to do with `machine-learning` - kindly do not spam the tag (removed). – desertnaut Dec 26 '18 at 16:27
  • yes it is a python list defined like this: eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i]) for i in range(len(eig_vals))] – matteof93 Dec 26 '18 at 16:36
  • Since the tuples are a mix of numbers and arrays, you should first extract the arrays with a list comprehension or map. It's straight forward to build an array from a list of arrays (provided they have same shape). – hpaulj Dec 26 '18 at 18:40

4 Answers4

2

You can use np.stack with axis=1 to stack your vectors column wise:

np.stack([vec for val, vec in eig_pairs[:60]], axis=1)

The list comprehension will extract the eigenvectors from the first 60 tuples. stack creates a new axis to concatenate along, in the dimension you indicate.

The expression eig_pairs[:60] is still a list, so eig_pairs[:60][1] is just the second tuple in that list, not the second element from each tuple. That's why you need a comprehension to extract the vectors.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
0

Maybe something like this?

np.concatenate(list(map(lambda x: x[1], eig_pairs[:60]))).reshape(-1, 60)
Fred
  • 1,462
  • 8
  • 15
0

If you have a python array of tuples called tuples of eigenvalues and vectors, you can get an array of just the eigenvectors like:

eigenvectors = [tuple[1] for tuple in tuples]

Now, you can probably just do np.array(eigenvectors).

overfull hbox
  • 747
  • 3
  • 10
  • The result will be transposed, and OP wants only the first 60. That being said, this is a good general way to approach the problem. – Mad Physicist Dec 26 '18 at 22:02
0

As @Tyler Chen observed, you can't slice a Python list of tuples with Numpy-like slicing (or at least I don't know a way). There are several ways to approach the problem:

  1. loop over the list with an index
  2. use map and itemgetter
  3. create a dictionary of the elements: dict()
  4. use zip in the list elements

Details about each in this SO answer:
How to extract the n-th elements from a list of tuples in python?

None of the examples show how this works with an array as a List/Tuple element. So, I created a simple example using the loop method (easiest for a new user to comprehend). The code above the +-+-+-+ comment creates data similar to yours (if I understand the problem statement). The code below the comment shows how I would do it. I looped on the index because I use it as the row number when adding to the array. You can also loop on the list elements, and add a row counter for that purpose (see alternate method).
This example has 10 rows and 20 values in each eigenvector. I will let you generalize for N rows and M vectors.
Note: Numpy array size is allocated in advance. So, in general you will need to scan your tuples to determine the number of rows and columns to allocate the array before the loop.

import numpy as np
# First, build some simple Eigenvalue and Eigenvector data
# 10 Eigenvalues in eig_vals and Eigenvectors as 20 values in 10 rows (shape [10,20])
eig_vals = np.logspace(0.1,3., num=10)
eig_vec = np.zeros([10,20])
for i in range(len(eig_vals)) :
  eig_vec_r = np.random.random_sample(20)
  eig_vec[i,:]=eig_vec_r
# Create List of tuples for each eig_vals, eig_vec pair: 
eigen_pairs = [(eig_vals[i], eig_vec[i,:]) for i in range(len(eig_vals)) ]
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

# create new nd.array to hold extrated Eigenvector data (shape [10,20])
saved_eig_vec = np.zeros([10,20])

# loop thru List of tuples to extract Eigenvector array and write to saved_eig_vec
# Each Eigenvector will be in 1 row
for i in range(len(eigen_pairs)) :
  saved_eig_vec[i,:] = eigen_pairs[i][1]

#Verify correctness by comparing the following values:
#  1) eig_vec[9,:] initial array created with random_sample function
#  2) eigen_pairs[9][1] -  array saved in list of tuples
#  3) saved eig_vec[9,:] array extrated and saved from list of tuples

print (eig_vec[9,:])
print (eigen_pairs[9][1])
print (saved_eig_vec[9,:])

# Alternate method, looping on list elements with row counter (reset saved_eig_vec array)
saved_eig_vec = np.zeros([10,20])
row = 0
for i in eigen_pairs :
  saved_eig_vec[row,:] = i[1]
  row += 1

print (saved_eig_vec[9,:])
kcw78
  • 7,131
  • 3
  • 12
  • 44