private static Element makeVariables(SemIm semIm) { Element variablesElement = new Element(SemXmlConstants.SEM_VARIABLES); Element variable; Node measuredNode, latentNode; for (Node node1 : semIm.getSemPm().getMeasuredNodes()) { measuredNode = node1; variable = new Element(SemXmlConstants.CONTINUOUS_VARIABLE); variable.addAttribute(new Attribute(SemXmlConstants.NAME, measuredNode.getName())); variable.addAttribute(new Attribute(SemXmlConstants.IS_LATENT, "no")); variable.addAttribute( new Attribute(SemXmlConstants.MEAN, Double.toString(semIm.getMean(measuredNode)))); variable.addAttribute( new Attribute(SemXmlConstants.X, Integer.toString(measuredNode.getCenterX()))); variable.addAttribute( new Attribute(SemXmlConstants.Y, Integer.toString(measuredNode.getCenterY()))); variablesElement.appendChild(variable); } for (Node node : semIm.getSemPm().getLatentNodes()) { latentNode = node; variable = new Element(SemXmlConstants.CONTINUOUS_VARIABLE); variable.addAttribute(new Attribute(SemXmlConstants.NAME, latentNode.getName())); variable.addAttribute(new Attribute(SemXmlConstants.IS_LATENT, "yes")); variable.addAttribute( new Attribute(SemXmlConstants.MEAN, Double.toString(semIm.getMean(latentNode)))); variable.addAttribute( new Attribute(SemXmlConstants.X, Integer.toString(latentNode.getCenterX()))); variable.addAttribute( new Attribute(SemXmlConstants.Y, Integer.toString(latentNode.getCenterY()))); variablesElement.appendChild(variable); } return variablesElement; }
public int getNodeIndex(Node node) { List<Node> nodes = semIm.getSemPm().getVariableNodes(); for (int i = 0; i < nodes.size(); i++) { Node _node = nodes.get(i); if (node == _node) { return i; } } return -1; }
public int getNodeIndex(String nodeName) { List<Node> nodes = semIm.getSemPm().getVariableNodes(); for (int i = 0; i < nodes.size(); i++) { Node node = nodes.get(i); if (node.getName().equals(nodeName)) { return i; } } return -1; }
private static Element makeMarginalErrorDistribution(SemIm semIm) { Element marginalErrorElement = new Element(SemXmlConstants.MARGINAL_ERROR_DISTRIBUTION); Element normal; SemGraph semGraph = semIm.getSemPm().getGraph(); semGraph.setShowErrorTerms(true); for (Node node : getExogenousNodes(semGraph)) { normal = new Element(SemXmlConstants.NORMAL); normal.addAttribute(new Attribute(SemXmlConstants.VARIABLE, node.getName())); normal.addAttribute(new Attribute(SemXmlConstants.MEAN, "0.0")); normal.addAttribute( new Attribute( SemXmlConstants.VARIANCE, Double.toString(semIm.getParamValue(node, node)))); marginalErrorElement.appendChild(normal); } return marginalErrorElement; }
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; }
protected SemIm estimateCoeffs(SemIm semIm) { // System.out.print("\n****************\nCalling 2SLS... "); SemGraph semGraph = semIm.getSemPm().getGraph(); // Get list of fixed measurements that will be kept fixed, and the // respective latent variables that are their parents. // "X" variables are exogenous, while "Y" variables are endogenous. List<Node> ly = new LinkedList<Node>(); List<Node> lx = new LinkedList<Node>(); List<Node> my1 = new LinkedList<Node>(); List<Node> mx1 = new LinkedList<Node>(); List<Node> observed = new LinkedList<Node>(); for (Node nodeA : semGraph.getNodes()) { if (nodeA.getNodeType() == NodeType.ERROR) { continue; } if (nodeA.getNodeType() == NodeType.LATENT) { if (semGraph.getParents(nodeA).size() == 0) { lx.add(nodeA); } else { ly.add(nodeA); } } else { observed.add(nodeA); } } setFixedNodes(semGraph, mx1, my1); // ------------------------------------------------------------------ // Estimate freeParameters for the latent/latent edges for (Node current : ly) { if (nodeName != null && !nodeName.equals(current.getName())) { continue; } // Build Z, the matrix containing the data for the fixed measurements // associated with the parents of the getModel (endogenous) latent node List<Node> endo_parents_m = new LinkedList<Node>(); List<Node> exo_parents_m = new LinkedList<Node>(); List<Node> endo_parents = new LinkedList<Node>(); List<Node> exo_parents = new LinkedList<Node>(); Iterator<Node> it_p = semGraph.getParents(current).iterator(); lNames = new String[lx.size() + ly.size()]; while (it_p.hasNext()) { Node node = it_p.next(); if (node.getNodeType() == NodeType.ERROR) { continue; } if (lx.contains(node)) { int position = lx.indexOf(node); exo_parents_m.add(mx1.get(position)); exo_parents.add(node); } else { int position = ly.indexOf(node); endo_parents_m.add(my1.get(position)); endo_parents.add(node); } } Object endp_a_m[] = endo_parents_m.toArray(); Object exop_a_m[] = exo_parents_m.toArray(); Object endp_a[] = endo_parents.toArray(); Object exop_a[] = exo_parents.toArray(); int n = dataSet.getNumRows(), c = endp_a_m.length + exop_a_m.length; if (c == 0) { continue; } double Z[][] = new double[n][c]; int count = 0; for (int i = 0; i < endp_a_m.length; i++) { Node node = (Node) endp_a_m[i]; String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // Z[j][i] = column_data[j]; Z[j][i] = dataSet.getDouble(j, colIndex); } lNames[count++] = (endo_parents.get(i)).getName(); } for (int i = 0; i < exop_a_m.length; i++) { Node node = (Node) exop_a_m[i]; String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // Z[j][endp_a_m.length + i] = column_data[j]; Z[j][endp_a_m.length + i] = dataSet.getDouble(j, colIndex); } lNames[count++] = exo_parents.get(i).getName(); } // Build V, the matrix containing the data for the nonfixed measurements // associated with the parents of the getModel (endogenous) latent node endo_parents_m = new LinkedList<Node>(); exo_parents_m = new LinkedList<Node>(); it_p = semGraph.getParents(current).iterator(); while (it_p.hasNext()) { Node node = it_p.next(); if (node.getNodeType() == NodeType.ERROR) { continue; } List<Node> other_measures = new LinkedList<Node>(); for (Node next : semGraph.getChildren(node)) { if (next.getNodeType() == NodeType.MEASURED) { other_measures.add(next); } } if (lx.contains(node)) { int position = lx.indexOf(node); other_measures.remove(mx1.get(position)); exo_parents_m.addAll(other_measures); } else { int position = ly.indexOf(node); other_measures.remove(my1.get(position)); endo_parents_m.addAll(other_measures); } } endp_a_m = endo_parents_m.toArray(); exop_a_m = exo_parents_m.toArray(); n = dataSet.getNumRows(); c = endp_a_m.length + exop_a_m.length; double V[][] = new double[n][c]; if (c == 0) { continue; } for (int i = 0; i < endp_a_m.length; i++) { Node node = ((Node) endp_a_m[i]); String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // V[j][i] = column_data[j]; V[j][i] = dataSet.getDouble(j, colIndex); } } for (int i = 0; i < exop_a_m.length; i++) { Node node = (Node) exop_a_m[i]; String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // V[j][endp_a_m.length + i] = column_data[j]; V[j][endp_a_m.length + i] = dataSet.getDouble(j, colIndex); } } double yi[] = new double[n]; if (lx.contains(current)) { int position = lx.indexOf(current); Node node = mx1.get(position); String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // // System.arraycopy(column.getRawData(), 0, yi, 0, n); for (int i = 0; i < n; i++) { yi[i] = dataSet.getDouble(i, colIndex); } } else { int position = ly.indexOf(current); Node node = my1.get(position); String name = node.getName(); Node variable = dataSet.getVariable(name); int colIndex = dataSet.getVariables().indexOf(variable); // System.arraycopy(dataSet.getColumnObject(variable).getRawData(), 0, yi, 0, // n); for (int i = 0; i < n; i++) { yi[i] = dataSet.getDouble(i, colIndex); } } // Build Z_hat double Z_hat[][] = MatrixUtils.product( V, MatrixUtils.product( MatrixUtils.inverse(MatrixUtils.product(MatrixUtils.transpose(V), V)), MatrixUtils.product(MatrixUtils.transpose(V), Z))); A_hat = MatrixUtils.product( MatrixUtils.inverse(MatrixUtils.product(MatrixUtils.transpose(Z_hat), Z_hat)), MatrixUtils.product(MatrixUtils.transpose(Z_hat), yi)); // Set the edge for the fixed measurement int position = ly.indexOf(current); semIm.setParamValue(current, my1.get(position), 1.); // Set the edge for the latents for (int i = 0; i < endp_a.length; i++) { semIm.setParamValue((Node) endp_a[i], current, A_hat[i]); } for (int i = 0; i < exop_a.length; i++) { semIm.setParamValue((Node) exop_a[i], current, A_hat[endp_a.length + i]); } if (nodeName != null && nodeName.equals(current.getName())) { computeAsymptLatentCovar(yi, A_hat, Z, Z_hat, dataSet.getNumRows()); break; } } // ------------------------------------------------------------------ // Estimate freeParameters of the measurement model // Set the edges of the fixed measurements of exogenous for (Node current : lx) { int position = lx.indexOf(current); semIm.setParamValue(current, mx1.get(position), 1.); } for (Node current : observed) { if (nodeName != null && !nodeName.equals(current.getName())) { continue; } if (mx1.contains(current) || my1.contains(current)) { continue; } // First, get the parent of this observed Node current_latent = null; for (Node node : semGraph.getParents(current)) { if (node.getNodeType() == NodeType.ERROR) { continue; } current_latent = node; } Iterator<Node> children = semGraph.getChildren(current_latent).iterator(); List<Node> other_measures = new LinkedList<Node>(); Node fixed_measurement; while (children.hasNext()) { Node next = children.next(); if ((next.getNodeType() == NodeType.MEASURED) && next != current) { other_measures.add(next); } } if (lx.contains(current_latent)) { int position = lx.indexOf(current_latent); other_measures.remove(mx1.get(position)); fixed_measurement = mx1.get(position); } else { int position = ly.indexOf(current_latent); other_measures.remove(my1.get(position)); fixed_measurement = my1.get(position); } // Regress other_measures over the fixed measurement x1 (y1) correspondent // to the measurement variable that is being evaluated int n = dataSet.getNumRows(), c = other_measures.size(); if (c == 0) { continue; } double Z[][] = new double[n][c]; for (int i = 0; i < c; i++) { Node variable = dataSet.getVariable((other_measures.get(i)).getName()); int varIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // Z[j][i] = column_data[j]; Z[j][i] = dataSet.getDouble(varIndex, j); } } // Build C, the column matrix containing the data for the fixed // measurement associated with the only latent parent of the getModel // observed node (as assumed by the structure of our measurement model). Node variable = dataSet.getVariable(fixed_measurement.getName()); int colIndex = dataSet.getVariables().indexOf(variable); // Column column = dataSet.getColumnObject(variable); // double C[] = (double[]) column.getRawData(); double[] C = new double[dataSet.getNumRows()]; for (int i = 0; i < dataSet.getNumRows(); i++) { C[i] = dataSet.getDouble(colIndex, i); } // Build V, the matrix containing the data for the other measurements // associated with the parents of the (latent) parent of getModel // observed node. The only difference with respect to the estimation // of the within-latent coefficients is that here we only include // the other measurements attached to the parent of the getModel node, // assuming that the error term of the getModel node is independent // of the error term of the others and that each measurement is // taken with respect to only one latent. n = dataSet.getNumRows(); c = other_measures.size(); double V[][] = new double[n][c]; for (int i = 0; i < c; i++) { Node variable2 = dataSet.getVariable((other_measures.get(i)).getName()); int var2index = dataSet.getVariables().indexOf(variable2); // Column column = dataSet.getColumnObject(variable2); // double column_data[] = (double[]) column.getRawData(); for (int j = 0; j < n; j++) { // V[j][i] = column_data[j]; V[j][i] = dataSet.getDouble(j, var2index); } } double yi[] = new double[n]; Node variable3 = dataSet.getVariable((current).getName()); int var3Index = dataSet.getVariables().indexOf(variable3); for (int i = 0; i < n; i++) { yi[i] = dataSet.getDouble(i, var3Index); } // Object rawData = dataSet.getColumnObject(variable3).getRawData(); // System.arraycopy(rawData, 0, yi, 0, n); double C_hat[] = MatrixUtils.product( V, MatrixUtils.product( MatrixUtils.inverse(MatrixUtils.product(MatrixUtils.transpose(V), V)), MatrixUtils.product(MatrixUtils.transpose(V), C))); double A_hat = MatrixUtils.innerProduct( MatrixUtils.scalarProduct(1. / MatrixUtils.innerProduct(C_hat, C_hat), C_hat), yi); // Set the edge for the getModel measurement semIm.setParamValue(current_latent, current, A_hat); } return semIm; }
/** * 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()); }