View Javadoc

1   /*
2    * Copyright (C) 2004 Christian Siefkes <christian@siefkes.net>.
3    * Development of this software is supported by the German Research Society,
4    * Berlin-Brandenburg Graduate School in Distributed Information Systems
5    * (DFG grant no. GRK 316).
6    *
7    * This library is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU Lesser General Public
9    * License as published by the Free Software Foundation; either
10   * version 2.1 of the License, or (at your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, visit
19   * http://www.gnu.org/licenses/lgpl.html or write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21   */
22  package de.fu_berlin.ties.classify.feature;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.apache.commons.lang.builder.ToStringBuilder;
26  
27  import de.fu_berlin.ties.ProcessingException;
28  import de.fu_berlin.ties.TiesConfiguration;
29  import de.fu_berlin.ties.util.Util;
30  
31  /***
32   * An feature transformer transforms a feature vector in a suitable way.
33   * Feature transformer can be used for feature selection (discarding irrelevant
34   * features), for combining features etc. Feature transforms can be
35   * <em>chained</em> -- in this case each feature transformer will work on the
36   * featured returned by the previous one.
37   *
38   * @author Christian Siefkes
39   * @version $Revision: 1.3 $, $Date: 2004/07/08 08:42:18 $, $Author: siefkes $
40   */
41  public abstract class FeatureTransformer {
42  
43      /***
44       * Configuration key specifying the list of transformers to chain.
45       */
46      public static final String CONFIG_TRANSFORMERS = "transformer.chain";
47  
48      /***
49       * Factory method that delegates to {@link #createTransformer()} using the
50       * {@linkplain TiesConfiguration#CONF standard configuration}.
51       *
52       * @return the last transformer in the created transformer chain; or
53       * <code>null</code> is no transformers are specified (parameter value is
54       * <code>null</code> or empty)
55       * @throws IllegalArgumentException if the value of the
56       * {@link #CONFIG_TRANSFORMERS} key is invalid
57       * @throws ProcessingException if an error occurred while creating the
58       * transformer
59       */
60      public static FeatureTransformer createTransformer()
61      throws IllegalArgumentException, ProcessingException {
62          return createTransformer(TiesConfiguration.CONF);
63      }
64  
65      /***
66       * Factory method that creates a feature transformer based on the
67       * {@link #CONFIG_TRANSFORMERS} key in the provided configuration.
68       * This parameter must contain a list fully specified names of subclasses
69       * of this class) used in a chain.
70       *
71       * <p>Eeach specified transformer must provide a constructor accepting a
72       * preceding {@link FeatureTransformer} as first argument and a
73       * {@link TiesConfiguration} as second argument.
74       *
75       * @param config the configuration to use
76       * @return the last transformer in the created transformer chain; or
77       * <code>null</code> is no transformers are specified (parameter value is
78       * <code>null</code> or empty)
79       * @throws IllegalArgumentException if the value of the
80       * {@link #CONFIG_TRANSFORMERS} key is invalid
81       * @throws ProcessingException if an error occurred while creating the
82       * transformer
83       */
84      public static FeatureTransformer createTransformer(
85              final TiesConfiguration config)
86      throws IllegalArgumentException, ProcessingException {
87          final String[] paramValue = config.getStringArray(CONFIG_TRANSFORMERS);
88          FeatureTransformer transformer = null;
89          int i = 0;
90  
91          try {
92              for (; i < paramValue.length; i++) {
93                  // initialize each of the specified transformers, handing over
94                  // the previous transformer as first single argument and the
95                  // TiesConfiguration as second argument
96                  if (StringUtils.isNotEmpty(paramValue[i])) {
97                      transformer = (FeatureTransformer) Util.createObject(
98                          Class.forName(paramValue[i]),
99                          new Object[] {transformer, config},
100                         new Class[] {FeatureTransformer.class,
101                             TiesConfiguration.class});
102                 }
103             }
104         } catch (ClassNotFoundException cnfe) {
105              // convert and rethrow exception
106              throw new ProcessingException(
107                  "Cannot create transformer chain from key "
108                  + CONFIG_TRANSFORMERS + " because the class " + paramValue[i]
109                  + " is missing: " + cnfe.toString());
110          } catch (InstantiationException ie) {
111              // convert and rethrow exception
112              throw new ProcessingException(
113                  "Cannot create transformer chain from key "
114                  + CONFIG_TRANSFORMERS + " because instantation of the class "
115                  + paramValue[i] + " failed: ", ie);
116         }
117 
118         // return the last transformer in the chain (if any)
119         return transformer;
120     }
121 
122     /***
123      * The preceding transformer used if this transformer is part of a
124      * <em>chain</em>; <code>null</code> otherwise.
125      */
126     private final FeatureTransformer precedingTransformer;
127 
128     /***
129      * Creates a new instance.
130      *
131      * @param precTrans the preceding transformer to use if this transformer
132      * is part of a <em>chain</em>; <code>null</code> otherwise
133      */
134     public FeatureTransformer(final FeatureTransformer precTrans) {
135         super();
136         precedingTransformer = precTrans;
137     }
138 
139     /***
140      * Transforms a feature vector.
141      *
142      * @param orgFeatures the original feature vector to transform
143      * @return a new feature vector containing the transformed features
144      */
145     protected abstract FeatureVector doTransform(
146         final FeatureVector orgFeatures);
147 
148     /***
149      * Returns the preceding transformer used if this transformer is part of a
150      * <em>chain</em>.
151      *
152      * @return the preceding transformer, if any; or <code>null</code> if this
153      * transformer is not part of a chain resp. is the first transformer in a
154      * chain
155      */
156     public FeatureTransformer getPrecedingTransformer() {
157         return precedingTransformer;
158     }
159 
160     /***
161      * Returns a string representation of this object.
162      *
163      * @return a textual representation
164      */
165     public String toString() {
166         final ToStringBuilder builder =  new ToStringBuilder(this);
167 
168         if (precedingTransformer != null) {
169             builder.append("preceding transformer", precedingTransformer);
170         }
171         return builder.toString();
172     }
173 
174     /***
175      * Transforms a feature vector. This method calls itself on the
176      * {@linkplain #getPrecedingTransformer() preceding transformer} (if any)
177      * prior to delegating to the abstract {@link #doTransform(FeatureVector)}
178      * method.
179      *
180      * @param orgFeatures the original feature vector to transform
181      * @return a new feature vector containing the transformed features
182      */
183     public FeatureVector transform(final FeatureVector orgFeatures) {
184         final FeatureVector result;
185 
186         if (precedingTransformer != null) {
187             // call preceding transformer prior to abstract method
188             result = doTransform(precedingTransformer.transform(orgFeatures));
189         } else {
190             // no preceding transformer -- just call abstract method
191             result = doTransform(orgFeatures);
192         }
193 
194 //      Util.LOG.debug("Length of original feature vector: "
195 //          + orgFeatures.size() + ", of transformed vector: " + result.size());
196         return result;
197     }
198 
199 }