Reducing spurious transitions

At the end of the activity recognition pipeline, we want to make sure that the classifications are not too volatile, that is, we don't want activities to change every millisecond. A basic approach is to design a filter that ignores quick changes in the activity sequence.

We build a filter that remembers the last window activities and returns the most frequent one. If there are multiple activities with the same score, it returns the most recent one.

First, we create a new SpuriousActivityRemoval class, which will hold a list of activities and the window parameter:

class SpuriousActivityRemoval{ 
   
  List<Object> last; 
  int window; 
   
  public SpuriousActivityRemoval(int window){ 
    this.last = new ArrayList<Object>(); 
    this.window = window; 
  } 

Next, we create the Object filter(Object) method, which will take an activity and return a filtered activity. The method first checks whether we have enough observations. If not, it simply stores the observation and returns the same value, as shown in the following code:

  public Object filter(Object obj){ 
    if(last.size() < window){ 
      last.add(obj); 
      return obj; 
  } 

If we already collected window observations, we simply return the most frequent observation, remove the oldest observation, and insert the new observation:

    Object o = getMostFrequentElement(last); 
    last.add(obj); 
    last.remove(0); 
    return o; 
  } 

What is missing here is a function that returns the most frequent element from a list of objects. We implement this with a hash map, as follows:

  private Object getMostFrequentElement(List<Object> list){ 
     
    HashMap<String, Integer> objectCounts = new HashMap<String, 
Integer>(); Integer frequntCount = 0; Object frequentObject = null;

Now, we iterate over all the elements in the list, insert each unique element into a hash map, or update its counter if it is already in the hash map. At the end of the loop, we store the most frequent element that we found so far, as follows:

    for(Object obj : list){ 
      String key = obj.toString(); 
      Integer count = objectCounts.get(key); 
      if(count == null){ 
        count = 0; 
      } 
      objectCounts.put(key, ++count); 
       
      if(count >= frequntCount){ 
        frequntCount = count; 
        frequentObject = obj; 
      } 
    } 
     
    return frequentObject; 
  } 
   
} 

Let's run a simple example:

String[] activities = new String[]{"Walk", "Walk", "Walk", "Run", 
"Walk", "Run", "Run", "Sit", "Sit", "Sit"}; SpuriousActivityRemoval dlpFilter = new
SpuriousActivityRemoval(3); for(String str : activities){ System.out.println(str +" -> "+ dlpFilter.filter(str)); }

The example outputs the following activities:

    Walk -> Walk
    Walk -> Walk
    Walk -> Walk
    Run -> Walk
    Walk -> Walk
    Run -> Walk
    Run -> Run
    Sit -> Run
    Sit -> Run
    Sit -> Sit

The result is a continuous sequence of activities, that is, we do not have quick changes. This adds some delay, but unless this is absolutely critical for the application, it is acceptable.

Activity recognition may be enhanced by appending n previous activities, as recognized by the classifier, to the feature vector. The danger of appending previous activities is that the machine learning algorithm may learn that the current activity is always the same as the previous one, as this will often be the case. The problem may be solved by having two classifiers, A and B: classifier B's attribute vector contains n previous activities as recognized by classifier A. Classifier A's attribute vector does not contain any previous activities. This way, even if B gives a lot of weight to the previous activities, the previous activities as recognized by A will change as A is not burdened with B's inertia.

All that remains to do is to embed the classifier and filter it into our mobile application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.239.182