Archive for April, 2010


As developers, we try our best to create the best products we can.  We really do.  Yes, I know that some features get pushed to the back burner when releases are behind schedule or some bugs get kludged and we hedge our bets on whether the user will hit them or not.  However, for the most part, we do what makes the application look the best.  I mean why not – we are type A personalities after all (usually).

So, it really bugs (read: annoys) me when users criticize the application that they are using without providing any helpful feed back, what they don’t like or even what went wrong!  Help us help you – we can’t do anything unless you provide us some information.  We aren’t expecting you to debug the application yourself or even send us crash logs – just a general, accurate description of the problem.  However, don’t think that the responsibility is completely on the consumer.  Developers have to at least attempt to easily facilitate the collection of this information.

The good example the Apple App store.  For those of you who aren’t familiar with the rating systems on there, you can rate the app after you download it with a 1-5 star designation.  You also can enter a comment along with your rating.  If you break down what kind of reviews people leave, there are several main categories: 1) the faithful user who expounds the virtues of the application and leaves a glowing review, 2) an impossible to please user that will give your app a 3 star rating for giving the old “college try” (i.e. “This app is good but would be better if it had “x, y and z” feature) 3) a user that leaves a good comment, but poor star rating or vice versa 4) a user that reports bugs and gives a low star rating (i.e. “I updated the app and every time I attempt to launch it, the app crashes!  please fix!!!!” and 5) the type of user who’s review consists of no helpful information and a low rating (i.e “this app sucks” or “the worst application ever”)

To give you an idea of how broken the system is, here is a small sampling of some of the typical reviews found from the 5 categories above.  Note: These comments are taken in the original form and have not been edited.

  • “You get what you pay for.  A BIG FAT ZERO.  WHAT A JOKE.” (1 star)
  • “This app is garbage.” (1 star)
  • “Pure crap.  Sorry devs, but this is bad.” (1 star)
  • “The best app ever.” (5 stars)
  • “A great way to save money.” (1 star)
  • “I love the idea. But every time load the app it thinks for 30 seconds and returns to the home screen.  Good luck guys!.” (3 stars)

If you browse the comments for any given app, you can see they are all over the place.  Let me clear however – good apps deserve good ratings and bad apps deserve bad ratings.  However, you are able to rate apps without even downloading them to try them.  As proof of how ridiculous this is, the night before the iPad launched, iTunes users were able to go to the iTunes app store and download iPad apps.  Now, absolutely no one had an iPad to test the applications with, however the ratings were still pouring in.  How could end users possibly evaluate the application without even running?

Another part of the system that is broken is that the only time that the iPhone prompts you to rate applications is when you delete them off your phone.  Typically, if you’re deleting something, something went horribly, horribly wrong (i.e. the application crashes all the time, won’t run, you don’t have a use for it anymore).  At this point, the user’s rating will most likely be negative, which will end up affecting the rating of your application.

Lastly, there is no way to disable ratings, edit ratings or reset ratings.  The only way they get “reset” is if you release a new version, but even then the previous ratings don’t disappear – the iTunes App store only separates the ratings into “This version” and “Previous versions.”  I am not saying that you should be able to “hide” the previously poor versions, but they shouldn’t affect the overall rating because every piece of software has known and unknown bugs.  The “overall” rating is the lifetime rating of the application.  Anyone who understands statistics averages fairly well knows that once you get some bad ratings that bring your overall rating down, it takes a LOT more ratings to improve the average.  For example, suppose we had 10,000 ratings that gave us an overall of 2.5/5 stars.  It would require another 5,000 5-star ratings to raise the app rating 1/2 star to 3/5 stars.  It only takes longer to raise your rating with additional lower ratings.  This is stacked against the developer and isn’t fair.

So how can we improve the process so that both the consumer and the developer is satisfied, where the consumer gets to voice their opinion and the developer gets to fix the product. First of all, lets remove the functionality that allows someone to rate an app as they are removing it.  Let’s also can the the ability to rate apps without even downloading them.  If we were able to prompt the user for a rating after they had used the app n times or after some total accumulated usage time t (tracked by iTunes) then we might get a far more unbiased opinion.  After meeting these requirements, we could then unlock the ability to rate the app or iTunes could even prompt us for our thoughts (similar to how Amazon and eBay do after you’ve placed an order and they follow up with you to check on the service).

