Skip to content

Commit bde1dba

Browse files
Automated commit of generated code
1 parent 3c98b9a commit bde1dba

File tree

3 files changed

+62
-17
lines changed
  • core/generated-sources/src

3 files changed

+62
-17
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/NumberTypeUtils.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import java.math.BigDecimal
66
import java.math.BigInteger
77
import kotlin.reflect.KClass
88
import kotlin.reflect.KType
9+
import kotlin.reflect.full.isSubtypeOf
910
import kotlin.reflect.full.withNullability
1011
import kotlin.reflect.typeOf
1112

@@ -307,10 +308,24 @@ internal fun Sequence<Number?>.convertToUnifiedNumberType(
307308
"Cannot find unified number type of types: ${types.joinToString { renderType(it) }}",
308309
)
309310
}
310-
val converter = createConverter(typeOf<Number>(), commonNumberType)!! as (Number) -> Number?
311-
return map {
312-
if (it == null) return@map null
313-
converter(it) ?: error("Can not convert $it to $commonNumberType")
311+
require(commonNumberType.isSubtypeOf(typeOf<Number?>())) {
312+
"Cannot convert numbers to $commonNumberType; it is not a subtype of Number?"
313+
}
314+
return when (commonNumberType) {
315+
nothingType -> {
316+
require(null !in this) { "Cannot unify numbers to Nothing; it contains nulls" }
317+
this
318+
}
319+
320+
nullableNothingType -> this
321+
322+
else -> {
323+
val converter = createConverter(typeOf<Number>(), commonNumberType)!! as (Number) -> Number?
324+
this.map {
325+
if (it == null) return@map null
326+
converter(it) ?: error("Can not convert $it to $commonNumberType")
327+
}
328+
}
314329
}
315330
}
316331

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Analyze.kt

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.jetbrains.kotlinx.dataframe.api.mean
3535
import org.jetbrains.kotlinx.dataframe.api.meanFor
3636
import org.jetbrains.kotlinx.dataframe.api.meanOf
3737
import org.jetbrains.kotlinx.dataframe.api.median
38+
import org.jetbrains.kotlinx.dataframe.api.medianBy
3839
import org.jetbrains.kotlinx.dataframe.api.medianFor
3940
import org.jetbrains.kotlinx.dataframe.api.medianOf
4041
import org.jetbrains.kotlinx.dataframe.api.min
@@ -43,6 +44,7 @@ import org.jetbrains.kotlinx.dataframe.api.minFor
4344
import org.jetbrains.kotlinx.dataframe.api.minOf
4445
import org.jetbrains.kotlinx.dataframe.api.minOrNull
4546
import org.jetbrains.kotlinx.dataframe.api.percentile
47+
import org.jetbrains.kotlinx.dataframe.api.percentileBy
4648
import org.jetbrains.kotlinx.dataframe.api.percentileFor
4749
import org.jetbrains.kotlinx.dataframe.api.percentileOf
4850
import org.jetbrains.kotlinx.dataframe.api.pivot
@@ -179,7 +181,7 @@ class Analyze : TestBase() {
179181
// SampleStart
180182
df.sum() // sum of values per every numeric column
181183
df.sum { age and weight } // sum of all values in `age` and `weight`
182-
df.sumFor { age and weight } // sum of values per `age` and `weight` separately
184+
df.sumFor(skipNaN = true) { age and weight } // sum of values per `age` and `weight` separately
183185
df.sumOf { (weight ?: 0) / age } // sum of expression evaluated for every row
184186
// SampleEnd
185187
}
@@ -190,7 +192,7 @@ class Analyze : TestBase() {
190192
// SampleStart
191193
df.min() // min of values per every comparable column
192194
df.min { age and weight } // min of all values in `age` and `weight`
193-
df.minFor { age and weight } // min of values per `age` and `weight` separately
195+
df.minFor(skipNaN = true) { age and weight } // min of values per `age` and `weight` separately
194196
df.minOf { (weight ?: 0) / age } // min of expression evaluated for every row
195197
df.minBy { age } // DataRow with minimal `age`
196198
// SampleEnd
@@ -214,8 +216,9 @@ class Analyze : TestBase() {
214216
// SampleStart
215217
df.median() // median of values per every comparable column
216218
df.median { age and weight } // median of all values in `age` and `weight`
217-
df.medianFor { age and weight } // median of values per `age` and `weight` separately
219+
df.medianFor(skipNaN = true) { age and weight } // median of values per `age` and `weight` separately
218220
df.medianOf { (weight ?: 0) / age } // median of expression evaluated for every row
221+
df.medianBy { age } // DataRow where the median age lies (lower-median for an even number of values)
219222
// SampleEnd
220223
}
221224

@@ -235,10 +238,11 @@ class Analyze : TestBase() {
235238
@TransformDataFrameExpressions
236239
fun percentileModes() {
237240
// SampleStart
238-
df.percentile(25.0) // percentile of values per every comparable column
239-
df.percentile(25.0) { age and weight } // percentile of all values in `age` and `weight`
240-
df.percentileFor(25.0) { age and weight } // percentile of values per `age` and `weight` separately
241-
df.percentileOf(25.0) { (weight ?: 0) / age } // percentile of expression evaluated for every row
241+
df.percentile(25.0) // 25th percentile of values per every comparable column
242+
df.percentile(75.0) { age and weight } // 75th percentile of all values in `age` and `weight`
243+
df.percentileFor(50.0, skipNaN = true) { age and weight } // 50th percentile of values per `age` and `weight` separately
244+
df.percentileOf(75.0) { (weight ?: 0) / age } // 75th percentile of expression evaluated for every row
245+
df.percentileBy(25.0) { age } // DataRow where the 25th percentile of `age` lies (index rounded using R3)
242246
// SampleEnd
243247
}
244248

@@ -247,9 +251,9 @@ class Analyze : TestBase() {
247251
fun percentileAggregations() {
248252
// SampleStart
249253
df.percentile(25.0)
250-
df.age.percentile(25.0)
251-
df.groupBy { city }.percentile(25.0)
252-
df.pivot { city }.percentile(25.0)
254+
df.age.percentile(75.0)
255+
df.groupBy { city }.percentile(50.0)
256+
df.pivot { city }.percentile(75.0)
253257
df.pivot { city }.groupBy { name.lastName }.percentile(25.0)
254258
// SampleEnd
255259
}
@@ -259,8 +263,8 @@ class Analyze : TestBase() {
259263
fun meanModes() {
260264
// SampleStart
261265
df.mean() // mean of values per every numeric column
262-
df.mean(skipNaN = true) { age and weight } // mean of all values in `age` and `weight`, skips NA
263-
df.meanFor(skipNaN = true) { age and weight } // mean of values per `age` and `weight` separately, skips NA
266+
df.mean { age and weight } // mean of all values in `age` and `weight`
267+
df.meanFor(skipNaN = true) { age and weight } // mean of values per `age` and `weight` separately, skips NaN
264268
df.meanOf { (weight ?: 0) / age } // median of expression evaluated for every row
265269
// SampleEnd
266270
}
@@ -283,7 +287,7 @@ class Analyze : TestBase() {
283287
// SampleStart
284288
df.std() // std of values per every numeric column
285289
df.std { age and weight } // std of all values in `age` and `weight`
286-
df.stdFor { age and weight } // std of values per `age` and `weight` separately, skips NA
290+
df.stdFor(skipNaN = true) { age and weight } // std of values per `age` and `weight` separately, skips NA
287291
df.stdOf { (weight ?: 0) / age } // std of expression evaluated for every row
288292
// SampleEnd
289293
}

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/statistics/sum.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import io.kotest.matchers.doubles.shouldBeNaN
55
import io.kotest.matchers.floats.shouldBeNaN
66
import io.kotest.matchers.shouldBe
77
import io.kotest.matchers.string.shouldContain
8+
import org.jetbrains.kotlinx.dataframe.DataColumn
9+
import org.jetbrains.kotlinx.dataframe.api.cast
810
import org.jetbrains.kotlinx.dataframe.api.columnOf
911
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
1012
import org.jetbrains.kotlinx.dataframe.api.isEmpty
@@ -14,7 +16,9 @@ import org.jetbrains.kotlinx.dataframe.api.sum
1416
import org.jetbrains.kotlinx.dataframe.api.sumFor
1517
import org.jetbrains.kotlinx.dataframe.api.sumOf
1618
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
19+
import org.jetbrains.kotlinx.dataframe.impl.nullableNothingType
1720
import org.junit.Test
21+
import kotlin.reflect.typeOf
1822

1923
class SumTests {
2024

@@ -46,6 +50,28 @@ class SumTests {
4650
df.sumOf { value() } shouldBe expected
4751
}
4852

53+
@Test
54+
fun `empty column with types`() {
55+
val emptyIntCol by columnOf<Int?>(null, null)
56+
emptyIntCol.sum() shouldBe 0
57+
58+
// empty column with Number type
59+
val emptyNumberColumn = DataColumn.createValueColumn<Number?>(
60+
"emptyNumberColumn",
61+
listOf(null, null),
62+
typeOf<Number?>(),
63+
)
64+
emptyNumberColumn.sum() shouldBe 0.0
65+
66+
// empty column with nullable Nothing type
67+
val emptyNothingColumn = DataColumn.createValueColumn(
68+
"emptyNothingColumn",
69+
listOf(null, null),
70+
nullableNothingType,
71+
)
72+
emptyNothingColumn.cast<Number?>().sum() shouldBe 0.0
73+
}
74+
4975
@Test
5076
fun `test multiple columns`() {
5177
val value1 by columnOf(1, 2, 3)

0 commit comments

Comments
 (0)