После многократного поиска в Java единственное решение, которое, похоже, работает для меня, - это вручную прочитать файл jar, если вы не находитесь в среде разработки (IDE):
/** @return The root folder or jar file that the class loader loaded from */
public static final File getClasspathFile() {
return new File(YourMainClass.class.getProtectionDomain().getCodeSource().getLocation().getFile());
}
/** @param resource The path to the resource
* @return An InputStream containing the resource's contents, or
* <b><code>null</code></b> if the resource does not exist */
public static final InputStream getResourceAsStream(String resource) {
resource = resource.startsWith("/") ? resource : "/" + resource;
if(getClasspathFile().isDirectory()) {//Development environment:
return YourMainClass.class.getResourceAsStream(resource);
}
final String res = resource;//Jar or exe:
return AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
@SuppressWarnings("resource")
@Override
public InputStream run() {
try {
final JarFile jar = new JarFile(getClasspathFile());
String resource = res.startsWith("/") ? res.substring(1) : res;
if(resource.endsWith("/")) {//Directory; list direct contents:(Mimics normal getResourceAsStream("someFolder/") behaviour)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Enumeration<JarEntry> entries = jar.entries();
while(entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if(entry.getName().startsWith(resource) && entry.getName().length() > resource.length()) {
String name = entry.getName().substring(resource.length());
if(name.contains("/") ? (name.endsWith("/") && (name.indexOf("/") == name.lastIndexOf("/"))) : true) {//If it's a folder, we don't want the children's folders, only the parent folder's children!
name = name.endsWith("/") ? name.substring(0, name.length() - 1) : name;
baos.write(name.getBytes(StandardCharsets.UTF_8));
baos.write('\r');
baos.write('\n');
}
}
}
jar.close();
return new ByteArrayInputStream(baos.toByteArray());
}
JarEntry entry = jar.getJarEntry(resource);
InputStream in = entry != null ? jar.getInputStream(entry) : null;
if(in == null) {
jar.close();
return in;
}
final InputStream stream = in;//Don't manage 'jar' with try-with-resources or close jar until the
return new InputStream() {//returned stream is closed(closing the jar closes all associated InputStreams):
@Override
public int read() throws IOException {
return stream.read();
}
@Override
public int read(byte b[]) throws IOException {
return stream.read(b);
}
@Override
public int read(byte b[], int off, int len) throws IOException {
return stream.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return stream.skip(n);
}
@Override
public int available() throws IOException {
return stream.available();
}
@Override
public void close() throws IOException {
try {
jar.close();
} catch(IOException ignored) {
}
stream.close();
}
@Override
public synchronized void mark(int readlimit) {
stream.mark(readlimit);
}
@Override
public synchronized void reset() throws IOException {
stream.reset();
}
@Override
public boolean markSupported() {
return stream.markSupported();
}
};
} catch(Throwable e) {
e.printStackTrace();
return null;
}
}
});
}
Примечание: приведенный выше код, похоже, работает правильно для файлов jar, если он находится в основном классе. Я не уверен, почему.
Я предполагаю, что вы хотели набрать:
glm1 <-glm(Y ~ X1+X2+X3, family=binomial(link=logit))
glm2 <-glm(Y ~ X1 + X2, family=binomial(link=logit))
Интерфейс формулы для функций регрессии R не распознает запятые как добавление ковариатов к RHS формулы. И не используйте attach()
; используйте аргумент данных для функций регрессии.
Чтобы избежать ошибки "models were not all fitted to the same size of dataset"
, вы должны подгонять обе модели к одному и тому же подмножеству данных. Существует два простых способа сделать это:
data=glm1$model
во второй модели fit data=na.omit(orig.data[ , all.vars(formula(glm1))])
во втором model fit Вот пример воспроизводимости с использованием lm
(для glm
тот же подход должен работать) и update
:
# 1st approach
# define a convenience wrapper
update_nested <- function(object, formula., ..., evaluate = TRUE){
update(object = object, formula. = formula., data = object$model, ..., evaluate = evaluate)
}
# prepare data with NAs
data(mtcars)
for(i in 1:ncol(mtcars)) mtcars[i,i] <- NA
xa <- lm(mpg~cyl+disp, mtcars)
xb <- update_nested(xa, .~.-cyl)
anova(xa, xb)
## Analysis of Variance Table
##
## Model 1: mpg ~ cyl + disp
## Model 2: mpg ~ disp
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 26 256.91
## 2 27 301.32 -1 -44.411 4.4945 0.04371 *
## ---
## Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# 2nd approach
xc <- update(xa, .~.-cyl, data=na.omit(mtcars[ , all.vars(formula(xa))]))
anova(xa, xc)
## Analysis of Variance Table
##
## Model 1: mpg ~ cyl + disp
## Model 2: mpg ~ disp
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 26 256.91
## 2 27 301.32 -1 -44.411 4.4945 0.04371 *
## ---
## Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
См. также:
Причина хорошо описана Грегом Сноу. Альтернативным и очень простым решением является добавление новой переменной, совпадающей с NA NA проблемной переменной, и в противном случае со значением 1. Включите ее в обе модели, и R исключит те же строки в обеих моделях (-> набор данных будет соответствовать).
Решение состоит в том, чтобы использовать:
glm1 <-glm(Y ~ X1 + X2 + X3, family = binomial(link = logit), na.action = na.exclude)
glm2 <-glm(Y ~ X1 + X2, family = binomial(link = logit), na.action = na.exclude)
anova(glm2,glm1)
Это приведет к тому, что R включает случаи с отсутствующими данными (NA) в установленной модели. Это гарантирует, что наборы данных идентичны для разных моделей подгонки независимо от того, как распределяются недостающие данные.
Основной причиной этой ошибки является отсутствие значений в одной или нескольких переменных предиктора. В последних версиях R действие по умолчанию состоит в том, чтобы опустить все строки, у которых отсутствуют какие-либо значения (предыдущим значением по умолчанию было создание ошибки). Так, например, если в кадре данных есть 100 строк и в X3 есть одно отсутствующее значение, тогда ваша модель glm1 будет соответствовать 99 строкам данных (отбрасывая строку, где отсутствует X3), но объект glm2 будет полностью укомплектован 100 строк данных (поскольку он не использует X3, никакие строки не нужно удалять).
Итак, функция anova
дает вам ошибку, потому что две модели подходят для разных наборов данных (и как вы вычисляете степени свободы и т. д.).
Одним из решений является создание нового фрейма данных, который имеет только те столбцы, которые будут использоваться, по крайней мере, в одной из ваших моделей и удалять все строки с любыми (функция na.omit
или na.exclude
сделает это проще), затем установите обе модели в один и тот же фрейм данных, у которого нет каких-либо отсутствующих значений.
Другими вариантами были бы просмотр инструментов для множественного вменения или других способов устранения недостающих данных.