Another idea is that even though this might deter a few people from leaving ratings, good AND bad, have a required comment field that would allow someone to elaborate on why an app deserves a particular rating.  If the user can’t take the 2 minutes to fill out a simple rating form, then they can’t be too serious about rating the application.  This could even be taken one step further by allowing the Apple or the developer to create a questionnaire with different fields depending on the rating.  eBay has a very good of example of this by listing categories of behavoirs that are encouraged. In the same vein, you could also introduce categories.  Obviously this last addition is probably overkill because it is more complicated to implement.

Lastly, it might be helpful to have a rating system within a rating system where other users could click a “thumbs up” or “thumbs down” to indicate whether another user’s review was particularly helpful or completely off base.

While no rating system is absolutely perfect, we want to get the best information possible about a potential purchase. While a rating system should be easy for the user to express their opinion, it shouldn’t be so simple as to give them all the power or reduce the rating to a simple binary “Good” or “Bad” rating.

Of course, the other alternative to all this is that, we as developers could just produce bug-free software the first time we have a app release.

I recently came across a problem of needing to create incremental backups to a remote site for my server in the case of a failure. Since my VPS provider didn’t provide this as a service (paid or free), I had to come up with a different solution. This solution assumes that you are using Ubuntu (in my case, Karmic Koala), root access and an Amazon S3 account.  Also, this assumes that you are willing to spend the money to back up to S3.  The pricing structure is here, but in my experience, my initial backup cost $3.78 and since then, my average monthly bill has been < $0.25.  You can calculate your own bill with this handy Amazon S3 S3/EC2 calculator.

I know that using FUSE is not the fastest method of backing up, so you’re mileage may vary depending on your tolerance levels and needs.  The actual download site for FuseOverAmazon is here.  Also, I am using rsync because I believe that incremental (differential) backups are far more efficient and cost/time saving than full backups every week.

1.  The first step is to install all the dependencies we’ll need for FUSE:

sudo apt-get install build-essential libcurl4-openssl-dev libxml2-dev libfuse-dev

Next, install the most recent version of s3fs. As of now the most recent is r191, but here is a link to the downloads section so that you can check to see which version is the most up-to-date. I chose to put my src download in /usr/local/src.

wget http://s3fs.googlecode.com/files/s3fs-r191-source.tar.gz
tar -xzf s3fs*
cd s3fs
make
sudo make install
sudo mkdir /backup/s3
sudo chown yourusername:yourusername /backup/s3

2. Scripting your backup plan:

You’ll need to create a bucket on the S3 cloud.  If you haven’t done this already, you can use an online tool like JetS3t (my favorite).  I would recommend that you create a separate bucket for each logical site you are going to backup.  For example, I backup each one of my repositories in Unfuddle in a different bucket.  That makes restoring easier.  You might also want to consider replicating to multiple locations, if you don’t trust that Amazon can keep your data safe or even use a separate service provider like JungleDisk, Mozy or Backblaze.

Using gvim or TextMate (or some other text editor), we are going to automate mounting the volume, perform a sync and unmount the volume.  The reason I unmount is for safety.  If somehow the hard disk becomes corrupted, I have a bit of time to prevent the script from running and replicating the bad data.  If the volume is constantly mounted, that may not be the case.  It is also easy to wipe out the volume if you aren’t careful.

The following will be the script in your backup script, s3fs-backup.sh (or whatever you name yours):

#!/bin/bash

/usr/bin/s3fs yourbucket -o accessKeyId=yourS3key -o secretAccessKey=yourS3secretkey /mnt/s3
/usr/bin/rsync -avz --delete /home/username/dir/you/want/to/backup /mnt/s3
/usr/bin/rsync -avz --log-file=log.file --delete --exclude /sys --exclude /mnt --exclude /proc --exclude /tmp / /mnt/s3 #exclude some directories
mail -s "backup complete with log" user@host.org &lt; log.file #email yourself the log
mv log.file log.file.`date +"%Y%m%d%H%M%S"` # move the file to a log with a datetime stamp
/bin/umount /mnt/s3

There some directories that I don’t want to backup, one being proc, because the that directory is manged by the OS while the system is running. You don’t want to restore this directory. Also, even though rsync is smart enough to recognize cycles, we don’t want to backup our /mnt/s3 directory. We exclude those here. Note, the –delete option. This will delete any files that have been removed on the ’source’. Lastly, note that we can increase/decrease the verbosity of the script and email ourselves a transcript of the backup session so we know that it actually took place – not a bad way to keep tabs.  After we are finished emailing ourselves (the potentially massive log file), we rename it to keep track of our backups on the server as well. There are many more options with rsync, so check out the man pages for the command to customize your script.

