Centroid of a set of N-dimensional points: Difference between revisions
Content added Content deleted
(→{{header|Wren}}: Added some validity checks.) |
(Added Go) |
||
Line 27:
;; [[https://mathworld.wolfram.com/GeometricCentroid.html Wolfram Mathworld on Centroid]]
=={{header|Go}}==
{{trans|Wren}}
The image will, of course, be the same as Wren when the relevant points are fed into Gnuplot.
<syntaxhighlight lang="go">package main
import (
"fmt"
"log"
)
func centroid(pts [][]float64) []float64 {
n := len(pts)
if n == 0 {
log.Fatal("Slice must contain at least one point.")
}
d := len(pts[0])
for i := 1; i < n; i++ {
if len(pts[i]) != d {
log.Fatal("Points must all have the same dimension.")
}
}
res := make([]float64, d)
for j := 0; j < d; j++ {
for i := 0; i < n; i++ {
res[j] += pts[i][j]
}
res[j] /= float64(n)
}
return res
}
func main() {
points := [][][]float64{
{{1}, {2}, {3}},
{{8, 2}, {0, 0}},
{{5, 5, 0}, {10, 10, 0}},
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}},
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}},
}
for _, pts := range points {
fmt.Println(pts, "=> Centroid:", centroid(pts))
}
}</syntaxhighlight>
{{out}}
<pre>
[[1] [2] [3]] => Centroid: [2]
[[8 2] [0 0]] => Centroid: [4 1]
[[5 5 0] [10 10 0]] => Centroid: [7.5 7.5 0]
[[1 3.1 6.5] [-2 -5 3.4] [-7 -4 9] [2 0 3]] => Centroid: [-1.5 -1.475 5.475]
[[0 0 0 0 1] [0 0 0 1 0] [0 0 1 0 0] [0 1 0 0 0]] => Centroid: [0 0.25 0.25 0.25 0.25]
</pre>
=={{header|Julia}}==
|
Revision as of 11:21, 17 July 2023
Centroid of a set of N-dimensional points is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
In analytic geometry, the centroid of a set of points is a point in the same domain as the set. The centroid point is chosen to show a property which can be calculated for that set.
Consider the centroid defined as the arithmetic mean of a set of points of arbitrary dimension.
- Task
Create a function in your chosen programming language to calculate such a centroid using an arbitrary number of points of arbitrary dimension.
- Test your function with the following groups of points
one-dimensional: (1), (2), (3)
two-dimensional: (8, 2), (0, 0)
three-dimensional: the set (5, 5, 0), (10, 10, 0) and the set (1, 3.1, 6.5), (-2, -5, 3.4), (-7, -4, 9), (2, 0, 3)
five-dimensional: (0, 0, 0, 0, 1), (0, 0, 0, 1, 0), (0, 0, 1, 0, 0), (0, 1, 0, 0, 0)
- Stretch task
Show a 3D plot image of the second 3-dimensional set and its centroid.
- See Also
Go
The image will, of course, be the same as Wren when the relevant points are fed into Gnuplot.
package main
import (
"fmt"
"log"
)
func centroid(pts [][]float64) []float64 {
n := len(pts)
if n == 0 {
log.Fatal("Slice must contain at least one point.")
}
d := len(pts[0])
for i := 1; i < n; i++ {
if len(pts[i]) != d {
log.Fatal("Points must all have the same dimension.")
}
}
res := make([]float64, d)
for j := 0; j < d; j++ {
for i := 0; i < n; i++ {
res[j] += pts[i][j]
}
res[j] /= float64(n)
}
return res
}
func main() {
points := [][][]float64{
{{1}, {2}, {3}},
{{8, 2}, {0, 0}},
{{5, 5, 0}, {10, 10, 0}},
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}},
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}},
}
for _, pts := range points {
fmt.Println(pts, "=> Centroid:", centroid(pts))
}
}
- Output:
[[1] [2] [3]] => Centroid: [2] [[8 2] [0 0]] => Centroid: [4 1] [[5 5 0] [10 10 0]] => Centroid: [7.5 7.5 0] [[1 3.1 6.5] [-2 -5 3.4] [-7 -4 9] [2 0 3]] => Centroid: [-1.5 -1.475 5.475] [[0 0 0 0 1] [0 0 0 1 0] [0 0 1 0 0] [0 1 0 0 0]] => Centroid: [0 0.25 0.25 0.25 0.25]
Julia
using Plots
struct Point{T, N}
v::Vector{T}
end
function centroid(points::Vector{Point{T, N}}) where N where T
arr = zeros(T, N)
for p in points, (i, x) in enumerate(p.v)
arr[i] += x
end
return Point{T, N}(arr / length(points))
end
function centroid(arr)
isempty(arr) && return Point{Float64, 0}(arr)
n = length(arr[begin])
t = typeof(arr[begin][begin])
return centroid([Point{t, n}(v) for v in arr])
end
const testvecs = [[[1], [2], [3]],
[(8, 2), (0, 0)],
[[5, 5, 0], [10, 10, 0]],
[[1.0, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9.0], [2.0, 0.0, 3.0],],
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0],],
]
function test_centroids(tests)
for t in tests
isempty(t) && error("The empty set of points $t has no centroid")
vvec = [Point{Float64, length(t[begin])}(collect(v)) for v in t]
println("$t => $(centroid(vvec))")
end
xyz = [p[1] for p in tests[4]], [p[2] for p in tests[4]], [p[3] for p in tests[4]]
cpoint = centroid(tests[4]).v
for i in eachindex(cpoint)
push!(xyz[i], cpoint[i])
end
scatter(xyz..., color = [:navy, :navy, :navy, :navy, :red], legend = :none)
end
test_centroids(testvecs)
- Output:
[[1], [2], [3]] => Point{Float64, 1}([2.0]) [(8, 2), (0, 0)] => Point{Float64, 2}([4.0, 1.0]) [[5, 5, 0], [10, 10, 0]] => Point{Float64, 3}([7.5, 7.5, 0.0]) [[1.0, 3.1, 6.5], [-2.0, -5.0, 3.4], [-7.0, -4.0, 9.0], [2.0, 0.0, 3.0]] => Point{Float64, 3}([-1.5, -1.475, 5.475]) [[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Point{Float64, 5}([0.0, 0.25, 0.25, 0.25, 0.25])
Wren
var centroid = Fn.new { |pts|
var n = pts.count
if (n == 0) Fiber.abort("List must contain at least one point.")
var d = pts[0].count
if (pts.skip(1).any { |p| p.count != d }) {
Fiber.abort("Points must all have the same dimension.")
}
var res = List.filled(d, 0)
for (j in 0...d) {
for (i in 0...n) {
res[j] = res[j] + pts[i][j]
}
res[j] = res[j] / n
}
return res
}
var points = [
[ [1], [2], [3] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
]
for (pts in points) {
System.print("%(pts) => Centroid: %(centroid.call(pts))")
}
- Output:
[[1], [2], [3]] => Centroid: [2] [[8, 2], [0, 0]] => Centroid: [4, 1] [[5, 5, 0], [10, 10, 0]] => Centroid: [7.5, 7.5, 0] [[1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3]] => Centroid: [-1.5, -1.475, 5.475] [[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]