Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

K 결정 및 알고리즘 성능 판단(실루엣 이용) 함수 추가, 테스트 #33

Merged
merged 13 commits into from
Nov 26, 2020
Merged
12 changes: 12 additions & 0 deletions Project17-C-Map/InteractiveClusteringMap.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
46B444582568F095001B79D4 /* InteractiveMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B444572568F095001B79D4 /* InteractiveMapView.swift */; };
C9FF187A077822AA8BD00410 /* Pods_InteractiveClusteringMap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A551109FA7E11823B10D084F /* Pods_InteractiveClusteringMap.framework */; };
FA81D67825690F360023E123 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA81D67725690F360023E123 /* CoreDataStack.swift */; };
FA84D560256F796700ECDD44 /* BoundingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A12E22256CD4DB007BDF3E /* BoundingBox.swift */; };
FAC9FD05256E2107009FBB41 /* KCoefficient.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC9FD04256E2107009FBB41 /* KCoefficient.swift */; };
FAC9FD0A256E23B1009FBB41 /* KDefineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC9FD09256E23B1009FBB41 /* KDefineTests.swift */; };
FAC9FD0E256E2495009FBB41 /* KCoefficient.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC9FD04256E2107009FBB41 /* KCoefficient.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -100,6 +104,8 @@
57582C893214A43A5DC8E8C9 /* Pods-InteractiveClusteringMap.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteractiveClusteringMap.release.xcconfig"; path = "Target Support Files/Pods-InteractiveClusteringMap/Pods-InteractiveClusteringMap.release.xcconfig"; sourceTree = "<group>"; };
A551109FA7E11823B10D084F /* Pods_InteractiveClusteringMap.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_InteractiveClusteringMap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FA81D67725690F360023E123 /* CoreDataStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = "<group>"; };
FAC9FD04256E2107009FBB41 /* KCoefficient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KCoefficient.swift; sourceTree = "<group>"; };
FAC9FD09256E23B1009FBB41 /* KDefineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KDefineTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -185,6 +191,7 @@
FA81D66E2568FEC50023E123 /* CoreData */,
37EB73282562592700AC44D6 /* AppDelegate.swift */,
37EB732A2562592700AC44D6 /* SceneDelegate.swift */,
FAC9FD04256E2107009FBB41 /* KCoefficient.swift */,
37EB732C2562592700AC44D6 /* MapViewController.swift */,
4623BD1225694A1400940B12 /* MapController.swift */,
46153145256BDDD700BAE674 /* QuadTree */,
Expand All @@ -204,6 +211,7 @@
46A12E3E256CEDD3007BDF3E /* QuadTreeTests */,
37EB73422562592900AC44D6 /* InteractiveClusteringMapTests.swift */,
3713D3DB25694C3E00E703EC /* CoreDataStackTests.swift */,
FAC9FD09256E23B1009FBB41 /* KDefineTests.swift */,
37EB73442562592900AC44D6 /* Info.plist */,
);
path = InteractiveClusteringMapTests;
Expand Down Expand Up @@ -482,6 +490,7 @@
46A12E1B256CD099007BDF3E /* Extension.swift in Sources */,
37352CDB25695E7400CAFDFD /* JSONReader.swift in Sources */,
46A12E23256CD4DB007BDF3E /* BoundingBox.swift in Sources */,
FAC9FD05256E2107009FBB41 /* KCoefficient.swift in Sources */,
37EB73292562592700AC44D6 /* AppDelegate.swift in Sources */,
372216C12569325600231245 /* DataManagable.swift in Sources */,
37352CE025695EE000CAFDFD /* Place.swift in Sources */,
Expand All @@ -493,6 +502,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FAC9FD0E256E2495009FBB41 /* KCoefficient.swift in Sources */,
192D34BE256E36B900861703 /* Extension.swift in Sources */,
3713D3E425694CD300E703EC /* POI.swift in Sources */,
46A12E2B256CED1B007BDF3E /* POIEntity+CoreDataProperties.swift in Sources */,
Expand All @@ -503,10 +513,12 @@
46A12E27256CED18007BDF3E /* POIEntity+CoreDataClass.swift in Sources */,
37EB73432562592900AC44D6 /* InteractiveClusteringMapTests.swift in Sources */,
46A12E3A256CED57007BDF3E /* JSONReader.swift in Sources */,