chmod 755 s3fs-backup.sh

Before you run the entire script, you might want to use the line above to change the permissions on the script you just saved.  You can verify the integrity of the script by running each command individually, which isn’t a bad idea after editing it for your own situation because mistakes do happen.  A quick check after the S3 volume (df -h) is mounted will show 256T available for your own personal use.

The most important part is automating the backup process.  If you forget and you lose your most recent data, then what was the point!?  We are going to use good ol’ fashioned *nix cron daemon to handle this process for us. There are two options for creating your crontab.  You can either put this script (or a softlink) to it in your cron.hourly, cron.daily, cron.weekly, cron.monthly folder or you can directly edit the crontab file to have more control over when the script runs.  I personally run mine every hour and every week on Sunday.  Here is a nice cron reference to customize your schedule.

crontab -e
* * * * * /path/to/s3fs.sh # this runs it hourly
0 0 0 0 0 /path/to/s3fs.sh # this runs it every week on sunday

A note about speed: The initial backup could take a long time.  The server up-stream speed is the limiting factor on how long this takes.  While rsync is a great program, using FUSE is not the speediest option in the world. There is another solution out there called ‘s3sync.’

To run the script initially and create your first back-up (if you can’t wait), simply run this command: sudo ./s3fs.sh.

One last nice thing is that this can be adapted to run anywhere, other servers, your home computers, etc.  If you can install Ruby and the dependencies above, you can have ultra cheap backups without a lot of hassle.

That’s it!

Abstract—Recommendation systems take artifacts about items and provide suggestions to the user on what other products the might like. There are many different types of recommender algorithms, including nearest-neighbor, linear classifiers and SVMs. However, most recommender systems are collaborative systems that rely on users to rate the products that they bought. This paper presents a analysis of recommender systems using a mobile device and backend data points for a coupon delivery system.

Index Terms—machine learning, recommender systems, supervised learning, nearest neighbor, classification

1. INTRODUCTION

Recommendations are a part of everyday life. An individual constantly receives recommendations from friends, family, salespeople and Internet resources, such as online reviews. We want to make the most informed choices possible about decisions in our daily life. For example, when buying a flat screen TV, we want to have the best resolution, size and refresh rate for the money. There are many factors that influence our decisions – budget, time, product features and most importantly, previous experience. We can analyze all the factors that led up to the decision and then make a conclusion or decision based on those results. A recommender system uses historical data to recommend new items that may of be interest to a particular user.

Coupious is a mobile phone application that gives it’s user coupons and deals for businesses around their geographic location. The application runs on the user’s cell phone and automatically retrieves coupons based upon GPS coordinates. Redemption of these coupons is as simple as tapping a “Use Now” button. Coupious’ services is now available on the iPhone, iPod Touch, and Android platforms. Coupious is currently available in Minneapolis, MN, West Lafayette, IN at Purdue University and Berkley, CA. Clip Mobile is the Canada based version of Coupious that is currently available in Toronto.

Using push technology, it is possible to integrate a mobile recommendation system into Coupious. The benefit of this would be threefold: 1) offer the customers the best possible coupons based on their personal spending habits – if a user feels they received a “good deal” with Coupious, they would be more likely to use it again and integrate it into their bargain shopping strategy, 2) offer businesses the ability to capitalize on their market demographics – the ability to reach individual customers to provide goods or services would drive home more revenue and add value to the product and 3) adding coupons to the service would immediately make the system more useful to a user as it would present, desirable, geographically proximate offers without extraneous offers.

1.1 OUTLINE OF RESEARCH

In this research project, we evaluated the batch k-nearest neighbors algorithm in Java. We chose to write the implementation of the decision tree in Java because of the ease of use of the language. Java also presented superior capabilities in working with and parsing data from files. Using Java allowed the author to more efficiently model the problem through the use of OO concepts, such as polymorphism and inheritance. The kNN algorithm was originally suggested by Donald Knuth in [9] where it was referenced as the post-office problem, where one would want to assign residences to the nearest post office.

The goal of this research was to find a solution that we felt would be successful in achieving the highest rate of coupon redemption. Presumptively, in achieving the highest rate of redemption required learning what the user likes with the smallest error percentage. Additionally, we wanted to know if increasing the attributes used for computation, would effect the quality of the result set.

