Skip to content

Commit fa896f0

Browse files
committed
added tests and fixes for std and mean functions regarding Nothing(?) types
1 parent 73ba813 commit fa896f0

File tree

5 files changed

+36
-7
lines changed

5 files changed

+36
-7
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/math/mean.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.jetbrains.kotlinx.dataframe.math
22

33
import org.jetbrains.kotlinx.dataframe.api.skipNA_default
4+
import org.jetbrains.kotlinx.dataframe.impl.renderType
45
import java.math.BigDecimal
56
import kotlin.reflect.KType
67
import kotlin.reflect.full.withNullability
@@ -31,7 +32,10 @@ internal fun <T : Number> Sequence<T>.mean(type: KType, skipNA: Boolean = skipNA
3132

3233
Number::class -> (this as Sequence<Number>).map { it.toDouble() }.mean(skipNA)
3334

34-
else -> throw IllegalArgumentException("Unable to compute mean for type $type")
35+
// this means the sequence is empty
36+
Nothing::class -> Double.NaN
37+
38+
else -> throw IllegalArgumentException("Unable to compute the mean for type ${renderType(type)}")
3539
}
3640
}
3741

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/math/std.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.jetbrains.kotlinx.dataframe.math
22

33
import org.jetbrains.kotlinx.dataframe.api.ddof_default
44
import org.jetbrains.kotlinx.dataframe.api.skipNA_default
5+
import org.jetbrains.kotlinx.dataframe.impl.renderType
56
import java.math.BigDecimal
67
import kotlin.reflect.KType
78
import kotlin.reflect.full.withNullability
@@ -13,11 +14,10 @@ internal fun <T : Number> Iterable<T?>.std(
1314
ddof: Int = ddof_default,
1415
): Double {
1516
if (type.isMarkedNullable) {
16-
if (skipNA) {
17-
return filterNotNull().std(type.withNullability(false), true, ddof)
18-
} else {
19-
if (contains(null)) return Double.NaN
20-
return std(type.withNullability(false), skipNA, ddof)
17+
return when {
18+
skipNA -> filterNotNull().std(type = type.withNullability(false), skipNA = true, ddof = ddof)
19+
contains(null) -> Double.NaN
20+
else -> std(type = type.withNullability(false), skipNA = false, ddof = ddof)
2121
}
2222
}
2323
return when (type.classifier) {
@@ -26,7 +26,8 @@ internal fun <T : Number> Iterable<T?>.std(
2626
Int::class, Short::class, Byte::class -> (this as Iterable<Int>).std(ddof)
2727
Long::class -> (this as Iterable<Long>).std(ddof)
2828
BigDecimal::class -> (this as Iterable<BigDecimal>).std(ddof)
29-
else -> throw IllegalArgumentException("Unsupported type ${type.classifier}")
29+
Nothing::class -> Double.NaN
30+
else -> throw IllegalArgumentException("Unable to compute the std for type ${renderType(type)}")
3031
}
3132
}
3233

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/statistics/BasicMathTests.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.jetbrains.kotlinx.dataframe.statistics
22

33
import io.kotest.matchers.shouldBe
4+
import org.jetbrains.kotlinx.dataframe.DataColumn
45
import org.jetbrains.kotlinx.dataframe.api.columnOf
56
import org.jetbrains.kotlinx.dataframe.api.mean
7+
import org.jetbrains.kotlinx.dataframe.impl.nothingType
68
import org.junit.Test
79
import kotlin.reflect.typeOf
810

@@ -18,5 +20,8 @@ class BasicMathTests {
1820
fun `mean with nans and nulls`() {
1921
columnOf(10, 20, Double.NaN, null).mean() shouldBe Double.NaN
2022
columnOf(10, 20, Double.NaN, null).mean(skipNA = true) shouldBe 15
23+
24+
DataColumn.createValueColumn("", emptyList<Nothing>(), nothingType(false)).mean() shouldBe Double.NaN
25+
DataColumn.createValueColumn("", listOf(null), nothingType(true)).mean() shouldBe Double.NaN
2126
}
2227
}

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/statistics/std.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package org.jetbrains.kotlinx.dataframe.statistics
22

33
import io.kotest.matchers.shouldBe
4+
import org.jetbrains.kotlinx.dataframe.DataColumn
45
import org.jetbrains.kotlinx.dataframe.api.columnOf
56
import org.jetbrains.kotlinx.dataframe.api.columnTypes
67
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
78
import org.jetbrains.kotlinx.dataframe.api.std
9+
import org.jetbrains.kotlinx.dataframe.impl.nothingType
810
import org.jetbrains.kotlinx.dataframe.math.std
11+
import org.jetbrains.kotlinx.dataframe.type
912
import org.junit.Test
1013
import kotlin.reflect.typeOf
1114

@@ -37,4 +40,16 @@ class StdTests {
3740
df[value].std() shouldBe expected
3841
df.std { value } shouldBe expected
3942
}
43+
44+
@Test
45+
fun `std on empty or nullable column`() {
46+
val empty = DataColumn.createValueColumn("", emptyList<Nothing>(), nothingType(false))
47+
val nullable = DataColumn.createValueColumn("", listOf(null), nothingType(true))
48+
49+
empty.values().std(empty.type) shouldBe Double.NaN
50+
nullable.values().std(nullable.type) shouldBe Double.NaN
51+
52+
empty.std() shouldBe Double.NaN
53+
nullable.std() shouldBe Double.NaN
54+
}
4055
}

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/testSets/person/DataFrameTests.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.kotest.matchers.shouldBe
77
import io.kotest.matchers.shouldNotBe
88
import org.jetbrains.kotlinx.dataframe.AnyFrame
99
import org.jetbrains.kotlinx.dataframe.AnyRow
10+
import org.jetbrains.kotlinx.dataframe.DataColumn
1011
import org.jetbrains.kotlinx.dataframe.DataFrame
1112
import org.jetbrains.kotlinx.dataframe.DataRow
1213
import org.jetbrains.kotlinx.dataframe.RowExpression
@@ -2196,6 +2197,9 @@ class DataFrameTests : BaseTest() {
21962197
fun `isNumber`() {
21972198
typed.age.isNumber() shouldBe true
21982199
typed.weight.isNumber() shouldBe true
2200+
2201+
DataColumn.createValueColumn("a", emptyList<Nothing>(), nothingType(false)).isNumber() shouldBe true
2202+
DataColumn.createValueColumn("a", listOf(null), nothingType(true)).isNumber() shouldBe true
21992203
}
22002204

22012205
@Test

0 commit comments

Comments
 (0)