如何在 java 中获取白天的均值和标准差
How to get mean and standard deviation of daytimes in java
对于用 Java 编写的 Android Studio 项目,我有一个白天列表,它收集小时和分钟作为整数,如下所示:
List<Integer> times = new ArrayList<>();
int hour = 16;
int minute = 25;
int time = hour * 60 + minute;
times.add(time);
我需要时间的均值和标准差以获得非异常值时间列表。但是,普通的均值和标准差似乎不起作用。这是我现在正在做的事情:
private List<String> getNonOutlierTimes() {
int mean = convertToTime((times.stream().mapToInt(Integer::intValue).sum()) / times.size());
int sd = (int) calculateStandardDeviation(mean);
int maxTime = (int) (mean + 1.5 * sd);
int minTime = (int) (mean - 1.5 * sd);
List<Integer> nonOutliers = new ArrayList<>();
for (int i = 0; i < times.size(); i++) {
if ((times.get(i) <= maxTime) && (times.get(i) >= minTime)) {
nonOutliers.add(times.get(i));
}
}
List<String> nonOutliersStr = new ArrayList<>();
for (Integer nonOutlier : nonOutliers) {
nonOutliersStr.add(convertIntTimesToStr(nonOutlier));
}
return nonOutliersStr;
}
private int convertToTime(int a) {
if ((a < 24*60) && (a >= 0)) {
return a;
} else if (a < 0) {
return 24*60 + a;
} else {
return a % (24*60);
}
}
private double calculateStandardDeviation(int mean) {
int sum = 0;
for (int j = 0; j < times.size(); j++) {
int time = convertToTime(times.get(j));
sum = sum + ((time - mean) * (time - mean));
}
double squaredDiffMean = (double) (sum) / (times.size());
return (Math.sqrt(squaredDiffMean));
}
private String convertIntTimesToStr(int time) {
String hour = (time / 60) + "";
int minute = time % 60;
String minuteStr = minute < 10 ? "0" + minute : "" + minute;
return hour + ":" + minuteStr;
}
虽然所有的计算都是基于有效的统计数据,但计算出的均值和标准差似乎无关紧要。例如,当时间列表包含以下内容时:
225(03:45 上午),
90(凌晨 01:30),
0(上午 12:00),
1420(晚上 11 点 40 分),
730(下午 12:10)
我需要一个非异常值列表,其中包含:
1420(晚上 11:40),
0(上午 12:00),
90(凌晨 01:30),
225(03:45上午)
其中实际输出为:
0(上午 12:00),
90(凌晨 01:30),
225(03:45 下午),
730(下午 12:10)
也就是说,我需要的是大多数时间所在的位置。更具体地说,考虑包含整数 1380(23:00 或 11:00 pm)、1400(23:20 或 11:20 pm)和 60(01:00是)。这些时间的平均值是 945(下午 15:45 或 03:45),我需要平均值位于 23:00 和 01:00 之间。
我已经找到this solution两次的列表。但是,我的 times.size() 总是大于 2,我也想计算标准差。因此,非常感谢您在这方面的帮助。
提前致谢。
您使用的不是实数,而是以 1440 为模的数。在这种情况下,除以自然数的定义不明确或更好 n x = a
每个 [=15] 都有 n
个解决方案=].例如。 3 x = 300
有解决方案 300 / 3
、1740 / 3
和 3180 / 3
(300
、1740
和 3180
是同一元素的不同表示300
).
因此,您不能在一天中的时间范围内谈论算术平均值。然而,一天中的两个时间 之间的距离是 明确定义的:21:00 和 23:00 之间的距离以及 [=67] 之间的距离是 2 小时=] 和 1:00。因此我们可以采用 "mean":
的另一种定义
- 我们称均值 一天中与数据的平方距离总和最小的时间。这是实数的通常平均值的 属性。
幸运的是,可以证明,这个新的均值是n x = sum of values
的解之一。这些解决方案之间的变化是与数据的平方距离之和,我们必须选择最小的一个。
假设我们有一个 LocalTime
的列表:
private static final long DAY = TimeUnit.DAYS.toSeconds(1L);
private static final double HALF_DAY = DAY / 2;
private static final List<LocalTime> times = Arrays.asList(
LocalTime.of(3, 45),
LocalTime.of(1, 30),
LocalTime.of(0, 0),
LocalTime.of(23, 40),
LocalTime.of(12, 10));
我们可以在 “通常” 确定中计算平均值和平方和(我在 0 到 86400 之间以秒计算):
public static void printMeanVariance(final List<LocalTime> times) {
final List<Double> dTimes = times.stream().mapToDouble(LocalTime::toSecondOfDay).boxed().collect(Collectors.toList());
dTimes.sort(Double::compareTo);
// A valid 'mean' must have max - HALF_DAY < mean < min + HALF_DAY
double max = dTimes.get(dTimes.size() - 1);
int count = 0;
double sum = 0.0, sumOfSquares = 0.0;
for (final Double time : dTimes) {
count++;
sum += time;
sumOfSquares += time * time;
}
// to be continued...
如果这是“意思”它必须满足两个条件:
- “均值”必须在
max + DAY
和min + DAY
之间,其中min
和max
是最小和当前测定中的最大值,
- 通常的方差必须最小。
我们通过每次将 86400 添加到最小值来检查所有确定的这些条件:
// continuation
double average = -1;
double sumOfDistancesSquared = Double.MAX_VALUE;
for (final Double time : dTimes) {
// Check if previous value is admissible
final double tmpAverage = sum / count;
final double tmpSumOfDistancesSquared = sumOfSquares - sum * sum / count;
if (max - HALF_DAY <= tmpAverage && tmpAverage <= time + HALF_DAY && tmpSumOfDistancesSquared < sumOfDistancesSquared) {
average = tmpAverage;
sumOfDistancesSquared = tmpSumOfDistancesSquared;
}
sum += DAY;
max = time + DAY;
sumOfSquares += DAY * (2 * time + DAY);
}
// average has the "real" mean
double sd = Math.sqrt(sumOfDistancesSquared / (count - 1));
System.out.println("Mean = " + LocalTime.ofSecondOfDay((long) average) +
", deviation = " + Duration.ofSeconds((long) sd));
}
}
对于用 Java 编写的 Android Studio 项目,我有一个白天列表,它收集小时和分钟作为整数,如下所示:
List<Integer> times = new ArrayList<>();
int hour = 16;
int minute = 25;
int time = hour * 60 + minute;
times.add(time);
我需要时间的均值和标准差以获得非异常值时间列表。但是,普通的均值和标准差似乎不起作用。这是我现在正在做的事情:
private List<String> getNonOutlierTimes() {
int mean = convertToTime((times.stream().mapToInt(Integer::intValue).sum()) / times.size());
int sd = (int) calculateStandardDeviation(mean);
int maxTime = (int) (mean + 1.5 * sd);
int minTime = (int) (mean - 1.5 * sd);
List<Integer> nonOutliers = new ArrayList<>();
for (int i = 0; i < times.size(); i++) {
if ((times.get(i) <= maxTime) && (times.get(i) >= minTime)) {
nonOutliers.add(times.get(i));
}
}
List<String> nonOutliersStr = new ArrayList<>();
for (Integer nonOutlier : nonOutliers) {
nonOutliersStr.add(convertIntTimesToStr(nonOutlier));
}
return nonOutliersStr;
}
private int convertToTime(int a) {
if ((a < 24*60) && (a >= 0)) {
return a;
} else if (a < 0) {
return 24*60 + a;
} else {
return a % (24*60);
}
}
private double calculateStandardDeviation(int mean) {
int sum = 0;
for (int j = 0; j < times.size(); j++) {
int time = convertToTime(times.get(j));
sum = sum + ((time - mean) * (time - mean));
}
double squaredDiffMean = (double) (sum) / (times.size());
return (Math.sqrt(squaredDiffMean));
}
private String convertIntTimesToStr(int time) {
String hour = (time / 60) + "";
int minute = time % 60;
String minuteStr = minute < 10 ? "0" + minute : "" + minute;
return hour + ":" + minuteStr;
}
虽然所有的计算都是基于有效的统计数据,但计算出的均值和标准差似乎无关紧要。例如,当时间列表包含以下内容时:
225(03:45 上午), 90(凌晨 01:30), 0(上午 12:00), 1420(晚上 11 点 40 分), 730(下午 12:10)
我需要一个非异常值列表,其中包含:
1420(晚上 11:40), 0(上午 12:00), 90(凌晨 01:30), 225(03:45上午)
其中实际输出为:
0(上午 12:00), 90(凌晨 01:30), 225(03:45 下午), 730(下午 12:10)
也就是说,我需要的是大多数时间所在的位置。更具体地说,考虑包含整数 1380(23:00 或 11:00 pm)、1400(23:20 或 11:20 pm)和 60(01:00是)。这些时间的平均值是 945(下午 15:45 或 03:45),我需要平均值位于 23:00 和 01:00 之间。
我已经找到this solution两次的列表。但是,我的 times.size() 总是大于 2,我也想计算标准差。因此,非常感谢您在这方面的帮助。
提前致谢。
您使用的不是实数,而是以 1440 为模的数。在这种情况下,除以自然数的定义不明确或更好 n x = a
每个 [=15] 都有 n
个解决方案=].例如。 3 x = 300
有解决方案 300 / 3
、1740 / 3
和 3180 / 3
(300
、1740
和 3180
是同一元素的不同表示300
).
因此,您不能在一天中的时间范围内谈论算术平均值。然而,一天中的两个时间 之间的距离是 明确定义的:21:00 和 23:00 之间的距离以及 [=67] 之间的距离是 2 小时=] 和 1:00。因此我们可以采用 "mean":
的另一种定义- 我们称均值 一天中与数据的平方距离总和最小的时间。这是实数的通常平均值的 属性。
幸运的是,可以证明,这个新的均值是n x = sum of values
的解之一。这些解决方案之间的变化是与数据的平方距离之和,我们必须选择最小的一个。
假设我们有一个 LocalTime
的列表:
private static final long DAY = TimeUnit.DAYS.toSeconds(1L);
private static final double HALF_DAY = DAY / 2;
private static final List<LocalTime> times = Arrays.asList(
LocalTime.of(3, 45),
LocalTime.of(1, 30),
LocalTime.of(0, 0),
LocalTime.of(23, 40),
LocalTime.of(12, 10));
我们可以在 “通常” 确定中计算平均值和平方和(我在 0 到 86400 之间以秒计算):
public static void printMeanVariance(final List<LocalTime> times) {
final List<Double> dTimes = times.stream().mapToDouble(LocalTime::toSecondOfDay).boxed().collect(Collectors.toList());
dTimes.sort(Double::compareTo);
// A valid 'mean' must have max - HALF_DAY < mean < min + HALF_DAY
double max = dTimes.get(dTimes.size() - 1);
int count = 0;
double sum = 0.0, sumOfSquares = 0.0;
for (final Double time : dTimes) {
count++;
sum += time;
sumOfSquares += time * time;
}
// to be continued...
如果这是“意思”它必须满足两个条件:
- “均值”必须在
max + DAY
和min + DAY
之间,其中min
和max
是最小和当前测定中的最大值, - 通常的方差必须最小。
我们通过每次将 86400 添加到最小值来检查所有确定的这些条件:
// continuation
double average = -1;
double sumOfDistancesSquared = Double.MAX_VALUE;
for (final Double time : dTimes) {
// Check if previous value is admissible
final double tmpAverage = sum / count;
final double tmpSumOfDistancesSquared = sumOfSquares - sum * sum / count;
if (max - HALF_DAY <= tmpAverage && tmpAverage <= time + HALF_DAY && tmpSumOfDistancesSquared < sumOfDistancesSquared) {
average = tmpAverage;
sumOfDistancesSquared = tmpSumOfDistancesSquared;
}
sum += DAY;
max = time + DAY;
sumOfSquares += DAY * (2 * time + DAY);
}
// average has the "real" mean
double sd = Math.sqrt(sumOfDistancesSquared / (count - 1));
System.out.println("Mean = " + LocalTime.ofSecondOfDay((long) average) +
", deviation = " + Duration.ofSeconds((long) sd));
}
}