1.2 DATA

The data that we used is from the Coupious production database. Currently, there are approximately 70,000 rows of data (“nearby” queries, impressions and details impressions) and approximately 3,400 of those represent actual coupon redemptions. The data is an aggregate from March 25th, 2009 until February 11, 2010. The results are from a mixture of different cities where Coupious is currently in production.

From a logical standpoint, Coupious is simply a conduit through which a user may earn his discount and has no vested interest in whether or not a user redeems a coupon in a particular session. However, from a business standpoint, Coupious markets the product based on being able to entice sales through coupon redemption. Therefore, for classification purposes, sessions that ended in one or more redemptions will be labeled +1 and sessions that ended without redemption will be labeled -1.

1.3 PREVIOUS WORK

While there hasn’t been any previous work in the space of mobile recommendation systems, there has been a large amount of work in the recommender systems space and classification. In [1], [2] and [3], direct marketing is studied using collaborative filtering. In [3], the authors use SVMs and latent class models to model predictions of whether or not a customer would be likely to buy a particular product. The most direct comparison of work would be in [1] and [8], where SVMs and linear classifiers are used to cluster content driven recommender systems.

2. APPLICATION

Broadly, recommender systems can be grouped into two categories, content-based and collaborative based. In content-based systems, the recommendations are based solely on the attributes of the actual product. For example, in Coupious, attributes of a particular coupon redemption includes the distance from the merchant when the coupon was used, the date and time of the redemption, the category of the coupon, the expiry and the offer text. These attributes are physical characteristics of the coupon. Recommendations can be made to users without relying on any experience-based information.

In collaboration systems, recommendations are provided based on not only product attributes but the overlap of preferences of “like-minded” people, first introduced by Goldberg et. al [5]. For example, a user is asked to rate how well they liked the product or give an opinion of a movie. This provides the algorithm a base line of preference for a particular user, which allows the algorithm to associate product attributes with a positive or negative response. Since Coupious does not ask for user ratings, this paper will focus exclusively on content-based applications.

Many content-based systems have similar or common attributes. As stated in [3], the “central problem of content-based recommendation is identifying a sufficiently large set of key attributes.” If the attribute set is too small, there may not be enough information for the program to build a profile of the user. Conversely, if there are too many attributes, the program won’t be able to identify the truly influential attributes, which leads to poor performance [6]. Also, while the label for a particular feature vector with Coupious data is +1 or -1, many of the features in the data are multi-valued attributes (such as distance, date-time stamps, etc.), which maybe hard to represent in a binary manner, if the algorithm requires it.

In feature selection, we are “interested in finding k of the d dimensions that give us the most information and accuracy and we discard the other (d – k) dimensions [4].” How can we find the attributes that will give us the most information and accuracy? For Coupious, the attribute set is quite limited. For this research, we explicitly decided the features that will contribute to our recommendations. In all cases, all attributes were under consideration while the algorithm was running and we never partitioned the attributes for different runs to create different recommendations.

2.1 THE kNN ALGORITHM

As shown in [7], “Once the clustering is complete, performance can be very good, since the size of the group that must be analyzed is much smaller.” The nearest neighbor algorithm is such a classification algorithm. K-nearest neighbors is one of the simplest machine learning algorithms, where an instance is classified by a majority vote by the closest training examples in the hypothesis space. This algorithm is an example of instance-based learning, where previous data points are stored and interpolations is performed to find a recommendation. An important distinction to make is that kNN does not try to create a model when it are given test data, but rather performs the computation when tested. The algorithm works by attempting to find a previously seen data point that is “closest” to the query data point and then uses its previous output for prediction. The algorithm calculates its approximation using this definition:

The algorithm is shown below

KNN (Examples, Target_Instance)

  • Determine the parameter K = number of nearest neighbors.
  • Calculate the distance between Target_Instance and all the Examples based on the Euclidian distance.
  • Sort the distance and determine nearest neighbor based on the Kth minimum distance.
  • Gather the Category Y of the nearest neighbors.
  • Use simple majority of the category of nearest neighbors as the prediction value of the Target_Instance.
  • Return classification of Target_Instance.

