/* * Copyright (c) 2012 Patrick Meyer * * This program 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. * * This program 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 com.itemanalysis.jmetrik.stats.irt.linking; import com.itemanalysis.jmetrik.sql.DataTableName; import com.itemanalysis.psychometrics.data.VariableName; import com.itemanalysis.psychometrics.irt.model.*; import java.sql.*; import java.util.ArrayList; import java.util.LinkedHashMap; public class DbItemParameterSet { public DbItemParameterSet(){ } public LinkedHashMap<String, ItemResponseModel> getFormXItemParameters(Connection conn, DataTableName tableName, ArrayList<LinkingItemPair> commonItems, boolean logisticScale) throws SQLException{ return getItemParameters(conn, tableName, commonItems, true, logisticScale); } public LinkedHashMap<String, ItemResponseModel> getFormYItemParameters(Connection conn, DataTableName tableName, ArrayList<LinkingItemPair> commonItems, boolean logisticScale) throws SQLException{ return getItemParameters(conn, tableName, commonItems, false, logisticScale); } private LinkedHashMap<String, ItemResponseModel> getItemParameters(Connection conn, DataTableName tableName, ArrayList<LinkingItemPair> commonItems, boolean formX, boolean logisticScale) throws SQLException{ LinkedHashMap<String, ItemResponseModel> irmSet = new LinkedHashMap<String, ItemResponseModel>(); PreparedStatement pstmt = null; ResultSet rs = null; ItemResponseModel irm = null; VariableName itemName = new VariableName("name");//must be in item parameter table VariableName modelName = new VariableName("model");//must be in item parameter table VariableName ncatName = new VariableName("ncat");//must be in item parameter table VariableName aparam = new VariableName("aparam"); VariableName bparam = new VariableName("bparam"); VariableName cparam = new VariableName("cparam"); VariableName uparam = new VariableName("uparam"); VariableName scoreWeight = new VariableName("sweight"); VariableName scale = new VariableName("scale"); VariableName step = null; VariableName iName = null; double a = 1, b = 0, c = 0, D = 1.0, u = 1.0, defaultD = 1.0; double[] stepParam = null; String model = "L3"; int ncat = 2; int binaryModelParam = 1;//Rasch model by default if(logisticScale) defaultD = 1.0; else defaultD = 1.7; try{ pstmt = conn.prepareStatement("SELECT * FROM " + tableName.getNameForDatabase() + " WHERE " + itemName.nameForDatabase() + "=?"); //get meta data to check for variable names -- could be slow for some drivers ResultSetMetaData rsmd = pstmt.getMetaData(); int ncols = rsmd.getColumnCount(); ArrayList<VariableName> colNames = new ArrayList<VariableName>(); for(int i=0;i<ncols;i++){ VariableName vName = new VariableName(rsmd.getColumnName(i+1)); colNames.add(vName); } //loop over common items and read values from database for(LinkingItemPair pair : commonItems){ a = 1; b = 0; c = 0; u = 1; D = defaultD; binaryModelParam = 1; if(formX){ iName = pair.getXVariable(); }else{ iName = pair.getYVariable(); } pstmt.setString(1, iName.toString()); rs = pstmt.executeQuery(); rs.next(); //read resultset -- required fields model = rs.getString(modelName.nameForDatabase()); ncat = rs.getInt(ncatName.nameForDatabase()); //discrimination parameter -- optional if(colNames.contains(aparam)){ a = rs.getDouble(aparam.nameForDatabase()); if(rs.wasNull()){ a = 1.0; }else{ binaryModelParam = 2; } }else{ a = 1.0; } //scale factor -- optional if(colNames.contains(scale)){ D = rs.getDouble(scale.nameForDatabase()); if(rs.wasNull()) D = defaultD; }else{ D = defaultD; } //binary item response model if("L4".equals(model) || "L3".equals(model) || "L2".equals(model) || "L1".equals(model)){ //lower-asymptote parameter -- optional if(colNames.contains(cparam)){ c = rs.getDouble(cparam.nameForDatabase()); if(rs.wasNull()){ c = 0.0; }else{ binaryModelParam = 3; } } //upper-asymptote parameter -- optional if(colNames.contains(uparam)){ u = rs.getDouble(uparam.nameForDatabase()); if(rs.wasNull()){ u = 1.0; }else{ binaryModelParam = 4; } } //difficulty parameter -- required column for L3 b = rs.getDouble(bparam.nameForDatabase()); //Set specific type of binary model because irm constructor will //determine number of parameters from constructor. if("L4".equals(model)){ irm = new Irm4PL(a, b, c, u, D); }else{ if(binaryModelParam==1){ irm = new Irm3PL(b, D); }else if(binaryModelParam==2){ irm = new Irm3PL(a, b, D); }else{ irm = new Irm3PL(a, b, c, D); } irm.setSlipping(u); } }else if("PC1".equals(model) || "PC4".equals(model)){ //These item response models store step parameters in array of size ncat and the first value is always zero. stepParam = new double[ncat]; stepParam[0] = 0;//This is the new part for(int k=1;k<ncat;k++){ step = new VariableName("step" + k); stepParam[k] = rs.getDouble(step.nameForDatabase()); } if("PC1".equals(model)){ irm = new IrmGPCM(a, stepParam, D); } if("PC4".equals(model)){ irm = new IrmPCM2(stepParam, D); } }else{ //polytomous item response models //These polytomous models store step parameters in an array of size ncat-1 //TODO change to new parameter array of size ncat stepParam = new double[ncat-1]; for(int k=1;k<ncat;k++){ step = new VariableName("step" + k); stepParam[k-1] = rs.getDouble(step.nameForDatabase()); } if("PC2".equals(model)){ b = rs.getDouble(bparam.nameForDatabase()); irm = new IrmGPCM2(a, b, stepParam, D); }else if("PC3".equals(model)){ b = rs.getDouble(bparam.nameForDatabase()); irm = new IrmPCM(b, stepParam, D); }else if("GR".equals(model)){ irm = new IrmGRM(a, stepParam, D); } } //read score weights if provided if(colNames.contains(scoreWeight)){ String s = rs.getString(scoreWeight.nameForDatabase()); String[] sa = s.split("\\s+"); double[] sw = new double[sa.length]; for(int i=0;i<sa.length;i++){ sw[i] = Double.parseDouble(sa[i]); } irm.setScoreWeights(sw); } irm.setName(iName); //common name given to formX and formY items irmSet.put(pair.getPairName(), irm); }//end loop over common items return irmSet; }catch(SQLException ex){ throw(ex); }finally{ if(pstmt!=null) pstmt.close(); } } /** * Tihs methods will get IRT item parameter and model information from a database table. * It will get the information for a list of selected variables. * * @param conn connection to the database * @param tableName name of database table that contains item parameter and model information * @param selectedItems selected items for which database information is sought * @param logisticScale default IRT scale parameter * @return * @throws SQLException */ public LinkedHashMap<String, ItemResponseModel> getItemParameters(Connection conn, DataTableName tableName, ArrayList<VariableName> selectedItems, boolean logisticScale) throws SQLException{ LinkedHashMap<String, ItemResponseModel> irmSet = new LinkedHashMap<String, ItemResponseModel>(); PreparedStatement pstmt = null; ResultSet rs = null; ItemResponseModel irm = null; VariableName itemName = new VariableName("name");//must be in item parameter table VariableName modelName = new VariableName("model");//must be in item parameter table VariableName ncatName = new VariableName("ncat");//must be in item parameter table VariableName aparam = new VariableName("aparam"); VariableName bparam = new VariableName("bparam"); VariableName cparam = new VariableName("cparam"); VariableName uparam = new VariableName("uparam"); VariableName scoreWeight = new VariableName("sweight"); VariableName scale = new VariableName("scale"); VariableName step = null; double a = 1, b = 0, c = 0, u = 1.0, D = 1.0, defaultD = 1.0; double[] stepParam = null; String model = "L3"; int ncat = 2; int binaryModelParam = 1;//Rasch model by default if(logisticScale) defaultD = 1.0; else defaultD = 1.7; try{ pstmt = conn.prepareStatement("SELECT * FROM " + tableName.getNameForDatabase() + " WHERE " + itemName.nameForDatabase() + "=?"); //get meta data to check for variable names -- could be slow for some drivers ResultSetMetaData rsmd = pstmt.getMetaData(); int ncols = rsmd.getColumnCount(); ArrayList<VariableName> colNames = new ArrayList<VariableName>(); for(int i=0;i<ncols;i++){ VariableName vName = new VariableName(rsmd.getColumnName(i+1)); colNames.add(vName); } for(VariableName v : selectedItems){ a = 1; b = 0; c = 0; u = 1.0; D = defaultD; binaryModelParam = 1; pstmt.setString(1, v.toString()); rs = pstmt.executeQuery(); rs.next(); //read resultset -- required fields model = rs.getString(modelName.nameForDatabase()); ncat = rs.getInt(ncatName.nameForDatabase()); //discrimination parameter -- optional if(colNames.contains(aparam)){ a = rs.getDouble(aparam.nameForDatabase()); if(rs.wasNull()){ a = 1.0; }else{ binaryModelParam = 2; } }else{ a = 1.0; } //scale factor -- optional if(colNames.contains(scale)){ D = rs.getDouble(scale.nameForDatabase()); if(rs.wasNull()) D = defaultD; }else{ D = defaultD; } //binary item response model if("L4".equals(model) || "L3".equals(model) || "L2".equals(model) || "L1".equals(model)){ //lower-asymptote parameter -- optional if(colNames.contains(cparam)){ c = rs.getDouble(cparam.nameForDatabase()); if(rs.wasNull()){ c = 0.0; }else{ binaryModelParam = 3; } } //upper-asymptote parameter -- optional if(colNames.contains(uparam)){ u = rs.getDouble(uparam.nameForDatabase()); if(rs.wasNull()){ u = 1.0; }else{ binaryModelParam = 4; } } //difficulty parameter -- required column for L3 b = rs.getDouble(bparam.nameForDatabase()); //Set specific type of binary model because irm constructor will //determine number of parameters from constructor. if("L4".equals(model)){ irm = new Irm4PL(a, b, c, u, D); }else{ if(binaryModelParam==1){ irm = new Irm3PL(b, D); }else if(binaryModelParam==2){ irm = new Irm3PL(a, b, D); }else{ irm = new Irm3PL(a, b, c, D); } irm.setSlipping(u); } }else if("PC1".equals(model) || "PC4".equals(model)){ //polytomous item response models that use the new parameter array with zero in the first index //TODO convert the extraction of other polytomous items to this format once changed in psychometrics library stepParam = new double[ncat]; stepParam[0] = 0;//This is the new part for(int k=1;k<ncat;k++){ step = new VariableName("step" + k); stepParam[k] = rs.getDouble(step.nameForDatabase()); } if("PC1".equals(model)){ irm = new IrmGPCM(a, stepParam, D); } if("PC4".equals(model)){ irm = new IrmPCM2(stepParam, D); } }else{ //polytomous item response models //all polytomous models have step parameter variables in database stepParam = new double[ncat-1]; for(int k=1;k<ncat;k++){ step = new VariableName("step" + k); stepParam[k-1] = rs.getDouble(step.nameForDatabase()); } //GPCM difficulty + thresholds if("PC2".equals(model)){ b = rs.getDouble(bparam.nameForDatabase()); irm = new IrmGPCM2(a, b, stepParam, D); } //Partial credit model difficulty + thresholds else if("PC3".equals(model)){ b = rs.getDouble(bparam.nameForDatabase()); irm = new IrmPCM(b, stepParam, D); } //Graded response model else if("GR".equals(model)){ irm = new IrmGRM(a, stepParam, D); } } //read score weights if provided if(colNames.contains(scoreWeight)){ String s = rs.getString(scoreWeight.nameForDatabase()); String[] sa = s.split("\\s+"); double[] sw = new double[sa.length]; for(int i=0;i<sa.length;i++){ sw[i] = Double.parseDouble(sa[i]); } irm.setScoreWeights(sw); } irm.setName(v); //add irm to collection irmSet.put(irm.getName().toString(), irm); } return irmSet; }catch(SQLException ex){ throw(ex); }finally{ if(pstmt!=null) pstmt.close(); } } }