192D34BA256E36A200861703 /* BoundingBox.swift in Sources */,
192D34B2256E368D00861703 /* QuadTreeTests.swift in Sources */,
199DDFF6256B9C8E0065B94E /* Place.swift in Sources */,
3713D3FA25694D9C00E703EC /* DataManagable.swift in Sources */,
FAC9FD0A256E23B1009FBB41 /* KDefineTests.swift in Sources */,
3713D3DC25694C3E00E703EC /* CoreDataStackTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
61 changes: 61 additions & 0 deletions Project17-C-Map/InteractiveClusteringMap/KCoefficient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// KCoefficient.swift
// InteractiveClusteringMap
//
// Created by A on 2020/11/25.
//

import Foundation

// rule of thumb
func KwithRuleOfThumb(numberOfData: Int) -> Int {
return Int(sqrt(Double(numberOfData/2)))
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 return 생략 가능한거 어떻게 맞추면 좋을지 논의해보면 좋을 거 같애용 ㅎ_ㅎ

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 이 생략가능하다는게 어떤 의미인지 좀 더 설명해 주실 수 있나요!!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func KwithRuleOfThumb(numberOfData: Int) -> Int {
    Int(sqrt(Double(numberOfData/2)))
}

이렇게용 ! 함수내부에 반환만하면 return 생략 가능하지 않나요 ~~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 오오 이런 방법이 있는 줄은 몰랐네요! 생략을 하는게 더 나을까요 ? ? 논의 해봅시당 ㅎㅎ


// AverageSilhouetteMethod
class AverageSilhouetteCalculator {

private let clusters: [Cluster]

init(clusters: [Cluster]) {
self.clusters = clusters
}

func findAverageSilhouette(cluster: Cluster) -> Double {
var silhouettes = [Double]()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

띄어쓰기가 두번이..

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

린트에서 오류가 뜨진 않았나요?

cluster.coordinates.forEach { coordinate in
silhouettes.append(findSilhouette(with: cluster, target: coordinate))
}
return silhouettes.reduce(.zero, +) / Double(silhouettes.count)
}

func findSilhouette(with cluster: Cluster, target: Coordinate) -> Double {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기두 계산아닌가용..?

guard !cluster.coordinates.isEmpty else {
return 0.0
}
let cohesion = findCohesion(in: cluster, target: target)
let separation = findSeparation(in: cluster, target: target)
return (separation - cohesion) / max(cohesion, separation)
}

// 점과 현재 포함된 클러스터의 응집도 계산
func findCohesion(in cluster: Cluster, target: Coordinate) -> Double {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응집도 계산이라서 find 보다 calculate 이런게 나아보여요!
제가 동작을 잘 몰라서 그런거일수도 있습니당

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클래스 명이 계산기니까 calculate가 더 나아 보이네요!!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그냥 cohesion 도 괜찮을거 같구용 !

var totalDistance = 0.0
let coordinates = cluster.coordinates.filter { $0 != target }
coordinates.forEach {
totalDistance += target.distanceTo($0)
}
return totalDistance / Double(coordinates.count)
}

// 점과 포함되지 않은 클러스터 간의 분리도 계산
func findSeparation(in cluster: Cluster, target: Coordinate) -> Double {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기두 calculate가 나을거같은데 아니면 말씀해주세용!

var totalDistances: [Double] = [Double]()
let otherClusters = clusters.filter { $0.coordinates != cluster.coordinates }
otherClusters.forEach {
totalDistances.append(findCohesion(in: $0, target: target))
}
return totalDistances.min() ?? 0
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,36 @@ extension BoundingBox: Equatable {}

struct Coordinate: Equatable {

static let zero = Coordinate(x: 0, y: 0)

let x: Double
let y: Double

func distanceTo(_ other: Coordinate) -> Double {
let powX = pow(self.x - other.x, 2.0)
let powY = pow(self.y - other.y, 2.0)

return sqrt(powX + powY)
}

static func + (left: Coordinate, right: Coordinate) -> Coordinate {
let x = left.x + right.x
let y = left.y + right.y
return Coordinate(x: x, y: y)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 개행 통일하면 보기 더 예쁠(?) 것 같아용 ㅎㅎ
지금도 좋습니다 ~~!


static func - (left: Coordinate, right: Coordinate) -> Coordinate {
let x = left.x - right.x
let y = left.y - right.y
return Coordinate(x: x, y: y)
}

static func / (left: Coordinate, right: Double) -> Coordinate {
let x = left.x / right
let y = left.y / right
return Coordinate(x: x, y: y)
}

static func <= (left: Coordinate, right: Coordinate) -> Bool {
left.x <= right.x && left.y <= right.y
}
Expand All @@ -56,6 +83,11 @@ struct Coordinate: Equatable {
}

struct Cluster {
let center: Coordinate
let coordinates: [Coordinate]
var coordinates: [Coordinate]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘(coordinates) 는 let 으로 놔둬도 되지 않아요? 나중에 수정할 예정인건가요.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 팀원들이랑 논의하다가 뒤에 var로 바꿀일이 있어서 저도 바꿔놓았는데 사실상 이번 PR에서의 의미는 없네요 😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아, 논의하신거라면 패쓰~

var center: Coordinate {
coordinates.reduce(.zero, +) / Double(coordinates.count)
}
init(coordinates: [Coordinate]) {
self.coordinates = coordinates
}
}
85 changes: 85 additions & 0 deletions Project17-C-Map/InteractiveClusteringMapTests/KDefineTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// KDefineTests.swift
// InteractiveClusteringMapTests
//
// Created by A on 2020/11/25.
//

import XCTest

class KDefineTests: XCTestCase {

let accuracy = 0.001
private var avc: AverageSilhouetteCalculator?

/// cluster1: A(1,1), B(2,2)
/// cluster2: C(-2,1), D(-3,-2), D(0, -2)
private let cluster1 = Cluster(coordinates: [Coordinate(x: 1, y: 1), Coordinate(x: 2, y: 2)])
private var cluster2 = Cluster(coordinates: [Coordinate(x: -2, y: 1), Coordinate(x: -3, y: -2), Coordinate(x: 0, y: -2)])

override func setUpWithError() throws {
let clusters = [cluster1, cluster2]
avc = AverageSilhouetteCalculator(clusters: clusters)
}

func test_avc_init() throws {
XCTAssertNotNil(avc)
}

func test_rule_of_thumb_with_5000() throws {
let expected = 50
let numberOfData = 5000
XCTAssertEqual(KwithRuleOfThumb(numberOfData: numberOfData), expected)
}

func test_rule_of_thumb_with_8000() throws {
let expected = 63
let numberOfData = 8000
XCTAssertEqual(KwithRuleOfThumb(numberOfData: numberOfData), expected)
}

func test_find_find_cohesion() throws {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_find_cohesion() ...?
밑에는 이렇게 되어있는 것 같아서요 ~~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엥 이상한 이름들이 많네요 큐ㅠㅠ 바로 수정하겠습니다!

guard let result = avc?.findCohesion(in: cluster1, target: cluster1.coordinates[0]) else {
return
}
let expected = sqrt(2)
XCTAssertEqual(expected, result, accuracy: accuracy)
}

func test_find_separation() throws {
guard let result = avc?.findSeparation(in: cluster1, target: cluster1.coordinates[0]) else {
return
}

let expected = 3.720759
XCTAssertEqual(expected, result, accuracy: accuracy)
}

func test_find_silhouette_A() throws {
guard let result = avc?.findSilhouette(with: cluster1, target: cluster1.coordinates[0]) else {
return
}

let expected = 0.619912
XCTAssertEqual(expected, result, accuracy: accuracy)
}

func test_find_silhouette_B() throws {
guard let result = avc?.findSilhouette(with: cluster1, target: cluster1.coordinates[1]) else {
return
}

let expected = 0.717126
XCTAssertEqual(expected, result, accuracy: accuracy)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 두 테스트 함수의 차이는 무엇인가요??? 같은 행동을 한다면 하나의 함수에서 하는건 어떤가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 함수당 xctAssert 함수가 하나씩 들어가는 게 이상적이라고 생각해서 나눴습니다!!


func test_find_average_silhouette_cluster1() throws {
guard let result = avc?.findAverageSilhouette(cluster: cluster1) else {
return
}

let expected = 0.668519
XCTAssertEqual(expected, result, accuracy: accuracy)
}

}