This algorithm lends itself well to the Coupious application. When a user uses the Coupious application, they want it to launch quickly and present a list of coupons within 10-15 seconds. Since this algorithm is so simple, we are able to calculate coupons that the user might enjoy fairly quickly and deliver them to the handset. Also, because Coupious doesn’t know any personal details about the user, the ability to cluster users into groups without the need for any heavy additional implementation on the front or back ends of the application is advantageous.

There are several possible problems with this approach. While this is a simple algorithm, it doesn’t take high feature dimensionality into account. If there are many features, the algorithm will have to perform a lot of computations to create the clusters. Additionally, each attribute is given the same degree of influence on the recommendation. In Coupious, the date and time the coupon was redeemed has the same amount of bearing on the recommendation as does the current distance from the offer and previous redemption history. The features may not scale compared to their importance and the performance of the recommendation may be degraded by irrelevant features. Lastly, [6] describes the curse of dimensionality, which describes how, if a product has 20 attributes, 2 of which are actually useful, how classification may be completely different when considering each of the 20 attributes but identical when only considering the 2 relevant attributes.

2.2 ATTRIBUTE SELECTION

While implementing the k-nearest neighbors algorithm, we decided to evaluate instances based upon seven different attributes, including coupon category, distance, expiration, offer, redemption date, handset and handset operating system, and upon the session result, a “hit” or “redemption.” The offer and expiration attributes required extra processing before they were able to be used for clustering. In both of these attributes, a “bag of words” (applying a Naive Bayes classifier to text to determine the classification) implementation was used to determine what type of offer the coupon had made.

For the OFFER attribute, we split the value space into 4 discrete values, PAYFORFREE (an instance where the customer had to pay some initial amount to receive a free item), PERCENTAGE (an instance where the customer received some percentage discount), DOLLAR (an instance where a customer received a dollar amount discount) and UNKNOWN (an instance where the classification was unknown). While the PERCENTAGE and DOLLAR values essentially compute to the exact same values when calculated, consumers tend to react differently when seeing higher percentage discounts versus dollar discounts (i.e. 50% off instead of $5 discount, even though they may equate to an identical discount, if the price were $10).

For the expiration attribute, some text parsing was done to determine what type of expiration the coupon had (DATE, USES, NONE or UNKNOWN). If the parsing detected a date format, we used DATE and if the parsing detected that it was a limited usage coupon (either limited by total uses across a population, herein known as “global” or limited by uses per customer, herein known as “local”), we designated that the coupon was USES. If the coupon was valid indefinitely, we designated that the coupon expiration was NONE. We did not record the distance of dates in the future, by the type of limited usage (global or local) or by the number of uses left.

An important detail to note is that in our implementation of kNN, if an attribute was unknown, we declined using it for computation of the nearest neighbor because the UNKNOWN attribute was typically the last value in a Java enumeration and therefore would be assigned a high integer value which would skew the results unnecessarily if used for computation.

For the remaining attributes (OFFERTIME, CATEGORY, DISTANCE, HANDSET, which considers handset model and OS and ACTION), the value space of each attribute was divided over the possible discrete values for that attribute according to Table 2.2.

Attribute Possible Values
OFFERTIME Morning, Afternoon, Evening, Night, Unknown
CATEGORY Entertainment, Automotive, Food & Dining, Health & Beauty, Retail, Sports & Recreation, Travel, Clothing & Apparel, Electronics & Appliances, Furniture & Decor, Grocery, Hobbies & Crafts, Home Services, Hotels & Lodging, Nightlife & Bars, Nonprofits & Youth, Office Supplies, Other, Pet Services, Professional Services, Real Estate, Unknown
DISTANCE Less than 2 miles, 2 to 5 miles, 5 to 10 miles, 10 to 20 miles, 20 to 50 miles, 50 to 100 miles, Unknown
HANDSET Device: iPhone, iPod, G1, Hero, myTouch, Droid, Unknown
OS: iPhone, Android, Unknown
ACTION Redeem, Hit, Unknown

Table 2.2

In the case of the handset OS, iPhone and iPod were classified together as the iPhone OS as they are the same OS with different build targets. It is important to note that kNN works equally well with continuous valued attributes as well as discrete-valued attributes. For further discussion on using kNN with real-valued attributes, see [10].

3. PROBLEMS

