class_docstr: Implements the per-arm version of the MovieLens Bandit environment.
  
  This environment implements the MovieLens 100K dataset, available at:
  https://www.kaggle.com/prajitdatta/movielens-100k-dataset
  
  This dataset contains 100K ratings from 943 users on 1682 items.
  This csv list of:
  user id | item id | rating | timestamp.
  This environment computes a low-rank matrix factorization (using SVD) of the
  data matrix `A`, such that: `A ~= U * Sigma * V^T`.
  
  The environment uses the rows of `U` as global (or user) features, and the
  rows of `V` as per-arm (or movie) features.
  
  The reward of recommending movie `v` to user `u` is `u * Sigma * v^T`.
class_docstr_tok: ["Implements","the","per-arm","version","of","the","MovieLens","Bandit","environment",".","This","environment","implements","the","MovieLens","100K","dataset",",","available","at",":","https",":","\/\/www.kaggle.com\/prajitdatta\/movielens-100k-dataset","This","dataset","contains","100K","ratings","from","943","users","on","1682","items",".","This","csv","list","of",":","user","id","|","item","id","|","rating","|","timestamp",".","This","environment","computes","a","low-rank","matrix","factorization","(","using","SVD",")","of","the","data","matrix","`","A","`",",","such","that",":","`","A","~=","U","*","Sigma","*","V^T","`",".","The","environment","uses","the","rows","of","`","U","`","as","global","(","or","user",")","features",",","and","the","rows","of","`","V","`","as","per-arm","(","or","movie",")","features",".","The","reward","of","recommending","movie","`","v","`","to","user","`","u","`","is","`","u","*","Sigma","*","v^T","`","."]
code: def _observe(self):
      sampled_user_indices = np.random.randint(
          self._num_users, size=self._batch_size
      )
      self._previous_user_indices = self._current_user_indices
      self._current_user_indices = sampled_user_indices
  
      sampled_movie_indices = np.array(
          [
              random.sample(range(self._num_movies), self._num_actions)
              for _ in range(self._batch_size)
          ]
      )
      movie_index_vector = sampled_movie_indices.reshape(-1)
      flat_movie_list = self._v_hat[movie_index_vector]
      current_movies = flat_movie_list.reshape(
          [self._batch_size, self._num_actions, self._context_dim]
      )
  
      self._previous_movie_indices = self._current_movie_indices
      self._current_movie_indices = sampled_movie_indices
  
      batched_observations = {
          GLOBAL_KEY: self._u_hat[sampled_user_indices],
          PER_ARM_KEY: current_movies,
      }
      return batched_observations
  
imports: from __future__ import absolute_import
  import random
  from typing import Optional, Text
  import gin
  import numpy
  from tf_agents.bandits.environments import bandit_py_environment
  from tf_agents.bandits.environments import dataset_utilities
  from tf_agents.bandits.specs import utils
  from tf_agents.specs import array_spec
  from tf_agents.trajectories import time_step
label_desc: Use image node_id 4 for calling the MovieLensPerArmPyEnvironment obj's underlying member method code with example usage: obj._observe() and returns: batched_observations