private double paramValue(SemIm im, Parameter parameter) {
    double paramValue = im.getParamValue(parameter);

    if (parameter.getType() == ParamType.VAR) {
      paramValue = Math.sqrt(paramValue);
    }

    return paramValue;
  }
  private String typeString(Parameter parameter) {
    ParamType type = parameter.getType();

    if (type == ParamType.COEF) {
      return "Coef";
    }

    if (type == ParamType.VAR) {
      // return "Variance";
      return "StdDev";
    }

    if (type == ParamType.COVAR) {
      return "Covar";
    }

    throw new IllegalStateException("Unknown param type.");
  }
    /**
     * Computes the maximum likelihood function value for the given freeParameters values as given
     * by the optimizer. These values are mapped to parameter values.
     */
    public double evaluate(double[] parameters) {
      List<Parameter> _parameters = sem.getSemPm().getFreeParameters();

      for (int i = 0; i < _parameters.size(); i++) {
        Parameter parameter = _parameters.get(i);
        if (parameter.getType() == ParamType.VAR && parameters[i] < 0) {
          parameters[i] = 0;
        }
      }

      sem.setFreeParamValues(parameters);

      // This needs to be FML-- see Bollen p. 109.
      //            try {
      return sem.getScore();
      //            } catch (Exception e) {
      //                return Double.NEGATIVE_INFINITY;
      //            }
    }
  private static Element makeJointErrorDistribution(SemIm semIm) {
    Element jointErrorElement = new Element(SemXmlConstants.JOINT_ERROR_DISTRIBUTION);
    Element normal;
    Parameter param;

    for (Parameter parameter : semIm.getSemPm().getParameters()) {
      param = parameter;
      if (param.getType() == ParamType.COVAR) {
        normal = new Element(SemXmlConstants.NORMAL);
        normal.addAttribute(new Attribute(SemXmlConstants.NODE_1, param.getNodeA().getName()));
        normal.addAttribute(new Attribute(SemXmlConstants.NODE_2, param.getNodeB().getName()));
        normal.addAttribute(
            new Attribute(SemXmlConstants.COVARIANCE, Double.toString(param.getStartingValue())));
        jointErrorElement.appendChild(normal);
      }
    }

    return jointErrorElement;
  }
  private static Element makeEdges(SemIm semIm) {
    Element edgesElement = new Element(SemXmlConstants.EDGES);
    Parameter param;
    Element edge;

    for (Parameter parameter : semIm.getSemPm().getParameters()) {
      param = parameter;
      if (param.getType() == ParamType.COEF) {
        edge = new Element(SemXmlConstants.EDGE);
        edge.addAttribute(new Attribute(SemXmlConstants.CAUSE_NODE, param.getNodeA().getName()));
        edge.addAttribute(new Attribute(SemXmlConstants.EFFECT_NODE, param.getNodeB().getName()));
        edge.addAttribute(
            new Attribute(SemXmlConstants.VALUE, Double.toString(semIm.getParamValue(param))));
        edge.addAttribute(
            new Attribute(SemXmlConstants.FIXED, Boolean.valueOf(param.isFixed()).toString()));
        edgesElement.appendChild(edge);
      }
    }
    return edgesElement;
  }
  /**
   * This method computes the information matrix or Hessian matrix of second order partial
   * derivatives of the fitting function (4B_2 on page 135 of Bollen) with respect to the free
   * freeParameters of the estimated SEM. It then computes the inverse of the the information matrix
   * and calculates the standard errors of the freeParameters as the square roots of the diagonal
   * elements of that matrix.
   *
   * @param estSem the estimated SEM.
   */
  public void computeStdErrors(ISemIm estSem) {
    //        if (!unmeasuredLatents(estSem.getSemPm()).isEmpty()) {
    //            int n = estSem.getFreeParameters().size();
    //            stdErrs = new double[n];
    //
    //            for (int i = 0; i < n; i++) {
    //                stdErrs[i] = Double.NaN;
    //            }
    //
    //            return;
    //        }

    //        this.semIm = estSem;
    estSem.setParameterBoundsEnforced(false);
    double[] paramsOriginal = estSem.getFreeParamValues();
    double delta;
    FittingFunction fcn = new SemFittingFunction(estSem);
    boolean ridder = false; // Ridder is more accurate but a lot slower.

    int n = fcn.getNumParameters();

    // Store the free freeParameters of the SemIm so that they can be reset to these
    // values.  The differentiation methods change them.
    double[] params = new double[n];
    System.arraycopy(paramsOriginal, 0, params, 0, n);

    // If the Ridder method (secondPartialDerivativeRidr) is used to search for
    // the best delta it is initially set to 0.1.  Otherwise the delta is set to
    // 0.005.  That value has worked well for those fitting functions tested to
    // date.
    if (ridder) {
      delta = 0.1;
    } else {
      delta = 0.005;
    }

    // The Hessian matrix of second order partial derivatives is called the
    // information matrix.
    TetradMatrix hess = new TetradMatrix(n, n);

    List<Parameter> freeParameters = estSem.getFreeParameters();
    boolean containsCovararianceParameter = false;

    for (Parameter p : freeParameters) {
      if (p.getType() == ParamType.COVAR) {
        containsCovararianceParameter = true;
        break;
      }
    }

    for (int i = 0; i < n; i++) {
      for (int j = i; j < n; j++) {
        Parameter pi = freeParameters.get(i);
        Parameter pj = freeParameters.get(j);

        if (!containsCovararianceParameter) {

          // Restrict off-diagonal to just collider edge freeParameters.
          if (i != j && (pi.getType() != ParamType.COEF || pj.getType() != ParamType.COEF)) {
            continue;
          }

          if (pi.getNodeB() != pj.getNodeB()) {
            continue;
          }
        }

        double v;

        if (ridder) {
          v = secondPartialDerivativeRidr(fcn, i, j, params, delta);
        } else {
          v = secondPartialDerivative(fcn, i, j, params, delta);
        }

        if (Math.abs(v) < 1e-7) {
          v = 0;
        }

        //                if (Double.isNaN(v)) {
        //                    v = 0;
        //                }

        hess.set(i, j, v);
        hess.set(j, i, v);
      }
    }

    ROWS:
    for (int i = 0; i < hess.rows(); i++) {
      for (int j = 0; j < hess.columns(); j++) {
        if (hess.get(i, j) != 0) {
          continue ROWS;
        }
      }

      //            System.out.println("Zero row for " + freeParameters.get(i));
    }

    // The diagonal elements of the inverse of the information matrix are the
    // squares of the standard errors of the freeParameters.  Their order is the
    // same as in the array of free parameter values stored in paramsOriginal.
    try {

      TetradMatrix hessInv = hess.inverse();
      //            TetradMatrix hessInv = hess.ginverse();

      //            System.out.println("Inverse: " + hessInv);

      //            for (int i = 0; i < freeParameters.size(); i++) {
      //                System.out.println(i + " = " + freeParameters.get(i));
      //            }

      stdErrs = new double[n];

      // Hence the standard errors of the freeParameters are the square roots of the
      // diagonal elements of the inverse of the information matrix.
      for (int i = 0; i < n; i++) {
        double v = Math.sqrt((2.0 / (estSem.getSampleSize() - 1)) * hessInv.get(i, i));

        if (v == 0) {
          System.out.println("v = " + v + " hessInv(i, i) = " + hessInv.get(i, i));
        }

        if (v == 0) {
          stdErrs[i] = Double.NaN;
        } else {
          stdErrs[i] = v;
        }
      }
    } catch (Exception e) {
      e.printStackTrace();

      stdErrs = new double[n];

      for (int i = 0; i < n; i++) {
        stdErrs[i] = Double.NaN;
      }
    }

    // Restore the freeParameters of the estimated SEM to their original values.
    estSem.setFreeParamValues(paramsOriginal);
    estSem.setParameterBoundsEnforced(true);
  }