There were several problems that were encountered while implementing kNN. The first problem was “Majority Voting.” Majority voting is the last step in the algorithm to classify an instance and is an inherent problem with the way the kNN algorithm works. If a particular class dominates the training data, it will skew the votes towards that class since we are only considering data at a local level, that is the distance from our classification instance to the nearest data points. There are two ways to solve this problem: 1) balancing the dataset, or, 2) weighting the neighboring instances. Balancing is the simplest technique where an equal proportion of either class are present in the training data. A more complicated, but more effective, method is to weight the neighboring instances such that neighbors that are further away have a smaller weight value than closer neighbors.

Determining “k” beforehand is a troublesome problem. This is due to the fact that, if “k” is too large, the separation between classifications becomes blurred. This could cause the program to group two clusters together that are, in fact, distinct clusters themselves. However, a large “k” value does reduce the effect of noise by including more samples in the hypothesis. If “k” is too small, we might not calculate a good representation of the sample space because our results were too local. In either case, if the target attribute is binary, “k” should be an odd number to avoid the possibilities of ties with majority voting.

Also, kNN has a high computation cost because it has to consider the distance of every point from itself to another point. The time-complexity of kNN is O(n), which wouldn’t scale well to hypothesis spaces with millions of instances.

Discretizing non-related attributes, like category, presented a unique challenge for the author. When considering continuous attributes, such as distance, it was easy to discretize this data. In the case of Coupious, the distance ranges were already defined in the application so we just had to translate those over to our classification algorithm. However, some attributes, such as category, while related at an attribute level (in that they were all categories of coupon), had no real values. In this case, we simply assigned them increasing integer values

Another problem that we encountered is the sparsity problem. Since we implemented a content-driven model, the degree of accuracy relied upon how much data we had about a particular end user to build their profile. If the customer only had one or two sessions ending in no redemptions, it might not be possible to achieve any accuracy about this person. We dealt with this problem by artificially creating new records to supplement previous real records.

Coupious relies on the GPS module inside the smart phone to tell us where a user is currently located. From that position, the user gets a list of coupons that are close to the user’s location. However, there are no safeguards in place to guarantee that a redemption is real. A curious user may attempt to redeem a coupon when he is not at the actual merchant location. In the data, we can account for this by calculating the distance from the merchant at the time of the redemption request. However, this GPS reading may be inaccurate as the GPS model can adjust it’s accuracy to save power and battery life.

Lastly, accuracy is somewhat limited because of the fact that we are using a content-only model. There is no way to interact with the user to ask if the recommendations are truly useful. To achieve this additional metric would require major changes to the application and the backend systems that are outside the scope of this research paper.

Despite the multiple problems with kNN, it is quite robust to noisy data as indicated in section 4, which makes it well-suited for this classification task, as the author can only verify the reasonableness of the data, not the integrity.

4. TESTING

Testing of the kNN logic was carried out using a 3-fold cross validation method, were the data was divided into training and test sets such that | R | = k X | S |, where R is the size of the training set, k is the relative size and S is the size of the test set.

For each test run, we chose 4,000 training examples and 1 test example at random. We attempted to keep labeled classes in the training set as balanced as possible by setting a threshold n. This threshold prevented the classes from becoming unbalanced by more than a difference of n. If the threshold n was ever reached, we discarded random selections until we were under the threshold again and thereby balance the classes. Discussion of results are in section 5.

5. EVALUATION

Even though kNN is a simplistic algorithm, the classification results were quite accurate. To test the algorithm, we performed 10,000 independent runs where an equal number of “hit” and “redemption” rows were selected at random (2,000 of each so as to keep the inductive bias as fair as possible). An individual classification instance was chosen at random from that set of 4,000 instances and was then classified according to its nearest neighbors.

5.1 MACRO EVALUATION

When evaluating the results, there was one main factor that affected the recall and it was the size of the k neighbors considered in the calculation (see Table 5.1). In the 10,000 independent runs using random subsets of data for each test, the overall recall for the kNN algorithm was 85.32%. The average F-measure for these runs was 0.45.

However, if one considers a subset of results with k-size less than or equal to 15, the average recall was much higher – 94%. After a k-size greater than 30, we see a significant drop-off of recall. This can be attributed to the fact that the groups are becoming less defined because, as k-size grows, the nodes that are being used are “further” away from the classification instance, and therefore the results are not as “good.”

5.2 MICRO EVALUATION

When broken down into smaller sets of 1,000 runs, the recall and F-measure vary greatly. In 16 runs, we had a range from 29.40% recall to 98.20% recall. The median recall was 92.70%.

