1
\$\begingroup\$

I would like to search a list of unique values and create a dictionary with those unique values as keys, and a binary list for whether those values occur.

I have successfully solved this, but would like a more efficient solution. This solution performs a high amount of operations for a search list of size 1000, 10000, and 1000000.

This code is fully reproducible.

import numpy as np

# Create random array, len(10), of integers 1-5

array_to_search = np.array(np.random.randint(0,5,(1,10)))
array_to_search = array_to_search.flatten()

#array_to_search = [0 3 0 0 0 2 1 3 3 0]

# Extract each unique value from array_to_search

array_of_unique_values = np.unique(array_to_search)

# array_of_unique_values = [0 1 2 3]

# Create a dictionary of unique values
output = dict.fromkeys(array_of_unique_values)

# Declare lists as values to the dictionary

output = { k : [] for k in array_of_unique_values}

# For each value in unique values, search the larger list and set the dictionary
# value to a 1 if found, 0 if not found.

for i in array_of_unique_values:
    for j in array_to_search:
        if i == j:
            output[i].append(1) 
        else:
            output[i].append(0)

output = {0: [1, 0, 1, 1, 1, 0, 0, 0, 0, 1], 
          1: [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
          2: [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
          3: [0, 1, 0, 0, 0, 0, 0, 1, 1, 0]}
\$\endgroup\$
  • 2
    \$\begingroup\$ You could write {i:array_to_search == i for i in np.unique(array_to_search)}, but why do you need this? It seems wasteful to allocate all these arrays of Booleans when you could just write array_to_search == i when you need one of them. Please tell us more about your real problem — if we knew more about it, we might be able to spot a better approach. \$\endgroup\$ – Gareth Rees Feb 8 '18 at 19:49
1
\$\begingroup\$

== with broadcasting is the most straightforward solution:

array_to_search = np.array(np.random.randint(0,5,(1,10))).ravel()
array_of_unique_values = np.unique(array_to_search)

# Creates the binary vectors
matches = array_of_unique_values[:, None] == array_to_search

# Converts to dict
output = dict(zip(array_of_unique_values, matches))

You can also set return_indices flag to True in np.unique and use these to create the table:

array_to_search = np.array(np.random.randint(0,5,(1,10))).ravel()
array_of_unique_values, indices = np.unique(array_to_search, return_inverse=True)
matches = np.zeros((array_of_unique_values.size, array_to_search.size), dtype=bool)
matches[indices, np.arange(array_to_search.size)] = True
output = dict(zip(array_of_unique_values, matches))
\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit it to explain your reasoning (how your solution works and how it improves upon the original) so that everyone can learn from your thought process. \$\endgroup\$ – Toby Speight Feb 16 '18 at 15:53
-1
\$\begingroup\$

If you put it in a Pandas Series, then you can use get_dummies to get a DataFrame containing the data you want. If you want it as a dictionary of lists, then you can just convert it with output = {col:list(df[col]) for col in df.columns}

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.