Beispiel #7
0
  /**
   * Constructs a new standardized SEM IM from the freeParameters in the given SEM IM.
   *
   * @param im Stop asking me for these things! The given SEM IM!!!
   * @param initialization CALCULATE_FROM_SEM if the initial values will be calculated from the
   *     given SEM IM; INITIALIZE_FROM_DATA if data will be simulated from the given SEM,
   *     standardized, and estimated.
   */
  public StandardizedSemIm(SemIm im, Initialization initialization) {
    this.semPm = new SemPm(im.getSemPm());
    this.semGraph = new SemGraph(semPm.getGraph());
    semGraph.setShowErrorTerms(true);

    if (semGraph.existsDirectedCycle()) {
      throw new IllegalArgumentException("The cyclic case is not handled.");
    }

    if (initialization == Initialization.CALCULATE_FROM_SEM) {
      //         This code calculates the new coefficients directly from the old ones.
      edgeParameters = new HashMap<Edge, Double>();

      List<Node> nodes = im.getVariableNodes();
      TetradMatrix impliedCovar = im.getImplCovar(true);

      for (Parameter parameter : im.getSemPm().getParameters()) {
        if (parameter.getType() == ParamType.COEF) {
          Node a = parameter.getNodeA();
          Node b = parameter.getNodeB();
          int aindex = nodes.indexOf(a);
          int bindex = nodes.indexOf(b);
          double vara = impliedCovar.get(aindex, aindex);
          double stda = Math.sqrt(vara);
          double varb = impliedCovar.get(bindex, bindex);
          double stdb = Math.sqrt(varb);
          double oldCoef = im.getEdgeCoef(a, b);
          double newCoef = (stda / stdb) * oldCoef;
          edgeParameters.put(Edges.directedEdge(a, b), newCoef);
        } else if (parameter.getType() == ParamType.COVAR) {
          Node a = parameter.getNodeA();
          Node b = parameter.getNodeB();
          Node exoa = semGraph.getExogenous(a);
          Node exob = semGraph.getExogenous(b);
          double covar = im.getErrCovar(a, b) / Math.sqrt(im.getErrVar(a) * im.getErrVar(b));
          edgeParameters.put(Edges.bidirectedEdge(exoa, exob), covar);
        }
      }
    } else {

      // This code estimates the new coefficients from simulated data from the old model.
      DataSet dataSet = im.simulateData(1000, false);
      TetradMatrix _dataSet = dataSet.getDoubleData();
      _dataSet = DataUtils.standardizeData(_dataSet);
      DataSet dataSetStandardized = ColtDataSet.makeData(dataSet.getVariables(), _dataSet);

      SemEstimator estimator = new SemEstimator(dataSetStandardized, im.getSemPm());
      SemIm imStandardized = estimator.estimate();

      edgeParameters = new HashMap<Edge, Double>();

      for (Parameter parameter : imStandardized.getSemPm().getParameters()) {
        if (parameter.getType() == ParamType.COEF) {
          Node a = parameter.getNodeA();
          Node b = parameter.getNodeB();
          double coef = imStandardized.getEdgeCoef(a, b);
          edgeParameters.put(Edges.directedEdge(a, b), coef);
        } else if (parameter.getType() == ParamType.COVAR) {
          Node a = parameter.getNodeA();
          Node b = parameter.getNodeB();
          Node exoa = semGraph.getExogenous(a);
          Node exob = semGraph.getExogenous(b);
          double covar = -im.getErrCovar(a, b) / Math.sqrt(im.getErrVar(a) * im.getErrVar(b));
          edgeParameters.put(Edges.bidirectedEdge(exoa, exob), covar);
        }
      }
    }

    this.measuredNodes = Collections.unmodifiableList(semPm.getMeasuredNodes());
  }