Run K Size Recall F-measure Avg. Distance
1 1 98.20% 0.49 0.18
2 2 97.80% 0.49 0.23
3 3 95.80% 0.48 0.49
4 4 95.70% 0.48 0.44
5 5 95.60% 0.48 0.46
6 6 95.20% 0.48 0.59
7 7 93.10% 0.48 0.48
8 8 92.70% 0.47 0.69
9 9 94.20% 0.48 0.82
10 10 93.40% 0.48 0.88
11 15 91.70% 0.48 1.21
12 30 87.50% 0.47 2.16
13 50 85.10% 0.46 3.63
14 100 70.80% 0.42 7.57
15 200 48.90% 0.32 16.57
16 500 29.40% 0.22 31.64
Overall 85.32% 0.45 4.25

Table 5.1

There is a large gap between our maximum and our minimum recall. This can be attributed mainly to our k-size. Based on these results, we would feel fairly confident that we could make a useful prediction, but only if we had a confidence rating on the results (due to the high variability of the results).

These results could provide good insight into what k-size or neighbors are the most influential in suggesting a coupon. This would allow us to more carefully target Coupious advertising based on the user.

When could one consider these results valid? If the average distance of a classification instance to the examples is below a threshold such that the classification truly reflects its neighbors, we could consider the results valid. Another form of validating the results could be pruning the attribute set. If we were able to prune away attributes that didn’t affect the recall in a negative manner, we would be left with a set of attributes that truly influence the customers purchasing behavior, although this task is better suited for a decision or regression tree. An improvement to this kNN algorithm might come in the form of altering the k-size based upon the population or attributes that we are considering.

6. CONCLUSION

In this research project, we have implemented the kNN algorithm for recommender systems. The algorithm for the nearest neighbor was explored and several problems were identified and overcome. Different techniques were investigated to improve the accuracy of the system. The results of this project show an overall accuracy of 85.32%, which makes kNN an excellent, simple technique for implementing recommender systems.

REFERENCES

[1] Zhang, T., Iyengar, V. S. Recommender Systems Using Linear Classifiers. Journal of Machine Learning Research 2. (2002). 313-334.
[2] Basu, C., Hirsh, H., Cohen, W. Recommendation as Classification: Using Social and Content-Based Information in Recommendation.
[3] Cheung, K. W., Kowk, J. T., Law, M. H., Tsui, K. C. Mining Customer Product Ratings for Personalized Marketing
[4] E. Alpayden., Introduction to Machine Learning, 2nd ed. MIT Press. Cambridge, Mass, 2010.
[5] D. Goldberg, D. Nichols, B.M. Oki, D. Terry, Collaborative filtering to weave an information tapestry, Communications of the ACM 35. (12) (December 1992) 61 – 70.
[6] T.M. Mitchell, Machine Learning, New York. McGraw-Hill, 1997.
[7] B. Sarwar, G. Karypis, J. Konstan, and J. Riedl, “Recommender Systems for Large-Scale E-Commerce: Scalable Neighborhood Formation Using Clustering,” Proc. Fifth Int’l Conf. Computer and Information Technology, 2002.
[8] D. Barbella, S. Benzaid, J. Christensen, B. Jackson, X. V. Qin, D. Musicant. Understanding Support Vector Machine Classifications via a Recommender System-Like Approach. [Online]. http://www.cs.carleton.edu/faculty/dmusican/svmzen.pdf
[9] D.E. Knuth. “The Art of Computer Programming.” Addison-Wesley. 1973.
[10] C. Elkan. “Nearest Neighbor Classification.” University of California – San Diego. 2007. [Online]. http://cseweb.ucsd.edu/~elkan/151/nearestn.pdf

iPhone OS is one of the most advanced OS available today – and it s a mobile OS. Using the OS, it is clear to see why mobile computing is the future. When compared to other OSs, the iPhone OS holds it’s own. Broadly, looking at most modern desktop OSs, it has support for nearly everything that one would have available in a “full”, modern OS. It has support for network, full graphics support (video, animation, photos), security, etc. The one thing that it lacks is true multitasking. Let’s be clear though; Today’s iPhone 3.x firmware is a fully preemptive multitasking operating system, but it artificially restricts apps (other than specific ones bundled with the system by Apple) from running in the background.

But why? Apple initially avoided an app model supporting multiple apps running at once to help preserve battery life and simplify the user experience.

