/***
* Copyright (c) 2008, Endless Loop Software, Inc.
*
* This file is part of EgoNet.
*
* EgoNet is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* EgoNet is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.egonet.statistics;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import org.egonet.exceptions.MissingPairException;
import org.egonet.model.Interview;
import org.egonet.model.Study;
import org.egonet.model.answer.*;
import org.egonet.model.question.AlterPromptQuestion;
import org.egonet.model.question.AlterQuestion;
import org.egonet.model.question.Question;
import org.egonet.util.FileHelpers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import au.com.bytecode.opencsv.CSVWriter;
public class Statistics
{
final private static Logger logger = LoggerFactory.getLogger(Statistics.class);
private final Study _study;
private final Interview _interview;
public int[][] adjacencyMatrix = new int[0][];
public int[][] weightedAdjacencyMatrix = new int[0][];
public int[][] proximityMatrix = new int[0][];
public int[][] alter_alterPromptMatrix = new int[0][];
public float[] betweennessArray = new float[0];
public float[] closenessArray = new float[0];
public int[] farnessArray = new int[0];
public int[] degreeArray = new int[0];
public Set<Stack<Integer>> cliqueSet = new HashSet<Stack<Integer>>();
public Set<Stack<Integer>> allSet = new HashSet<Stack<Integer>>();
public Set<Set<Integer>> componentSet = new HashSet<Set<Integer>>();
public AlterStats[] alterStatArray = new AlterStats[0];
public Integer[][] alterSummary = new Integer[0][];
public String[] alterList = new String[0];
public int isolates;
public int dyads;
public int mostCentralDegreeAlterValue;
public float meanCentralDegreeValue;
public int mostCentralDegreeAlterIndex;
public String mostCentralDegreeAlterName;
public float degreeNC;
public float mostCentralBetweenAlterValue;
public float meanCentralBetweenAlterValue;
public int mostCentralBetweenAlterIndex;
public String mostCentralBetweenAlterName;
public float betweenNC;
public float mostCentralClosenessAlterValue;
public float meanCentralClosenessValue;
public int mostCentralClosenessAlterIndex;
public String mostCentralClosenessAlterName;
public float closenessNC;
public static final int MINIMUM_CLIQUE = 3;
/* Instantiable class */
private Statistics(Interview interview)
{
_interview = interview;
_study = interview.getStudy();
}
public static Statistics generateInterviewStatistics(Interview interview, Question q)
{
Statistics stats = new Statistics(interview);
int numAlters = stats.getInterview().getNumberAlters();
//int numAlters = 2;
int alterindex;
float maxfloat, meanfloat;
int maxint;
float sizefloat;
boolean noneYet = stats.getInterview().getAnswerSubset(q.UniqueId).size() == 0;
logger.info("CREATING STATISTICS: Study " + (noneYet ? "has none yet": "already had some"));
try
{
if (noneYet)
{
stats.adjacencyMatrix = new int[0][];
stats.weightedAdjacencyMatrix = new int[0][];
stats.alter_alterPromptMatrix = new int[0][];
stats.proximityMatrix = new int[0][];
stats.betweennessArray = new float[0];
stats.closenessArray = new float[0];
stats.farnessArray = new int[0];
stats.allSet = new HashSet<Stack<Integer>>(0);
stats.cliqueSet = new HashSet<Stack<Integer>>(0);
stats.componentSet = new HashSet<Set<Integer>>(0);
stats.degreeArray = new int[0];
stats.alterStatArray = new AlterStats[0];
stats.alterSummary = new Integer[0][];
}
else
{
stats.adjacencyMatrix = interview.generateAdjacencyMatrix(q, false);
stats.weightedAdjacencyMatrix = interview.generateAdjacencyMatrix(q, true);
stats.alter_alterPromptMatrix = interview.generateAlterByAlterPromptMatrix();
stats.alterList = interview.getAlterList();
stats.allSet = new HashSet<Stack<Integer>>(0);
stats.cliqueSet = new HashSet<Stack<Integer>>(0);
stats.componentSet = new HashSet<Set<Integer>>(0);
stats.allSet = stats.identifyAllConnections();
stats.cliqueSet = stats.identifyCliques();
stats.componentSet = stats.identifyComponents();
stats.isolates = stats.countComponentSize(1);
stats.dyads = stats.countComponentSize(2);
stats.clearIdentity(stats.adjacencyMatrix);
stats.clearIdentity(stats.weightedAdjacencyMatrix);
stats.proximityMatrix = stats.generateProximityMatrix();
stats.betweennessArray = stats.generateBetweennessArray();
stats.degreeArray = stats.generateDegreeArray();
stats.generateAlterStatArray();
/* find most between alter */
maxfloat = -1;
alterindex = -1;
float tot = 0;
for (int i = 0; i < numAlters; ++i)
{
stats.betweennessArray[i] = (float)(Math.rint(1000*(stats.betweennessArray[i]/2)))/1000;
tot = tot + stats.betweennessArray[i];
if (stats.betweennessArray[i] > maxfloat)
{
alterindex = i;
maxfloat = stats.betweennessArray[i];
}
}
stats.mostCentralBetweenAlterValue = maxfloat;
stats.mostCentralBetweenAlterIndex = alterindex;
stats.mostCentralBetweenAlterName = stats.alterList[alterindex];
stats.meanCentralBetweenAlterValue = (float)(Math.rint(1000*tot/numAlters))/1000;
//compute betweenness network centralization
meanfloat = 0;
for (int i = 0; i < numAlters; ++i)
{
meanfloat = meanfloat + (maxfloat - stats.betweennessArray[i]);
}
stats.betweenNC = (float)(Math.rint(1000*((2*meanfloat*100)/((numAlters-1)*(numAlters-1)*(numAlters-2)))))/1000;
//logger.info("Mean betweenness value is "+ stats.meanCentralBetweenAlterValue);
/* find most central degree alter */
maxint = -1;
for (int i = 0; i < numAlters; ++i)
{
if (stats.degreeArray[i] > maxint)
{
alterindex = i;
maxint = stats.degreeArray[i];
}
}
meanfloat = 0;
for (int i = 0; i < numAlters; ++i)
{
meanfloat = meanfloat + stats.degreeArray[i];
}
//logger.info("Mean degree centrality is "+ meanint/size);
stats.mostCentralDegreeAlterValue = maxint;
//logger.info("Most central degree value is "+ maxint);
stats.mostCentralDegreeAlterIndex = alterindex;
stats.mostCentralDegreeAlterName = stats.alterList[alterindex];
stats.meanCentralDegreeValue = (float)(Math.rint(1000*meanfloat/numAlters))/1000;
//compute network centralization
meanfloat = 0;
for(int i = 0; i < numAlters; ++i){
meanfloat = meanfloat + (maxint-stats.degreeArray[i]);
}
stats.degreeNC = (float)(Math.rint(1000*((meanfloat*100)/((numAlters*numAlters)-(3*numAlters)+2))))/1000;
//logger.info("summation is " + meanfloat + "NC is " + stats.degreeNC);
/* find most central closeness alter */
stats.closenessArray = new float[stats.alterList.length];
stats.farnessArray = new int[stats.alterList.length];
maxint = -1;
maxfloat = -1;
int count = 0;
boolean conn = true;
for (int i = 0; i < numAlters; ++i)
{
int total = 0;
count = 0;
for (int j = 0; j < numAlters; ++j)
{
//For farness add maximum value if unconnected
if (stats.proximityMatrix[i][j] == 0)
{
total += numAlters;
++count;
}
else
{
total += stats.proximityMatrix[i][j];
}
}
if (count > 1)
{
conn = false;
count = 0;
}
//Subtract the maximum value added for ego
total = total - numAlters;
stats.farnessArray[i] = total; //(total == 0) ? 0 : ((float) 1 /
// total);
if (stats.farnessArray[i] > 0)
{
sizefloat = (float) numAlters;
stats.closenessArray[i] = (float) (Math.rint(1000 * ((100 * (sizefloat - 1)) / stats.farnessArray[i]))) / 1000;
if (stats.closenessArray[i] > maxfloat)
{
alterindex = i;
maxfloat = stats.closenessArray[i];
}
}
else
{
stats.closenessArray[i] = 0;
}
}
meanfloat = 0;
for (int i = 0; i < numAlters; ++i)
{
meanfloat = meanfloat + stats.closenessArray[i];
}
//logger.info("Mean closeness centrality is "+ meanfloat/size);
stats.mostCentralClosenessAlterValue = maxfloat;
stats.mostCentralClosenessAlterIndex = alterindex;
stats.mostCentralClosenessAlterName = stats.alterList[alterindex];
stats.meanCentralClosenessValue = (float)(Math.rint(1000*meanfloat/numAlters))/1000;
//compute network centralization
if (conn)
{
meanfloat = 0;
for (int i = 0; i < numAlters; ++i)
{
meanfloat = meanfloat + (maxfloat - stats.closenessArray[i]);
}
stats.closenessNC = (float) (Math.rint(1000 * (meanfloat / (((numAlters * numAlters) - (3 * numAlters) + 2) / ((2 * numAlters) - 3))))) / 1000;
}
else
{
//logger.info("Unconnected nw");
stats.closenessNC = -1;
}
}
}
catch (MissingPairException ex)
{
throw new RuntimeException(ex);
}
return stats;
}
private void clearIdentity(int[][] matrix)
{
for (int i = 0; i < this.adjacencyMatrix.length; ++i)
{
matrix[i][i] = 0;
}
}
/********
* For a non-directional adjacency graph represented by the parameter matrix, determines
* shortest path length between each pair of alters
* @param adjacencyMatrix representing non-directed graph of alters
* @return Matrix of shortest path lengths
*/
private int[][] generateProximityMatrix()
{
int size = this.adjacencyMatrix.length;
int[][] outMatrix = new int[size][];
int s, i, j, k;
/* Clear */
for (i = 0; i < size; ++i)
{
outMatrix[i] = (int[]) this.adjacencyMatrix[i].clone();
outMatrix[i][i] = 0;
}
for (i = 0; i < size; ++i)
{
for (j = 0; j < size; ++j)
{
if (outMatrix[j][i] > 0)
{
for (k = 0; k < size; ++k)
{
if (outMatrix[i][k] > 0)
{
s = outMatrix[j][i] + outMatrix[i][k];
if ((outMatrix[j][k] == 0) || (s < outMatrix[j][k]))
{
outMatrix[j][k] = s;
}
}
}
}
}
}
/* Clear */
for (i = 0; i < size; ++i)
{
outMatrix[i][i] = 0;
}
return (outMatrix);
}
/********
* For a non-directional adjacency graph represented by the parameter matrix,
* the Degree Centrality value for each alter. This is simply the number of
* people the alter knows
* @param adjacencyMatrix representing non-directed graph of alters
* @return array of C(D) for each alter
*/
private int[] generateDegreeArray()
{
int[] d = new int[this.adjacencyMatrix.length];
for (int i = 0; i < this.adjacencyMatrix.length; ++i)
{
for (int j = 0; j < this.adjacencyMatrix.length; ++j)
{
if (this.adjacencyMatrix[i][j] > 0)
{
d[i]++;
}
}
}
return d;
}
/********
* For a non-directional adjacency graph represented by the parameter matrix,
* the "Betweenness" value for each alter. The betweenness is the percentage of
* all shortests paths which pass through the alter.
* Based on an algorithm by Ulrik Brandes (2001)
* @return array of C(B) for each alter
*/
private float[] generateBetweennessArray()
{
int size = this.adjacencyMatrix.length;
float[] Cb = new float[size];
int s;
for (s = 0; s < size; ++s)
{
Stack<Integer> S = new Stack<Integer>();
@SuppressWarnings({"unchecked"})
java.util.List<Integer>[] P = new java.util.List[size];
LinkedList<Integer> Q = new LinkedList<Integer>();
int[] spaths = new int[size];
int[] distance = new int[size];
for (int w = 0; w < size; ++w)
{
P[w] = new LinkedList<Integer>();
distance[w] = -1;
}
spaths[s] = 1;
distance[s] = 0;
Q.addLast(new Integer(s));
while (!Q.isEmpty())
{
Integer V = (Integer) Q.removeFirst();
int v = V.intValue();
S.push(V);
for (int w = 0; w < size; ++w)
{
if ((w != v) && (adjacencyMatrix[w][v] > 0))
{
// w found for first time?
if (distance[w] < 0)
{
Q.addLast(new Integer(w));
distance[w] = distance[v] + 1;
}
// shortest path to w via v?
if (distance[w] == (distance[v] + 1))
{
spaths[w] += spaths[v];
P[w].add(new Integer(v));
}
}
}
}
// S returns vertices in order of non-increasing distance from s
float[] dependency = new float[size];
while (!S.empty())
{
int w = ((Integer) S.pop()).intValue();
Iterator it = P[w].iterator();
while (it.hasNext())
{
int v = ((Integer) it.next()).intValue();
dependency[v] += (spaths[v] + (spaths[v] * dependency[w])) / spaths[w];
}
if (w != s)
{
Cb[w] += dependency[w];
}
}
}
return (Cb);
}
/********
* For a non-directional adjacency graph represented by the parameter matrix,
* counts the number of cliques in the graph
* Based on Bron Kerbosch [73]
* @return Set of Sets. Each Set represents one clique
*/
private Set<Stack<Integer>> identifyCliques()
{
int[][] matrix = (int[][]) adjacencyMatrix.clone();
int size = matrix.length;
int[] all = new int[size];
Stack<Integer> compsub = new Stack<Integer>();
Set<Stack<Integer>> cliqueSet = new HashSet<Stack<Integer>>();
for (int c = 0; c < size; ++c)
{
all[c] = c;
}
// Set identity
for (int i = 0; i < size; ++i)
matrix[i][i] = 1;
extendVersion2(matrix, compsub, cliqueSet, all, 0, size, 0);
return (cliqueSet);
}
/********
* For a non-directional adjacency graph represented by the parameter matrix,
* counts the number of all fully connected groups in the graph
* * @return Set of Sets. Each Set represents one fully connected graph
*/
private Set<Stack<Integer>> identifyAllConnections()
{
int[][] matrix = (int[][]) adjacencyMatrix.clone();
int size = matrix.length;
int[] all = new int[size];
Stack<Integer> compsub = new Stack<Integer>();
Set<Stack<Integer>> allSet = new HashSet<Stack<Integer>>();
for (int c = 0; c < size; ++c)
{
all[c] = c;
}
// Set identity
for (int i = 0; i < size; ++i)
matrix[i][i] = 1;
extendVersion2(matrix, compsub, allSet, all, 0, size, 1);
return (allSet);
}
//Returns the number of components of size n in the network
private int countComponentSize(int n)
{
int count = 0;
Iterator it = this.componentSet.iterator();
while (it.hasNext())
{
Set s = (Set) it.next();
if (s.size() == n)
{
++count;
}
}
return count;
}
@SuppressWarnings("unchecked")
private void extendVersion2(int[][] pMatrix, Stack<Integer> compsub, Set<Stack<Integer>> cliqueSet, int[] old, int ne, int ce,
int cliqueOrAll)
{
int[] newarray = new int[ce];
int nod, fixp = 0;
int newne, newce, i, j, count, pos = 0, p, s = 0, sel, minnod;
minnod = ce;
nod = 0;
// Determine each counter value and look for minimum
for (i = 0; (i < ce) && (minnod != 0); ++i)
{
p = old[i];
count = 0;
// Count Disconnections
for (j = ne; (j < ce) && (count < minnod); ++j)
{
if (pMatrix[p][old[j]] == 0)
{
++count;
// Save position of potential candidate
pos = j;
}
}
// Test new minimum
if (count < minnod)
{
fixp = p;
minnod = count;
if (i < ne)
{
s = pos;
}
else
{
s = i;
nod = 1;
}
}
}
/***
* If fixed point initially chosen from candidates then number of
* disconnections will be preincreased by one
*/
for (nod += minnod; nod >= 1; --nod)
{
/* Interchange */
p = old[s];
old[s] = old[ne];
old[ne] = p;
sel = p;
/* Fill new set "not" */
newne = 0;
for (i = 0; i < ne; ++i)
{
if (pMatrix[sel][old[i]] > 0)
{
newarray[newne++] = old[i];
}
}
newce = newne;
/* Fill new set "cand" */
for (i = ne + 1; i < ce; ++i)
{
if (pMatrix[sel][old[i]] > 0)
{
newarray[newce++] = old[i];
}
}
/* Add to compsub */
compsub.push(sel);
if (newce == 0)
{
if (cliqueOrAll == 1)
{
/* Add if all the disconnections are needed */
/* Return the fully connected graph */
if (compsub.size() >= 1)
{
cliqueSet.add((Stack<Integer>)compsub.clone());
}
}
else
{
/* Add if only the cliques are needed */
/* Return Clique */
if (compsub.size() >= MINIMUM_CLIQUE)
{
cliqueSet.add((Stack<Integer>)compsub.clone());
}
}
}
else if (newne < newce)
{
extendVersion2(pMatrix, compsub, cliqueSet, newarray, newne, newce, cliqueOrAll);
}
/* Remove from compsub */
compsub.pop();
ne++;
if (nod > 1)
{
for (s = ne; pMatrix[fixp][old[s]] > 0; ++s);
}
}
}
/********
* For a non-directional adjacency graph represented by the parameter matrix,
* identifies all unconnected components of the graph
* @param cliqueSet Set of stacks returned by identifyCliques
* @return Set of Sets. Each Set represents one component
*/
private Set<Set<Integer>> identifyComponents()
{
Set<Set<Integer>> s = new HashSet<Set<Integer>>();
LinkedList<Set<Integer>> list = new LinkedList<Set<Integer>>();
boolean merged;
/* clone stacks so this is non-destructive */
for (Iterator<Stack<Integer>> it = this.allSet.iterator(); it.hasNext();)
{
list.add(
new HashSet<Integer>(it.next())
);
}
while (list.size() > 0)
{
merged = false;
Iterator<Set<Integer>> it = list.iterator();
Set<Integer> component = it.next();
while (it.hasNext())
{
Set<Integer> intersection = new HashSet<Integer>(component);
Set<Integer> compareClique = it.next();
intersection.retainAll(compareClique);
if (intersection.size() > 0)
{
component.addAll(compareClique);
it.remove();
merged = true;
}
}
if (merged == false)
{
s.add(component);
list.remove(0);
}
}
return s;
}
/********
* Calculates compositional measures of alter questions
* Generates percentage summary for categorical, and average for numerical
*/
private void generateAlterStatArray()
{
List<Long> qList = _study.getQuestionOrder(AlterQuestion.class);
Iterator<Long> qIt = qList.iterator();
int index = 0;
alterSummary = new Integer[alterList.length][];
/* Count qList Questions which are categorical or numerical */
while (qIt.hasNext())
{
Question q = _study.getQuestions().getQuestion((Long) qIt.next());
if ((q.answerType.equals(CategoricalAnswer.class)) || (q.answerType.equals(NumericalAnswer.class)))
index++;
}
alterStatArray = new AlterStats[index];
for (int i = 0; i < index; ++i)
{
alterStatArray[i] = new AlterStats();
}
for (int i = 0; i < alterList.length; ++i)
{
alterSummary[i] = new Integer[index];
}
index = 0;
qIt = qList.iterator();
while (qIt.hasNext())
{
Long qId = (Long) qIt.next();
Question q = _study.getQuestions().getQuestion(qId);
if ((q.answerType.equals(CategoricalAnswer.class)) || (q.answerType.equals(NumericalAnswer.class)))
{
Set<Answer> answerSet = _interview.getAnswerSubset(qId);
Iterator<Answer> aIt = answerSet.iterator();
alterStatArray[index].questionId = qId;
alterStatArray[index].qTitle = q.title;
alterStatArray[index].answerType = q.answerType;
if (q.answerType.equals(NumericalAnswer.class))
{
alterStatArray[index].answerText = new String[] { "Mean" };
alterStatArray[index].answerTotals = new int[1];
}
else if (q.answerType.equals(CategoricalAnswer.class))
{
alterStatArray[index].answerTotals = new int[q.getSelections().size()];
alterStatArray[index].answerText = new String[q.getSelections().size()];
for (int i = 0; i < q.getSelections().size(); ++i)
{
// alterStatArray[index].answerText[i] = q.selections[q.selections.length - (i + 1)].getString();
alterStatArray[index].answerText[i] = q.getSelections().get(i).getString();
}
}
while (aIt.hasNext())
{
try {
Answer a = (Answer) aIt.next();
if (a.isAnswered())
{
alterSummary[a.firstAlter()][index] = new Integer(a.getValue());
if (q.answerType.equals(NumericalAnswer.class))
{
if (a.getValue() != -1)
{
alterStatArray[index].answerTotals[0] += a.getValue();
alterStatArray[index].answerCount++;
}
}
else if (q.answerType.equals(CategoricalAnswer.class))
{
alterStatArray[index].answerTotals[a.getIndex()] += 1;
alterStatArray[index].answerCount++;
}
}
else
{
alterSummary[a.firstAlter()][index] = new Integer(-1);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
index++;
}
}
}
/******************************************************************************
* Writes matrix alter-prompt to see which alters has appeared in which alter prompt
* questions.
*
* @param alterPromptWriter
* File to write data to
*
* @throws IOException
*
*/
public void writeAlterByPromptFile(PrintWriter alterPromptWriter, String name) throws IOException
{
logger.info("Writing Alter By Prompt matrix");
CSVWriter alterByPromptCSVWriter = new CSVWriter(alterPromptWriter);
writeAlterByPromptMatrix( name, alterByPromptCSVWriter );
alterByPromptCSVWriter.close();
}
private void writeAlterByPromptMatrix(String name, CSVWriter w){
List <String> columnNames = new ArrayList<String>();
columnNames.add(name);
int numPrompts = _study.getQuestionOrder(AlterPromptQuestion.class).size();
for (int i = 0; i < numPrompts; ++i)
{
columnNames.add(FileHelpers.formatForCSV("Question "+i));
}
w.writeNext(columnNames.toArray(new String[]{}));
for (int i = 0; i < alterList.length; i++)
{
List<String> row = new ArrayList<String>();
//_study.getQuestionIterator(AlterPromptQuestion.class);
row.add(FileHelpers.formatForCSV(alterList[i]));
for (int j = 0; j < numPrompts ; ++j)
{
row.add(""+ alter_alterPromptMatrix[i][j]);
}
w.writeNext(row.toArray(new String[]{}));
}
}
/***************************************************************************
* Writes all questions to a package file for later use
*
* @param f
* File to write data to
* @param stats
* Statistics Object
* @throws IOException
* @throws IOException
*/
public void writeAdjacencyFile(PrintWriter adjacencyWriter, String name, boolean weighted) throws IOException {
logger.info("Writing "+(weighted ? "" : "non-")+"weighted adjacency file for " + name);
CSVWriter adjacencyCSVWriter = new CSVWriter(adjacencyWriter);
writeAdjacencyArray(name, adjacencyCSVWriter, weighted);
adjacencyCSVWriter.close();
}
/********
* Write proximity array for current question to a printwriter
* @param name Name of Ego
* @param w PrintWriter
* @param weighted use weighted proximity array
*/
private void writeAdjacencyArray(String name, CSVWriter w, boolean weighted)
{
// Write column names
List<String> columnNames = new ArrayList<String>();
columnNames.add(name);
for (int i = 0; i < alterList.length; ++i)
{
columnNames.add(FileHelpers.formatForCSV(alterList[i]));
}
w.writeNext(columnNames.toArray(new String[]{}));
// Write other rows
for (int i = 0; i < alterList.length; ++i)
{
List<String> row = new ArrayList<String>();
row.add(FileHelpers.formatForCSV(alterList[i]));
for (int j = 0; j < alterList.length; ++j)
{
row.add(""+(weighted ? weightedAdjacencyMatrix[i][j] : adjacencyMatrix[i][j]));
}
w.writeNext(row.toArray(new String[]{}));
}
}
/********
* Write alters answer summary to a printwriter
* @param w PrintWriter
*/
public void writeAlterArray(PrintWriter w)
{
// Write column names
w.write("Alter_Name");
for (int i = 0; i < alterStatArray.length; ++i)
{
w.write(", " + FileHelpers.formatForCSV(alterStatArray[i].qTitle));
}
w.println(", Degree, Closeness, Betweenness");
for (int i = 0; i < alterList.length; ++i)
{
w.print(FileHelpers.formatForCSV(alterList[i]));
for (int j = 0; j < alterSummary[0].length; ++j)
{
w.print(", " + alterSummary[i][j]);
}
w.println(", " + degreeArray[i] + ", " + closenessArray[i] + ", " + betweennessArray[i]);
}
}
/********
* Calculates compositional measures of alter questions
* Generates percentage summary for categorical, and average for numerical
*/
public void writeTextAnswers(PrintWriter w)
{
List qList;
Iterator qIt;
qList = _interview.getEgoAnswers();
qIt = qList.iterator();
while (qIt.hasNext())
{
Answer answer = (Answer) qIt.next();
Question q = _study.getQuestions().getQuestion(answer.getQuestionId());
if (q.answerType.equals(TextAnswer.class))
{
if (answer.isAnswered())
{
w.println("Ego Question: " + q.title);
w.println("Text: " + q.text);
w.println(answer.string);
}
}
}
qList = _study.getQuestionOrder(AlterQuestion.class);
qIt = qList.iterator();
while (qIt.hasNext())
{
Long qId = (Long) qIt.next();
Question q = _study.getQuestions().getQuestion(qId);
if (q.answerType.equals(TextAnswer.class))
{
w.println("Alter Question: " + q.title);
w.println("Text: " + q.text);
Set answerSet = _interview.getAnswerSubset(qId);
Iterator aIt = answerSet.iterator();
while (aIt.hasNext())
{
Answer a = (Answer) aIt.next();
if (a.isAnswered())
{
w.println(alterList[a.firstAlter()] + ": " + a.string);
}
}
}
}
}
/**
* @return Returns the interview.
*/
public Interview getInterview()
{
return _interview;
}
/**
* @return Returns the study.
*/
public Study getStudy()
{
return _study;
}
}