Obj-C: Вычислить стандартное отклонение NSArray объектов NSNumber?

Если у меня есть NSArray объектов NSNumber, как я могу рассчитать стандартное отклонение чисел в массиве?

Ответ 1

Предполагая, что это безопасно обрабатывать все NSNumbers как плавающие по двойной длине (так что вы потеряете некоторую точность, если у вас есть 64-битные целые числа на крайних концах диапазона), и я правильно запомнил формулу реализация может быть:

- (NSNumber *)meanOf:(NSArray *)array
{
    double runningTotal = 0.0;

    for(NSNumber *number in array)
    {
        runningTotal += [number doubleValue];
    }

    return [NSNumber numberWithDouble:(runningTotal / [array count])];
}

- (NSNumber *)standardDeviationOf:(NSArray *)array
{
    if(![array count]) return nil;

    double mean = [[self meanOf:array] doubleValue];
    double sumOfSquaredDifferences = 0.0;

    for(NSNumber *number in array)
    {
         double valueOfNumber = [number doubleValue];
         double difference = valueOfNumber - mean;
         sumOfSquaredDifferences += difference * difference;
    }

    return [NSNumber numberWithDouble:sqrt(sumOfSquaredDifferences / [array count])];
}

Ответ 2

Вы можете использовать встроенные функции NSExpression.

NSArray *numbers = @[@1, @2, @3, @4, @5, @6, @7, @8];
NSExpression *expression = [NSExpression expressionForFunction:@"stddev:" arguments:@[[NSExpression expressionForConstantValue:numbers]]];
NSNumber *value = [expression expressionValueWithObject:nil context:nil];
NSLog(@"%@,", value); // => 2.29128...

Для получения дополнительной информации посетите официальную documentation и эту статью NSHipster.

Ответ 3

Здесь категория NSArray для облегчения подобных задач с использованием NSExpression, аналогичная методу Tiago. Вы можете передать любое NSExpression, которое вы хотите рассчитать как строку (двоеточие добавлено в функцию).

@interface NSArray (Stats)

- (NSNumber *)calculateStat:(NSString *)stat;

@end

@implementation NSArray (Stats)

- (NSNumber *)calculateStat:(NSString *)stat
{
    NSArray *args = @[[NSExpression expressionForConstantValue:self]];
    NSString *statFormatted = [stat stringByAppendingString:@":"];
    NSExpression *expression = [NSExpression expressionForFunction:statFormatted arguments:args];
    return [expression expressionValueWithObject:nil context:nil];
}

@end

Используйте так:

NSNumber *result = [myArray calculateStat:@"stddev"];

Ответ 4

Здесь ссылка к алгоритму, который вы могли бы использовать. Я не знаю каких-либо встроенных библиотек статистики Objective C, поэтому я бы просто сам реализовал алгоритм. Ссылка делает это на Java, но ее легко конвертировать.

Ответ 5

Для этого есть хороший код Rosetta Code. Чтобы пройти через ваш NSArray (вместо массива C, как в своем примере), просто используйте этот код вместе со своей реализацией SDAccum:

- (double)computeStandardDeviationWithArray:(NSArray *)numberArray
{
    double sd;
    SDAccum *sdacc = [[SDAccum alloc] init];

    for(NSNumber *aNumber in numberArray)
    {
        sd = [sdacc value: [aNumber doubleValue]];
    }

    [sdacc release];
    return sd;
}

Ответ 6

Вот еще одна версия, которую я использовал некоторое время назад.

NSArray *numbers = [NSArray arrayWithObjects:[NSNumber numberWithInt:...],
                                             [NSNumber numberWithInt:...],
                                             [NSNumber numberWithInt:...], nil];

// Compute array average
int total = 0;
int count = [numbers count];

for (NSNumber *item in numbers) {

    total += [item intValue];
}

double average = 1.0 * total / count;

// Sum difference squares
double diff, diffTotal = 0;

for (NSNumber *item in numbers) {

    diff = [item doubleValue] - average;
    diffTotal += diff * diff;
}

// Set variance (average from total differences)
double variance = diffTotal / count; // -1 if sample std deviation

// Standard Deviation, the square root of variance
double stdDeviation = sqrt(variance);