So, Apple decided instead to opt for a “compromise”, push notifications to enable third party apps to appear to respond to outside updates (such as incoming messages or news alerts) even when they were not actually running. It would give the “illusion” of allowing 3rd party multitasking by displaying messages to the user when the app needed their attention. Other OSs, such as Android and Blackberry have full support for 3rd party multitasking, at the expense of battery life and perhaps a more complicated user experience.

So what is one to do? After writing the initial draft of this post, the news of iPhone OS 4.0 supporting multitasking came out a few days later. But, I don’t care about rumors – I want results. Just as in “Jerry Maguire”, show me the money. Oh, and for the sake of argument, let’s assume that our hardware is a single processor and our OS is using kernal threads and round-robin scheduling.

First, let’s consider the model for most modern OS and how they implement multitasking. Multitasking is actually a simple slight of hand. A process is simply an instance of a program or executable that is mapped into memory. We all know that we can have multiple programs or processes running at a time. But does the computer work with all the processes all at the same time? No. Similar to how a human works and processes information, a processor works with whatever data it is handed, but is only capable of working with particular process at a time. The processes are scheduled in a round-robin queue and when their turn comes up, they get a small piece of time with the processor. After their time, or quantum, expires, or the process blocks, the process is removed from the running context and placed back in the queue to wait for their turn again. This context switching happens so fast that a normal user cannot tell that this is the true model of what is happening and they believe that all programs are executing concurrently, as in the processor sharing model. The model described above has a whole array of issues relating to memory management (including page faulting), security and protection. The model I would like to describe below would have the same issues, but I will only talk about security and protection.

Armed with a very basic idea of how processes work, how can we adapt this to a more mobile OS? What are the areas that we can adjust.

QuantumBAD
First, we can adjust the quantum, so there is less overhead associated with servicing each process and hence less power consumption. But Is this a good solution? Absolutely not. Quanta that are too short cause unnecessary thrashing with all the context switching that is occurring and if in an extreme case, the time servicing a context switch, may be longer than the actual time the process receives from the processor. What about variable quanta? Not a good idea either. The process would receive non-uniform amounts of time, making scheduling more difficult and perhaps a “jittery” response in the UI.

SchedulingBAD
What if we change the type of scheduling we do? What if we try FCFS (first come, first served) or SJF (shortest job first)? That is not a good solution either because with FCFS, the process will continue to run and hog the processor until it is finished and in the case of applications, they will never finish until the user terminates the app. However, the solution proposed will draw inspiration from this category.

NotificationBAD
What if we eliminate the context switching and interrupts? We can set bits to indicate the app needs service. This idea is the absolute worst of them so far. What happens if two background applications request OS services in the same off round-robin cycle. If you proposed using shared memory for notification, you just lost an “interrupt.” What about not using shared memory? What a pain! Now you have to setup dynamic data structures for each app that runs and terminates. Ok, enough with the freshmen ideas. Are you ready to have a heap of knowledge dumped on you?

Let’s revisit the scheduling idea and draw inspiration from a multi-level feedback queue. In this proposed solution, there would be the same blocked and ready queues that any scheduler would have. However, there would be a foreground queue and a background queue. The foreground queue would contain the currently “focused” app, i.e. the process that the user is actively using. The background queue would contain all the remaining ready processes. The foreground queue would receive processor cycles as normal and the background queue would receive a fraction of the cycles to the tune of 1/n processes, with n capped at some upper bound to ensure that all processes still receive decent service. Giving the background processes some processor time ensure they can still continue to work. When the user wants to switch to a different process, the foreground process is removed and placed in the background queue. The rest of the process paradigm would stay the same, where a process could interrupt and request services from the OS

There are security implications of allowing multiprocessing on the iPhone, and the major one is security and protection. When the user presses the home button on the iPhone, the application receives a delegate message from the OS, applicationWillTerminate. From that point, the application has 5 whole seconds to exit, before the OS steps in and kills the process. With multiple processes, we now have to consider how multiple apps will behave together. Obviously the iPhone OS implements a virtual address space, so that separate processes have separate chunks of transparent memory. However, some additional security measures might need to be taken so that other processes are unable to access anything but their own VAs.

As much as I wish I could test this hypothesis, I can’t because I have no access to the iPhone firmware. So I will leave it up to the folks at 1 Infinite Loop, but this is just my .02.

All code owned and written by David Stites and published on this blog is licensed under MIT/BSD.