| A: | 10, | 20, | 30, | 40 |
| B: | 40, | 30, | 20, | 10 |
| C: | 11, | 21, | 29, | 39 |
| D: | 39, | 29, | 21, | 11 |
We can see that A and C are 'closer' than B and D, so A and C can be grouped together, and B and D form a separate group.
R supports a wide variety of clustering techniques, all of which require us to pass a data frame object to the R interpreter. This post describes a simple way of generating a data frame, passing it to a clustering algorithm, and reading back some of the results.
Creating a Data Frame
The data frame is an R-specific data structure for holding data and its interpretation. For clustering, we need to describe a number of instances (the rows within a standard table) based on their attributes (the columns). For example, the following shows the first two instances from a weather dataset:
| instance | outlook | temperature | humidity | windy |
|---|---|---|---|---|
| 1 | 0 | 85 | 85 | 0 |
| 2 | 0 | 80 | 90 | 1 |
To define this in RSRuby, we need to set up a conversion tool, to handle the conversion from a hashmap to R's data frame.
require 'rsruby'
require 'rsruby/dataframe'
r = RSRuby.instance
r.class_table['data.frame'] = lambda {|x| DataFrame.new(x)}
RSRuby.set_default_mode(RSRuby::CLASS_CONVERSION)
The weather dataset can be defined and set up as follows:
outlooks = [0,0,1,2,2,2,1,0,0,2,0,1,1,2]
temps = [85,80,83,70,68,65,64,72,69,75,75,72,81,71]
humidities = [85,90,86,96,80,70,65,95,70,80,70,90,75,91]
winds = [0,1,0,0,0,1,1,0,0,0,1,1,0,1]
weather_data = {}
weather_data['outlook'] = outlooks
weather_data['temperature'] = temps
weather_data['humidity'] = humidities
weather_data['windy'] = winds
example = r.as_data_frame(:x => weather_data)
Of course, the definition of the hashmap can be simplified, but I like this format as a template for constructing the data frames from other sources of data. Note that the hashmap must be provided as the value of the :x key when constructing the data frame.
Clustering
To use any of the cluster techniques, we must include the 'cluster' library:
r.library("cluster")
A simple form of clustering algorithm is called clara. This takes a data frame and a number of clusters, and then returns a set of results which describe the data in terms of those clusters; the result is returned as a hashmap for Ruby, and the cluster results can be retrieved using the "clustering" key:
clara_result = r.clara(example,2)
14.times do |i|
puts "Data: #{clara_result["data"][i].join(",")} Cluster: #{clara_result["clustering"][i]}"
end
A sample output is:
Data: 0,85,85,0 Cluster: 1
Data: 0,80,90,1 Cluster: 2
Data: 1,83,86,0 Cluster: 1
Data: 2,70,96,0 Cluster: 2
Data: 2,68,80,0 Cluster: 1
Data: 2,65,70,1 Cluster: 1
Data: 1,64,65,1 Cluster: 1
Data: 0,72,95,0 Cluster: 2
Data: 0,69,70,0 Cluster: 1
Data: 2,75,80,0 Cluster: 1
Data: 0,75,70,1 Cluster: 1
Data: 1,72,90,1 Cluster: 2
Data: 1,81,75,0 Cluster: 1
Data: 2,71,91,1 Cluster: 2

