├── C_files └── edsc │ ├── ByInstanceDP.cpp │ ├── Data │ ├── result.txt │ ├── test │ └── train │ ├── DataSetInformation.h │ ├── Euclidean.cpp │ ├── Euclidean.h │ ├── quickSort.cpp │ └── quickSort.h ├── Java ├── ecec_test.main.jar ├── sfa.main.jar └── sfa.main_non_norm.jar ├── README.md ├── ets ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ └── cli.cpython-37.pyc ├── algorithms │ ├── MLSTM │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-37.pyc │ │ │ └── mlstm_impl.cpython-37.pyc │ │ ├── mlstm_impl.py │ │ ├── requirements.txt │ │ └── utils │ │ │ ├── __pycache__ │ │ │ ├── generic_utils.cpython-37.pyc │ │ │ ├── keras_utils.cpython-37.pyc │ │ │ └── layer_utils.cpython-37.pyc │ │ │ ├── constants.txt │ │ │ ├── embedding_utils.py │ │ │ ├── generic_utils.py │ │ │ ├── keras_utils.py │ │ │ ├── layer_utils.py │ │ │ └── note.txt │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-37.pyc │ │ ├── cfsr.cpython-37.pyc │ │ ├── early_classifier.cpython-37.pyc │ │ ├── ecdire.cpython-37.pyc │ │ ├── ecec.cpython-37.pyc │ │ ├── ects.cpython-37.pyc │ │ ├── ects_c.cpython-37.pyc │ │ ├── edsc.cpython-37.pyc │ │ ├── edsc_c.cpython-37.pyc │ │ ├── mlstm.cpython-37.pyc │ │ ├── nn.cpython-37.pyc │ │ ├── teaser.cpython-37.pyc │ │ ├── temp.cpython-37.pyc │ │ └── utils.cpython-37.pyc │ ├── early_classifier.py │ ├── ecec.py │ ├── ects.py │ ├── edsc_c.py │ ├── mlstm.py │ ├── non_myopic.py │ ├── teaser.py │ └── utils.py └── cli.py ├── requirements.txt ├── scripts ├── download_data.sh └── organise.py └── setup.py /C_files/edsc/Data/test: -------------------------------------------------------------------------------- 1 | 1 1137.0 1222.0 1208.0 1107.0 911.0 777.0 708.0 675.0 681.0 683.0 692.0 706.0 727.0 756.0 787.0 814.0 870.0 898.0 839.0 756.0 711.0 708.0 736.0 744.0 745.0 747.0 752.0 765.0 782.0 801.0 818.0 836.0 853.0 814.0 720.0 675.0 669.0 691.0 720.0 753.0 782.0 795.0 824.0 851.0 881.0 893.0 898.0 902.0 848.0 2 | 1 1137.0 1226.0 1236.0 1247.0 1199.0 1132.0 1105.0 1116.0 1111.0 1037.0 884.0 785.0 746.0 753.0 749.0 721.0 663.0 666.0 683.0 700.0 678.0 643.0 642.0 641.0 644.0 637.0 596.0 548.0 531.0 537.0 540.0 526.0 489.0 472.0 470.0 491.0 507.0 506.0 493.0 499.0 506.0 520.0 523.0 506.0 506.0 506.0 507.0 506.0 493.0 3 | 1 1137.0 1218.0 1195.0 1067.0 887.0 736.0 683.0 655.0 662.0 669.0 679.0 699.0 712.0 738.0 781.0 802.0 858.0 891.0 847.0 759.0 736.0 745.0 773.0 788.0 793.0 795.0 799.0 820.0 837.0 851.0 870.0 891.0 907.0 847.0 785.0 783.0 799.0 832.0 875.0 913.0 949.0 969.0 999.0 1034.0 1060.0 1068.0 1076.0 1076.0 1037.0 4 | 1 1137.0 1224.0 1221.0 1156.0 1005.0 827.0 713.0 676.0 670.0 681.0 698.0 703.0 686.0 655.0 629.0 644.0 666.0 698.0 734.0 758.0 769.0 743.0 714.0 684.0 666.0 666.0 680.0 696.0 706.0 711.0 659.0 608.0 593.0 595.0 611.0 641.0 680.0 703.0 725.0 713.0 678.0 654.0 663.0 680.0 689.0 700.0 703.0 704.0 661.0 5 | 1 1137.0 1227.0 1227.0 1227.0 1162.0 1014.0 908.0 853.0 852.0 855.0 822.0 713.0 653.0 618.0 620.0 635.0 674.0 674.0 648.0 624.0 626.0 635.0 663.0 667.0 642.0 597.0 568.0 566.0 571.0 583.0 586.0 570.0 537.0 529.0 541.0 559.0 588.0 615.0 611.0 596.0 599.0 603.0 617.0 639.0 659.0 636.0 585.0 552.0 553.0 6 | 1 1137.0 1224.0 1209.0 1098.0 908.0 767.0 714.0 686.0 670.0 679.0 692.0 712.0 734.0 760.0 790.0 763.0 730.0 715.0 730.0 750.0 765.0 780.0 823.0 839.0 842.0 845.0 854.0 830.0 763.0 708.0 692.0 701.0 710.0 738.0 765.0 796.0 818.0 855.0 917.0 968.0 959.0 894.0 866.0 866.0 888.0 893.0 898.0 907.0 921.0 7 | 1 1137.0 1219.0 1228.0 1163.0 1000.0 825.0 750.0 731.0 738.0 740.0 755.0 718.0 649.0 616.0 619.0 636.0 669.0 710.0 740.0 718.0 670.0 644.0 654.0 664.0 666.0 670.0 675.0 634.0 593.0 569.0 572.0 579.0 587.0 604.0 620.0 624.0 586.0 576.0 603.0 615.0 640.0 652.0 672.0 671.0 627.0 589.0 575.0 578.0 583.0 8 | 1 1137.0 1224.0 1235.0 1211.0 1077.0 935.0 833.0 809.0 798.0 808.0 821.0 841.0 859.0 819.0 696.0 630.0 611.0 643.0 671.0 687.0 704.0 721.0 744.0 700.0 601.0 566.0 553.0 557.0 566.0 576.0 586.0 592.0 590.0 533.0 475.0 455.0 465.0 483.0 510.0 542.0 564.0 578.0 586.0 552.0 504.0 479.0 481.0 482.0 484.0 9 | 1 1137.0 1223.0 1234.0 1229.0 1127.0 972.0 863.0 813.0 808.0 809.0 827.0 845.0 862.0 852.0 741.0 635.0 606.0 615.0 634.0 653.0 670.0 691.0 723.0 698.0 641.0 568.0 550.0 548.0 558.0 563.0 572.0 585.0 601.0 571.0 499.0 472.0 468.0 482.0 511.0 538.0 554.0 573.0 596.0 593.0 559.0 520.0 510.0 517.0 521.0 10 | 1 1137.0 1215.0 1200.0 1092.0 913.0 766.0 671.0 655.0 654.0 655.0 671.0 693.0 714.0 742.0 773.0 814.0 853.0 905.0 947.0 969.0 1001.0 992.0 911.0 818.0 751.0 735.0 741.0 750.0 764.0 782.0 796.0 811.0 834.0 859.0 893.0 928.0 965.0 1007.0 1068.0 1148.0 1176.0 1116.0 993.0 927.0 912.0 909.0 915.0 921.0 934.0 11 | 1 1137.0 1223.0 1232.0 1181.0 1040.0 860.0 750.0 726.0 723.0 735.0 751.0 759.0 701.0 618.0 574.0 569.0 582.0 616.0 656.0 676.0 683.0 640.0 611.0 572.0 568.0 568.0 577.0 586.0 600.0 599.0 563.0 495.0 478.0 481.0 495.0 517.0 533.0 560.0 576.0 574.0 547.0 524.0 529.0 547.0 557.0 567.0 571.0 569.0 531.0 12 | 1 1137.0 1227.0 1217.0 1127.0 975.0 873.0 825.0 781.0 723.0 659.0 638.0 643.0 645.0 636.0 655.0 673.0 706.0 731.0 759.0 775.0 784.0 790.0 812.0 814.0 812.0 798.0 774.0 764.0 769.0 786.0 779.0 777.0 795.0 819.0 840.0 859.0 888.0 936.0 979.0 1024.0 1038.0 1051.0 1077.0 1120.0 1109.0 1088.0 1086.0 1097.0 1091.0 13 | 1 1137.0 1218.0 1194.0 1089.0 896.0 748.0 679.0 653.0 648.0 651.0 669.0 687.0 709.0 735.0 775.0 814.0 851.0 906.0 955.0 989.0 993.0 942.0 842.0 800.0 775.0 765.0 770.0 781.0 801.0 815.0 831.0 847.0 868.0 896.0 935.0 979.0 1031.0 1083.0 1139.0 1136.0 1039.0 942.0 921.0 936.0 959.0 964.0 967.0 979.0 994.0 14 | 1 1137.0 1227.0 1232.0 1217.0 1164.0 1092.0 1058.0 1030.0 927.0 790.0 718.0 699.0 682.0 649.0 634.0 635.0 649.0 679.0 681.0 688.0 697.0 704.0 689.0 684.0 684.0 680.0 643.0 620.0 614.0 625.0 619.0 605.0 599.0 608.0 621.0 633.0 643.0 652.0 680.0 709.0 711.0 719.0 728.0 744.0 729.0 705.0 696.0 691.0 682.0 15 | 1 1137.0 1222.0 1230.0 1236.0 1241.0 1250.0 1270.0 1296.0 1292.0 1256.0 1224.0 1208.0 1227.0 1255.0 1218.0 1127.0 1072.0 1123.0 1170.0 1205.0 1162.0 1099.0 1105.0 1116.0 1120.0 1095.0 1046.0 1030.0 1032.0 1043.0 1058.0 1035.0 979.0 955.0 963.0 984.0 996.0 931.0 886.0 893.0 917.0 937.0 937.0 918.0 903.0 894.0 896.0 900.0 877.0 16 | 1 1137.0 1220.0 1216.0 1124.0 967.0 803.0 706.0 688.0 689.0 682.0 645.0 611.0 587.0 590.0 614.0 646.0 668.0 681.0 684.0 681.0 685.0 704.0 728.0 734.0 702.0 669.0 651.0 663.0 684.0 696.0 688.0 676.0 658.0 665.0 689.0 717.0 748.0 759.0 769.0 775.0 783.0 794.0 812.0 833.0 835.0 786.0 747.0 743.0 749.0 17 | 1 1137.0 1224.0 1226.0 1189.0 1068.0 989.0 959.0 953.0 932.0 824.0 710.0 660.0 650.0 664.0 650.0 629.0 621.0 641.0 662.0 674.0 673.0 659.0 669.0 679.0 681.0 676.0 642.0 620.0 611.0 620.0 631.0 627.0 598.0 578.0 591.0 611.0 628.0 631.0 629.0 640.0 655.0 660.0 659.0 646.0 628.0 620.0 621.0 627.0 622.0 18 | 1 1137.0 1220.0 1220.0 1176.0 1055.0 963.0 915.0 874.0 770.0 687.0 652.0 638.0 627.0 609.0 625.0 650.0 674.0 691.0 712.0 731.0 741.0 750.0 759.0 766.0 767.0 757.0 731.0 732.0 738.0 741.0 738.0 735.0 752.0 758.0 767.0 787.0 813.0 852.0 894.0 920.0 941.0 968.0 988.0 995.0 991.0 1000.0 996.0 962.0 949.0 19 | 1 1137.0 1218.0 1234.0 1233.0 1188.0 1118.0 1098.0 1099.0 1108.0 1127.0 1154.0 1173.0 1199.0 1245.0 1294.0 1274.0 1146.0 1049.0 1028.0 1026.0 1045.0 1068.0 1112.0 1123.0 1135.0 1145.0 1156.0 1103.0 960.0 889.0 877.0 890.0 915.0 937.0 969.0 1003.0 1038.0 1084.0 1123.0 1071.0 964.0 912.0 907.0 929.0 946.0 960.0 961.0 971.0 990.0 20 | 1 1137.0 1226.0 1235.0 1225.0 1160.0 1043.0 974.0 958.0 956.0 966.0 929.0 825.0 713.0 660.0 668.0 683.0 722.0 732.0 711.0 670.0 660.0 665.0 697.0 705.0 678.0 626.0 597.0 598.0 611.0 627.0 630.0 614.0 547.0 525.0 524.0 540.0 556.0 575.0 573.0 548.0 559.0 559.0 568.0 597.0 595.0 575.0 531.0 514.0 512.0 21 | 0 1137.0 1224.0 1204.0 1096.0 920.0 767.0 695.0 666.0 657.0 660.0 672.0 689.0 713.0 736.0 770.0 809.0 854.0 907.0 946.0 968.0 996.0 1024.0 1064.0 1090.0 1094.0 1108.0 1119.0 1142.0 1168.0 1200.0 1222.0 1249.0 1290.0 1313.0 1347.0 1393.0 1451.0 1534.0 1626.0 1731.0 1782.0 1842.0 1898.0 1977.0 2028.0 2055.0 2067.0 2085.0 2100.0 22 | 0 1137.0 1222.0 1197.0 1069.0 885.0 732.0 667.0 663.0 664.0 666.0 667.0 685.0 698.0 726.0 763.0 793.0 841.0 897.0 941.0 966.0 953.0 923.0 899.0 890.0 885.0 890.0 893.0 904.0 928.0 941.0 960.0 974.0 997.0 1025.0 1070.0 1120.0 1181.0 1246.0 1288.0 1274.0 1254.0 1246.0 1273.0 1311.0 1351.0 1354.0 1363.0 1373.0 1382.0 23 | 0 1137.0 1226.0 1234.0 1217.0 1090.0 916.0 759.0 680.0 650.0 643.0 644.0 664.0 681.0 711.0 733.0 766.0 807.0 860.0 903.0 919.0 936.0 963.0 1001.0 1020.0 1019.0 1030.0 1035.0 1050.0 1075.0 1094.0 1115.0 1136.0 1176.0 1206.0 1260.0 1311.0 1360.0 1418.0 1505.0 1596.0 1656.0 1688.0 1731.0 1787.0 1829.0 1850.0 1866.0 1882.0 1905.0 24 | 0 1137.0 1222.0 1203.0 1072.0 904.0 754.0 692.0 666.0 663.0 662.0 680.0 694.0 718.0 748.0 782.0 827.0 861.0 926.0 964.0 985.0 1017.0 1037.0 1087.0 1106.0 1110.0 1120.0 1141.0 1172.0 1195.0 1218.0 1237.0 1266.0 1304.0 1336.0 1389.0 1447.0 1523.0 1602.0 1685.0 1781.0 1849.0 1900.0 1949.0 2045.0 2091.0 2123.0 2137.0 2162.0 2220.0 25 | 0 1137.0 1221.0 1195.0 1069.0 897.0 738.0 674.0 652.0 657.0 661.0 672.0 685.0 708.0 736.0 780.0 808.0 857.0 907.0 963.0 977.0 967.0 918.0 880.0 862.0 857.0 865.0 870.0 883.0 901.0 907.0 937.0 957.0 977.0 1004.0 1033.0 1102.0 1150.0 1213.0 1215.0 1155.0 1117.0 1107.0 1125.0 1165.0 1174.0 1186.0 1195.0 1210.0 1230.0 26 | 0 1137.0 1223.0 1223.0 1120.0 942.0 768.0 695.0 664.0 657.0 650.0 665.0 679.0 686.0 732.0 758.0 787.0 826.0 887.0 922.0 948.0 970.0 995.0 1039.0 1057.0 1063.0 1066.0 1075.0 1092.0 1121.0 1150.0 1169.0 1195.0 1220.0 1254.0 1298.0 1356.0 1413.0 1491.0 1582.0 1667.0 1718.0 1753.0 1805.0 1888.0 1945.0 1955.0 1967.0 1978.0 2020.0 27 | 0 1137.0 1218.0 1216.0 1128.0 947.0 796.0 701.0 661.0 656.0 655.0 665.0 685.0 701.0 721.0 762.0 796.0 837.0 894.0 937.0 959.0 980.0 1009.0 1044.0 1068.0 1073.0 1074.0 1078.0 1092.0 1111.0 1131.0 1151.0 1177.0 1208.0 1236.0 1281.0 1352.0 1417.0 1485.0 1570.0 1657.0 1713.0 1745.0 1790.0 1860.0 1925.0 1945.0 1949.0 1969.0 1991.0 28 | 0 1137.0 1220.0 1209.0 1091.0 915.0 779.0 693.0 665.0 659.0 664.0 678.0 698.0 710.0 748.0 786.0 811.0 849.0 909.0 950.0 977.0 1004.0 1033.0 1070.0 1094.0 1106.0 1118.0 1128.0 1155.0 1180.0 1207.0 1231.0 1260.0 1295.0 1332.0 1390.0 1462.0 1526.0 1593.0 1683.0 1776.0 1838.0 1886.0 1935.0 2011.0 2066.0 2101.0 2121.0 2144.0 2181.0 29 | 0 1137.0 1222.0 1205.0 1068.0 874.0 756.0 692.0 669.0 665.0 670.0 685.0 702.0 723.0 751.0 786.0 818.0 856.0 922.0 976.0 996.0 992.0 947.0 936.0 922.0 917.0 922.0 932.0 947.0 960.0 984.0 1007.0 1028.0 1055.0 1084.0 1115.0 1169.0 1224.0 1294.0 1324.0 1278.0 1244.0 1255.0 1285.0 1333.0 1357.0 1359.0 1365.0 1379.0 1406.0 30 | 0 1137.0 1219.0 1185.0 1059.0 894.0 744.0 685.0 667.0 661.0 660.0 680.0 700.0 721.0 743.0 773.0 807.0 855.0 904.0 958.0 987.0 1017.0 1053.0 1101.0 1122.0 1131.0 1138.0 1153.0 1179.0 1210.0 1234.0 1261.0 1289.0 1333.0 1373.0 1412.0 1466.0 1523.0 1602.0 1702.0 1798.0 1859.0 1913.0 1992.0 2067.0 2120.0 2141.0 2161.0 2186.0 2238.0 31 | 0 1137.0 1222.0 1197.0 1065.0 897.0 761.0 699.0 672.0 664.0 670.0 684.0 702.0 720.0 743.0 770.0 809.0 848.0 913.0 949.0 964.0 975.0 1007.0 1038.0 1065.0 1072.0 1080.0 1098.0 1116.0 1133.0 1155.0 1180.0 1209.0 1243.0 1274.0 1296.0 1332.0 1379.0 1445.0 1548.0 1644.0 1712.0 1764.0 1824.0 1889.0 1931.0 1949.0 1961.0 1980.0 2012.0 32 | 0 1137.0 1226.0 1206.0 1089.0 909.0 774.0 695.0 668.0 667.0 671.0 684.0 704.0 725.0 757.0 786.0 818.0 860.0 917.0 968.0 972.0 930.0 897.0 911.0 920.0 924.0 927.0 934.0 955.0 970.0 986.0 1007.0 1024.0 1060.0 1091.0 1130.0 1187.0 1181.0 1155.0 1178.0 1209.0 1232.0 1252.0 1279.0 1326.0 1361.0 1374.0 1377.0 1387.0 1411.0 33 | 0 1137.0 1221.0 1228.0 1212.0 1093.0 905.0 746.0 655.0 634.0 632.0 631.0 648.0 666.0 685.0 721.0 742.0 788.0 831.0 882.0 902.0 913.0 930.0 978.0 983.0 988.0 995.0 1010.0 1033.0 1055.0 1069.0 1092.0 1122.0 1151.0 1195.0 1230.0 1282.0 1331.0 1407.0 1471.0 1554.0 1617.0 1659.0 1703.0 1757.0 1806.0 1824.0 1828.0 1848.0 1872.0 34 | 0 1137.0 1223.0 1202.0 1080.0 905.0 769.0 698.0 668.0 660.0 665.0 683.0 697.0 725.0 751.0 793.0 820.0 868.0 917.0 975.0 993.0 1021.0 1058.0 1104.0 1126.0 1132.0 1153.0 1162.0 1174.0 1205.0 1236.0 1256.0 1288.0 1325.0 1372.0 1428.0 1484.0 1543.0 1613.0 1719.0 1824.0 1878.0 1917.0 1996.0 2072.0 2129.0 2151.0 2178.0 2198.0 2224.0 35 | 0 1137.0 1223.0 1233.0 1213.0 1123.0 916.0 774.0 689.0 655.0 650.0 654.0 662.0 682.0 718.0 749.0 780.0 812.0 852.0 900.0 921.0 942.0 962.0 1005.0 1022.0 1028.0 1031.0 1040.0 1063.0 1093.0 1110.0 1134.0 1160.0 1184.0 1221.0 1271.0 1325.0 1387.0 1442.0 1527.0 1596.0 1646.0 1691.0 1735.0 1812.0 1857.0 1872.0 1885.0 1900.0 1929.0 36 | 0 1137.0 1225.0 1211.0 1102.0 909.0 772.0 695.0 677.0 672.0 678.0 690.0 710.0 729.0 762.0 796.0 827.0 866.0 917.0 970.0 994.0 1023.0 1059.0 1105.0 1127.0 1134.0 1139.0 1155.0 1185.0 1206.0 1232.0 1257.0 1280.0 1312.0 1349.0 1415.0 1472.0 1526.0 1597.0 1698.0 1793.0 1863.0 1919.0 1972.0 2044.0 2102.0 2115.0 2128.0 2156.0 2204.0 37 | 0 1137.0 1225.0 1227.0 1164.0 992.0 813.0 687.0 648.0 638.0 646.0 637.0 646.0 652.0 676.0 707.0 736.0 773.0 805.0 838.0 848.0 875.0 906.0 939.0 952.0 937.0 932.0 921.0 931.0 947.0 971.0 982.0 987.0 993.0 1009.0 1044.0 1102.0 1151.0 1193.0 1243.0 1304.0 1350.0 1379.0 1429.0 1476.0 1514.0 1510.0 1483.0 1478.0 1499.0 38 | 0 1137.0 1223.0 1198.0 1071.0 887.0 753.0 686.0 677.0 677.0 681.0 704.0 721.0 740.0 771.0 812.0 824.0 808.0 818.0 844.0 856.0 868.0 897.0 936.0 948.0 953.0 960.0 970.0 986.0 948.0 897.0 865.0 875.0 908.0 928.0 960.0 1003.0 1034.0 1084.0 1151.0 1220.0 1253.0 1224.0 1183.0 1187.0 1191.0 1195.0 1210.0 1217.0 1235.0 39 | 0 1137.0 1221.0 1232.0 1214.0 1084.0 906.0 759.0 681.0 647.0 639.0 647.0 655.0 673.0 707.0 731.0 761.0 795.0 848.0 897.0 920.0 935.0 952.0 989.0 1007.0 1012.0 1013.0 1021.0 1041.0 1079.0 1098.0 1109.0 1136.0 1158.0 1201.0 1250.0 1278.0 1344.0 1413.0 1487.0 1581.0 1645.0 1682.0 1723.0 1774.0 1832.0 1847.0 1860.0 1877.0 1911.0 40 | 0 1137.0 1227.0 1198.0 1056.0 874.0 747.0 686.0 667.0 660.0 667.0 678.0 695.0 713.0 744.0 783.0 821.0 856.0 916.0 958.0 990.0 1014.0 1045.0 1097.0 1114.0 1122.0 1126.0 1142.0 1163.0 1189.0 1216.0 1230.0 1260.0 1286.0 1317.0 1362.0 1429.0 1493.0 1571.0 1674.0 1767.0 1831.0 1875.0 1926.0 2023.0 2066.0 2085.0 2089.0 2107.0 2153.0 41 | 0 1137.0 1222.0 1201.0 1091.0 913.0 780.0 717.0 696.0 687.0 698.0 710.0 725.0 749.0 775.0 814.0 850.0 896.0 949.0 1005.0 1040.0 1059.0 1008.0 923.0 874.0 848.0 845.0 852.0 867.0 880.0 895.0 921.0 939.0 962.0 985.0 1028.0 1065.0 1120.0 1194.0 1243.0 1276.0 1179.0 1057.0 1018.0 1033.0 1052.0 1056.0 1061.0 1073.0 1089.0 42 | 0 1137.0 1223.0 1224.0 1172.0 1014.0 838.0 733.0 690.0 676.0 643.0 633.0 624.0 629.0 654.0 674.0 692.0 725.0 760.0 796.0 813.0 817.0 829.0 851.0 860.0 865.0 867.0 863.0 854.0 870.0 877.0 895.0 913.0 928.0 937.0 962.0 1005.0 1056.0 1111.0 1149.0 1191.0 1230.0 1253.0 1282.0 1295.0 1307.0 1312.0 1323.0 1333.0 1345.0 43 | 0 1137.0 1216.0 1223.0 1194.0 1075.0 887.0 739.0 681.0 648.0 643.0 641.0 654.0 675.0 699.0 730.0 760.0 801.0 855.0 898.0 914.0 937.0 958.0 992.0 1015.0 1017.0 1026.0 1037.0 1057.0 1089.0 1110.0 1125.0 1153.0 1178.0 1212.0 1244.0 1308.0 1365.0 1432.0 1521.0 1604.0 1660.0 1690.0 1741.0 1794.0 1843.0 1866.0 1876.0 1895.0 1924.0 44 | 0 1137.0 1218.0 1199.0 1064.0 891.0 773.0 703.0 682.0 676.0 679.0 683.0 704.0 718.0 745.0 789.0 824.0 867.0 928.0 954.0 947.0 934.0 939.0 973.0 985.0 985.0 991.0 1000.0 1016.0 1037.0 1051.0 1066.0 1085.0 1114.0 1136.0 1136.0 1119.0 1123.0 1158.0 1223.0 1305.0 1352.0 1377.0 1418.0 1475.0 1514.0 1531.0 1540.0 1551.0 1580.0 45 | 0 1137.0 1223.0 1201.0 1086.0 896.0 750.0 685.0 662.0 656.0 662.0 674.0 701.0 716.0 749.0 780.0 821.0 864.0 916.0 959.0 990.0 1021.0 1052.0 1110.0 1127.0 1130.0 1139.0 1155.0 1186.0 1208.0 1227.0 1246.0 1273.0 1308.0 1356.0 1399.0 1458.0 1535.0 1609.0 1693.0 1783.0 1849.0 1908.0 1974.0 2050.0 2108.0 2129.0 2153.0 2177.0 2228.0 46 | 0 1137.0 1224.0 1201.0 1075.0 892.0 756.0 690.0 669.0 670.0 678.0 691.0 713.0 734.0 760.0 798.0 795.0 781.0 798.0 829.0 847.0 865.0 893.0 927.0 944.0 953.0 964.0 973.0 961.0 911.0 863.0 855.0 863.0 883.0 915.0 955.0 998.0 1042.0 1096.0 1160.0 1213.0 1200.0 1159.0 1140.0 1156.0 1183.0 1196.0 1207.0 1222.0 1237.0 47 | 0 1137.0 1225.0 1198.0 1079.0 877.0 735.0 665.0 638.0 630.0 638.0 649.0 668.0 686.0 714.0 750.0 780.0 824.0 874.0 922.0 953.0 968.0 942.0 953.0 957.0 954.0 959.0 968.0 980.0 1000.0 1014.0 1032.0 1052.0 1078.0 1108.0 1141.0 1201.0 1247.0 1314.0 1388.0 1407.0 1412.0 1414.0 1445.0 1513.0 1558.0 1588.0 1593.0 1612.0 1630.0 48 | 0 1137.0 1223.0 1212.0 1088.0 898.0 767.0 697.0 669.0 663.0 672.0 695.0 712.0 726.0 751.0 799.0 828.0 870.0 928.0 956.0 977.0 996.0 1026.0 1076.0 1104.0 1111.0 1122.0 1140.0 1158.0 1188.0 1214.0 1237.0 1260.0 1281.0 1298.0 1329.0 1393.0 1451.0 1531.0 1638.0 1736.0 1791.0 1835.0 1892.0 1958.0 2018.0 2039.0 2044.0 2012.0 1993.0 49 | 0 1137.0 1221.0 1194.0 1059.0 875.0 733.0 675.0 638.0 637.0 640.0 652.0 667.0 694.0 716.0 762.0 789.0 821.0 863.0 903.0 915.0 933.0 957.0 998.0 1021.0 1041.0 1043.0 1050.0 1073.0 1099.0 1111.0 1131.0 1162.0 1183.0 1208.0 1238.0 1300.0 1367.0 1425.0 1508.0 1591.0 1664.0 1711.0 1750.0 1822.0 1877.0 1923.0 1922.0 1893.0 1877.0 50 | 0 1137.0 1223.0 1203.0 1080.0 897.0 743.0 684.0 663.0 655.0 654.0 661.0 680.0 699.0 734.0 761.0 796.0 844.0 894.0 948.0 979.0 986.0 1002.0 1031.0 1026.0 1024.0 1035.0 1040.0 1057.0 1078.0 1097.0 1104.0 1121.0 1154.0 1181.0 1226.0 1276.0 1326.0 1409.0 1502.0 1573.0 1607.0 1637.0 1693.0 1754.0 1806.0 1821.0 1839.0 1854.0 1879.0 51 | 0 1137.0 1223.0 1225.0 1152.0 974.0 802.0 693.0 655.0 651.0 652.0 672.0 683.0 706.0 740.0 768.0 794.0 840.0 895.0 936.0 961.0 982.0 1017.0 1060.0 1074.0 1076.0 1077.0 1092.0 1112.0 1131.0 1151.0 1170.0 1205.0 1234.0 1283.0 1343.0 1391.0 1459.0 1528.0 1602.0 1683.0 1741.0 1782.0 1838.0 1893.0 1927.0 1953.0 1963.0 1982.0 2020.0 52 | 0 1137.0 1225.0 1201.0 1058.0 909.0 779.0 700.0 671.0 655.0 666.0 679.0 695.0 721.0 747.0 784.0 820.0 870.0 922.0 968.0 999.0 1028.0 1061.0 1104.0 1117.0 1131.0 1143.0 1149.0 1168.0 1198.0 1218.0 1249.0 1278.0 1308.0 1348.0 1399.0 1472.0 1551.0 1622.0 1724.0 1822.0 1897.0 1946.0 2010.0 2091.0 2126.0 2145.0 2168.0 2194.0 2226.0 53 | 0 1137.0 1224.0 1202.0 1072.0 905.0 768.0 691.0 671.0 675.0 679.0 695.0 713.0 732.0 760.0 794.0 835.0 871.0 939.0 991.0 1016.0 1011.0 1012.0 1024.0 1035.0 1033.0 1040.0 1044.0 1058.0 1072.0 1095.0 1111.0 1138.0 1171.0 1207.0 1250.0 1298.0 1356.0 1428.0 1488.0 1534.0 1556.0 1574.0 1623.0 1678.0 1712.0 1742.0 1757.0 1768.0 1790.0 54 | 0 1137.0 1215.0 1187.0 1049.0 896.0 739.0 674.0 655.0 657.0 663.0 677.0 699.0 717.0 748.0 781.0 820.0 862.0 916.0 977.0 1001.0 1032.0 1072.0 1116.0 1139.0 1145.0 1152.0 1163.0 1182.0 1208.0 1225.0 1245.0 1277.0 1312.0 1347.0 1399.0 1439.0 1518.0 1595.0 1696.0 1808.0 1885.0 1939.0 1995.0 2074.0 2115.0 2141.0 2163.0 2182.0 2223.0 55 | 0 1137.0 1222.0 1194.0 1081.0 907.0 766.0 693.0 673.0 664.0 664.0 679.0 699.0 721.0 751.0 793.0 821.0 860.0 917.0 963.0 996.0 1020.0 1041.0 1036.0 973.0 907.0 888.0 884.0 893.0 914.0 930.0 947.0 967.0 990.0 1027.0 1064.0 1097.0 1167.0 1231.0 1307.0 1378.0 1430.0 1445.0 1367.0 1305.0 1301.0 1286.0 1287.0 1295.0 1319.0 56 | 0 1137.0 1217.0 1189.0 1042.0 875.0 738.0 678.0 660.0 660.0 665.0 681.0 699.0 718.0 752.0 791.0 823.0 869.0 920.0 959.0 986.0 1007.0 1037.0 1078.0 1097.0 1111.0 1114.0 1127.0 1160.0 1186.0 1210.0 1231.0 1262.0 1303.0 1324.0 1373.0 1433.0 1497.0 1572.0 1682.0 1754.0 1828.0 1876.0 1926.0 1987.0 2044.0 2075.0 2092.0 2104.0 2132.0 57 | 0 1137.0 1217.0 1204.0 1096.0 913.0 756.0 701.0 676.0 671.0 680.0 693.0 708.0 726.0 754.0 795.0 827.0 865.0 924.0 967.0 994.0 1015.0 1048.0 1099.0 1117.0 1128.0 1134.0 1142.0 1163.0 1182.0 1206.0 1231.0 1263.0 1297.0 1331.0 1383.0 1444.0 1513.0 1572.0 1669.0 1765.0 1836.0 1865.0 1918.0 1990.0 2032.0 2057.0 2068.0 2082.0 2125.0 58 | 0 1137.0 1224.0 1214.0 1084.0 906.0 775.0 703.0 672.0 662.0 667.0 681.0 697.0 709.0 736.0 779.0 816.0 858.0 908.0 970.0 986.0 1016.0 1043.0 1087.0 1108.0 1121.0 1127.0 1142.0 1155.0 1178.0 1194.0 1219.0 1249.0 1279.0 1314.0 1345.0 1409.0 1486.0 1566.0 1653.0 1752.0 1814.0 1870.0 1907.0 1960.0 2006.0 2034.0 2048.0 2070.0 2102.0 59 | 0 1137.0 1219.0 1192.0 1061.0 898.0 752.0 680.0 647.0 643.0 648.0 666.0 680.0 700.0 726.0 762.0 800.0 832.0 888.0 932.0 965.0 1001.0 1038.0 1074.0 1100.0 1106.0 1121.0 1138.0 1158.0 1180.0 1201.0 1219.0 1240.0 1279.0 1309.0 1358.0 1419.0 1498.0 1569.0 1649.0 1746.0 1806.0 1881.0 1942.0 2003.0 2056.0 2072.0 2083.0 2116.0 2156.0 60 | 0 1137.0 1223.0 1207.0 1084.0 886.0 746.0 703.0 666.0 654.0 665.0 674.0 688.0 709.0 735.0 774.0 810.0 849.0 904.0 957.0 980.0 997.0 1026.0 1075.0 1095.0 1099.0 1117.0 1132.0 1158.0 1180.0 1207.0 1223.0 1263.0 1287.0 1317.0 1354.0 1417.0 1485.0 1554.0 1650.0 1753.0 1816.0 1870.0 1925.0 1997.0 2052.0 2074.0 2102.0 2134.0 2167.0 61 | 0 1137.0 1225.0 1226.0 1166.0 999.0 826.0 718.0 664.0 659.0 646.0 627.0 629.0 631.0 658.0 683.0 708.0 736.0 781.0 811.0 835.0 851.0 875.0 888.0 880.0 873.0 872.0 875.0 884.0 889.0 883.0 878.0 893.0 919.0 943.0 983.0 1022.0 1048.0 1086.0 1170.0 1227.0 1271.0 1303.0 1319.0 1325.0 1352.0 1364.0 1379.0 1380.0 1367.0 62 | 0 1137.0 1224.0 1234.0 1236.0 1223.0 1189.0 1085.0 950.0 813.0 727.0 671.0 642.0 625.0 626.0 657.0 676.0 709.0 746.0 782.0 806.0 821.0 830.0 869.0 867.0 865.0 855.0 865.0 862.0 873.0 893.0 899.0 905.0 931.0 947.0 980.0 1018.0 1068.0 1118.0 1182.0 1246.0 1282.0 1303.0 1330.0 1377.0 1402.0 1409.0 1404.0 1400.0 1404.0 63 | 0 1137.0 1220.0 1194.0 1062.0 896.0 762.0 702.0 671.0 673.0 684.0 698.0 716.0 736.0 764.0 791.0 815.0 863.0 920.0 978.0 1012.0 1035.0 1073.0 1112.0 1123.0 1114.0 1106.0 1114.0 1130.0 1145.0 1159.0 1192.0 1222.0 1247.0 1301.0 1341.0 1390.0 1440.0 1510.0 1590.0 1706.0 1770.0 1822.0 1883.0 1959.0 1973.0 1974.0 1960.0 1981.0 2004.0 64 | 0 1137.0 1222.0 1198.0 1071.0 881.0 748.0 672.0 654.0 653.0 663.0 679.0 700.0 723.0 746.0 783.0 827.0 863.0 904.0 933.0 944.0 946.0 963.0 1009.0 1025.0 1030.0 1034.0 1048.0 1062.0 1075.0 1090.0 1115.0 1129.0 1120.0 1117.0 1131.0 1169.0 1252.0 1306.0 1393.0 1467.0 1528.0 1565.0 1606.0 1665.0 1702.0 1722.0 1724.0 1669.0 1610.0 65 | 0 1137.0 1224.0 1219.0 1139.0 970.0 821.0 726.0 674.0 669.0 670.0 659.0 657.0 656.0 677.0 707.0 738.0 760.0 794.0 836.0 866.0 887.0 913.0 949.0 944.0 935.0 936.0 956.0 973.0 978.0 977.0 967.0 981.0 1017.0 1048.0 1082.0 1115.0 1156.0 1200.0 1265.0 1329.0 1387.0 1400.0 1422.0 1449.0 1490.0 1510.0 1522.0 1530.0 1517.0 66 | 0 1137.0 1223.0 1200.0 1074.0 909.0 765.0 699.0 669.0 667.0 667.0 678.0 686.0 701.0 721.0 748.0 786.0 831.0 888.0 930.0 944.0 957.0 983.0 1039.0 1059.0 1062.0 1064.0 1057.0 1071.0 1090.0 1114.0 1131.0 1154.0 1185.0 1211.0 1236.0 1276.0 1322.0 1405.0 1501.0 1582.0 1642.0 1666.0 1684.0 1742.0 1809.0 1817.0 1826.0 1842.0 1872.0 67 | 0 1137.0 1225.0 1233.0 1239.0 1185.0 1041.0 867.0 747.0 684.0 659.0 653.0 670.0 681.0 710.0 743.0 769.0 804.0 858.0 894.0 917.0 937.0 959.0 998.0 1009.0 1001.0 1012.0 1016.0 1031.0 1046.0 1074.0 1094.0 1129.0 1157.0 1202.0 1245.0 1289.0 1352.0 1422.0 1483.0 1563.0 1621.0 1646.0 1688.0 1756.0 1791.0 1804.0 1816.0 1829.0 1851.0 68 | 0 1137.0 1222.0 1206.0 1064.0 888.0 762.0 679.0 653.0 645.0 661.0 670.0 691.0 712.0 743.0 781.0 821.0 859.0 908.0 949.0 970.0 995.0 1022.0 1068.0 1090.0 1099.0 1108.0 1117.0 1136.0 1161.0 1188.0 1211.0 1236.0 1262.0 1300.0 1334.0 1390.0 1469.0 1534.0 1634.0 1727.0 1792.0 1841.0 1895.0 1968.0 2020.0 2035.0 2041.0 2027.0 2009.0 69 | 0 1137.0 1225.0 1237.0 1233.0 1164.0 1019.0 831.0 708.0 647.0 612.0 609.0 621.0 635.0 663.0 683.0 716.0 761.0 797.0 843.0 864.0 888.0 910.0 953.0 963.0 961.0 964.0 967.0 974.0 995.0 1015.0 1031.0 1052.0 1080.0 1105.0 1151.0 1194.0 1243.0 1314.0 1386.0 1453.0 1516.0 1555.0 1605.0 1662.0 1699.0 1696.0 1700.0 1715.0 1723.0 70 | 0 1137.0 1220.0 1208.0 1094.0 883.0 737.0 679.0 652.0 658.0 662.0 676.0 689.0 711.0 742.0 773.0 799.0 856.0 912.0 956.0 981.0 1005.0 1033.0 1087.0 1107.0 1117.0 1121.0 1136.0 1158.0 1178.0 1201.0 1226.0 1259.0 1283.0 1318.0 1382.0 1436.0 1501.0 1582.0 1676.0 1775.0 1827.0 1878.0 1943.0 2017.0 2060.0 2087.0 2114.0 2137.0 2175.0 71 | 0 1137.0 1225.0 1191.0 1053.0 869.0 719.0 658.0 644.0 642.0 657.0 668.0 689.0 706.0 730.0 756.0 783.0 822.0 877.0 923.0 959.0 983.0 1020.0 1060.0 1082.0 1078.0 1072.0 1077.0 1088.0 1110.0 1132.0 1161.0 1189.0 1231.0 1272.0 1311.0 1365.0 1436.0 1482.0 1562.0 1639.0 1710.0 1765.0 1825.0 1912.0 1947.0 1955.0 1966.0 1977.0 1990.0 72 | 0 1137.0 1215.0 1206.0 1087.0 917.0 769.0 701.0 684.0 674.0 676.0 690.0 710.0 731.0 757.0 797.0 826.0 873.0 926.0 981.0 1013.0 1035.0 1075.0 1110.0 1127.0 1137.0 1145.0 1156.0 1179.0 1207.0 1233.0 1254.0 1277.0 1317.0 1351.0 1407.0 1464.0 1517.0 1599.0 1704.0 1820.0 1893.0 1955.0 2030.0 2093.0 2139.0 2163.0 2179.0 2199.0 2223.0 73 | 0 1137.0 1214.0 1198.0 1085.0 913.0 772.0 714.0 701.0 703.0 699.0 703.0 721.0 747.0 779.0 805.0 839.0 887.0 947.0 990.0 1021.0 1053.0 1083.0 1134.0 1155.0 1172.0 1185.0 1196.0 1218.0 1249.0 1280.0 1302.0 1325.0 1353.0 1396.0 1458.0 1514.0 1583.0 1668.0 1775.0 1857.0 1940.0 1992.0 2045.0 2140.0 2190.0 2225.0 2249.0 2273.0 2313.0 74 | 0 1137.0 1221.0 1198.0 1074.0 909.0 752.0 688.0 661.0 663.0 667.0 677.0 694.0 715.0 742.0 778.0 812.0 865.0 926.0 979.0 1004.0 1028.0 1060.0 1102.0 1123.0 1132.0 1138.0 1150.0 1161.0 1187.0 1210.0 1249.0 1274.0 1305.0 1356.0 1392.0 1462.0 1519.0 1607.0 1720.0 1839.0 1889.0 1941.0 2007.0 2092.0 2137.0 2160.0 2180.0 2206.0 2233.0 75 | 0 1137.0 1222.0 1197.0 1060.0 894.0 760.0 682.0 672.0 673.0 674.0 679.0 700.0 724.0 751.0 785.0 811.0 839.0 886.0 936.0 956.0 984.0 1012.0 1069.0 1085.0 1093.0 1107.0 1117.0 1119.0 1110.0 1113.0 1133.0 1153.0 1188.0 1233.0 1279.0 1348.0 1413.0 1478.0 1563.0 1641.0 1684.0 1684.0 1711.0 1771.0 1827.0 1846.0 1873.0 1896.0 1923.0 76 | 0 1137.0 1224.0 1210.0 1082.0 889.0 759.0 681.0 651.0 652.0 656.0 663.0 681.0 708.0 734.0 762.0 789.0 811.0 853.0 893.0 921.0 948.0 992.0 1027.0 1041.0 1047.0 1051.0 1060.0 1068.0 1058.0 1055.0 1073.0 1071.0 1101.0 1148.0 1198.0 1251.0 1322.0 1382.0 1463.0 1537.0 1585.0 1596.0 1637.0 1701.0 1738.0 1756.0 1778.0 1794.0 1822.0 77 | 0 1137.0 1227.0 1207.0 1112.0 927.0 777.0 685.0 661.0 654.0 664.0 676.0 697.0 717.0 746.0 769.0 803.0 846.0 890.0 941.0 971.0 999.0 1033.0 1076.0 1097.0 1107.0 1115.0 1109.0 1093.0 1088.0 1090.0 1102.0 1130.0 1154.0 1188.0 1237.0 1293.0 1340.0 1411.0 1469.0 1518.0 1567.0 1617.0 1674.0 1744.0 1796.0 1818.0 1829.0 1858.0 1891.0 78 | 0 1137.0 1224.0 1199.0 1067.0 883.0 765.0 712.0 684.0 685.0 694.0 709.0 726.0 748.0 781.0 816.0 853.0 904.0 957.0 1010.0 1048.0 1062.0 1067.0 1096.0 1111.0 1120.0 1129.0 1136.0 1151.0 1179.0 1199.0 1217.0 1239.0 1278.0 1309.0 1354.0 1394.0 1465.0 1546.0 1623.0 1702.0 1752.0 1817.0 1866.0 1948.0 2021.0 2043.0 2055.0 2072.0 2102.0 79 | 0 1137.0 1224.0 1196.0 1077.0 909.0 759.0 680.0 655.0 652.0 662.0 684.0 696.0 714.0 748.0 782.0 809.0 855.0 912.0 960.0 978.0 1004.0 1037.0 1080.0 1098.0 1110.0 1123.0 1138.0 1156.0 1171.0 1196.0 1223.0 1262.0 1294.0 1318.0 1361.0 1415.0 1458.0 1547.0 1647.0 1753.0 1814.0 1863.0 1928.0 1998.0 2068.0 2088.0 2109.0 2131.0 2147.0 80 | 0 1137.0 1214.0 1194.0 1075.0 888.0 748.0 689.0 671.0 657.0 665.0 680.0 698.0 717.0 743.0 778.0 806.0 856.0 914.0 961.0 979.0 965.0 910.0 878.0 874.0 872.0 868.0 874.0 887.0 901.0 919.0 938.0 963.0 988.0 1006.0 1047.0 1102.0 1158.0 1204.0 1211.0 1174.0 1126.0 1126.0 1147.0 1182.0 1218.0 1233.0 1238.0 1251.0 1273.0 81 | 0 1137.0 1219.0 1190.0 1083.0 891.0 748.0 692.0 675.0 676.0 681.0 694.0 712.0 731.0 765.0 800.0 838.0 887.0 940.0 980.0 996.0 1006.0 1042.0 1082.0 1104.0 1113.0 1123.0 1138.0 1157.0 1185.0 1206.0 1217.0 1250.0 1278.0 1313.0 1359.0 1414.0 1476.0 1544.0 1633.0 1730.0 1813.0 1868.0 1925.0 2010.0 2066.0 2086.0 2108.0 2138.0 2173.0 82 | 0 1137.0 1212.0 1188.0 1059.0 877.0 727.0 673.0 650.0 647.0 656.0 670.0 687.0 702.0 737.0 768.0 797.0 844.0 896.0 933.0 975.0 993.0 998.0 1021.0 1035.0 1042.0 1051.0 1063.0 1079.0 1091.0 1111.0 1130.0 1156.0 1181.0 1216.0 1264.0 1307.0 1364.0 1430.0 1522.0 1594.0 1643.0 1672.0 1712.0 1783.0 1846.0 1877.0 1892.0 1912.0 1928.0 83 | 0 1137.0 1224.0 1217.0 1137.0 971.0 828.0 715.0 673.0 651.0 643.0 651.0 659.0 683.0 709.0 745.0 770.0 814.0 863.0 911.0 938.0 950.0 971.0 1016.0 1034.0 1038.0 1042.0 1046.0 1058.0 1081.0 1102.0 1125.0 1143.0 1160.0 1192.0 1244.0 1303.0 1360.0 1435.0 1520.0 1596.0 1655.0 1696.0 1726.0 1785.0 1839.0 1850.0 1856.0 1862.0 1878.0 84 | 0 1137.0 1225.0 1222.0 1126.0 963.0 810.0 703.0 658.0 647.0 651.0 660.0 675.0 700.0 728.0 759.0 784.0 827.0 871.0 917.0 944.0 971.0 1000.0 1045.0 1072.0 1079.0 1083.0 1098.0 1107.0 1121.0 1133.0 1148.0 1177.0 1212.0 1258.0 1295.0 1355.0 1416.0 1499.0 1586.0 1657.0 1705.0 1748.0 1806.0 1860.0 1927.0 1954.0 1965.0 1987.0 2023.0 85 | 0 1137.0 1220.0 1224.0 1152.0 971.0 799.0 693.0 650.0 640.0 630.0 632.0 644.0 657.0 683.0 711.0 739.0 772.0 824.0 863.0 886.0 902.0 908.0 947.0 959.0 970.0 969.0 974.0 995.0 1016.0 1040.0 1056.0 1078.0 1103.0 1127.0 1160.0 1220.0 1275.0 1342.0 1417.0 1486.0 1538.0 1575.0 1603.0 1631.0 1665.0 1680.0 1692.0 1715.0 1746.0 86 | 0 1137.0 1225.0 1209.0 1095.0 902.0 755.0 699.0 679.0 677.0 680.0 688.0 709.0 727.0 763.0 793.0 822.0 879.0 934.0 976.0 1001.0 1018.0 1024.0 1049.0 1061.0 1069.0 1078.0 1096.0 1114.0 1135.0 1146.0 1162.0 1197.0 1224.0 1259.0 1301.0 1359.0 1417.0 1500.0 1592.0 1664.0 1694.0 1724.0 1764.0 1851.0 1912.0 1938.0 1953.0 1965.0 1991.0 87 | 0 1137.0 1219.0 1208.0 1110.0 917.0 746.0 684.0 656.0 648.0 653.0 655.0 682.0 692.0 721.0 754.0 793.0 833.0 882.0 929.0 954.0 976.0 1012.0 1049.0 1073.0 1079.0 1081.0 1094.0 1124.0 1149.0 1167.0 1198.0 1220.0 1246.0 1285.0 1329.0 1383.0 1443.0 1507.0 1621.0 1693.0 1754.0 1796.0 1845.0 1924.0 1966.0 1983.0 1997.0 2007.0 2040.0 88 | 0 1137.0 1226.0 1198.0 1065.0 869.0 731.0 655.0 644.0 638.0 645.0 656.0 668.0 682.0 723.0 753.0 783.0 825.0 872.0 907.0 939.0 961.0 991.0 1048.0 1065.0 1071.0 1083.0 1104.0 1119.0 1132.0 1153.0 1155.0 1165.0 1192.0 1218.0 1273.0 1335.0 1396.0 1462.0 1562.0 1658.0 1731.0 1783.0 1828.0 1869.0 1882.0 1877.0 1893.0 1913.0 1945.0 89 | 0 1137.0 1221.0 1199.0 1065.0 890.0 729.0 668.0 641.0 640.0 645.0 664.0 685.0 714.0 733.0 760.0 793.0 830.0 881.0 932.0 965.0 993.0 1028.0 1073.0 1091.0 1080.0 1061.0 1065.0 1079.0 1102.0 1125.0 1152.0 1180.0 1210.0 1261.0 1299.0 1345.0 1385.0 1441.0 1503.0 1591.0 1664.0 1716.0 1778.0 1848.0 1907.0 1913.0 1899.0 1874.0 1890.0 90 | 0 1137.0 1219.0 1196.0 1056.0 910.0 754.0 694.0 657.0 642.0 647.0 667.0 682.0 708.0 740.0 776.0 807.0 856.0 897.0 946.0 977.0 1003.0 1039.0 1072.0 1094.0 1103.0 1107.0 1127.0 1155.0 1176.0 1192.0 1208.0 1250.0 1285.0 1320.0 1375.0 1451.0 1515.0 1594.0 1688.0 1771.0 1843.0 1893.0 1950.0 2028.0 2079.0 2097.0 2106.0 2129.0 2176.0 91 | 0 1137.0 1222.0 1201.0 1067.0 899.0 755.0 686.0 661.0 661.0 662.0 678.0 701.0 727.0 754.0 774.0 797.0 838.0 892.0 937.0 963.0 992.0 1023.0 1071.0 1089.0 1077.0 1058.0 1057.0 1060.0 1085.0 1104.0 1132.0 1154.0 1192.0 1230.0 1289.0 1333.0 1372.0 1424.0 1524.0 1603.0 1660.0 1709.0 1762.0 1836.0 1906.0 1904.0 1893.0 1872.0 1872.0 92 | 0 1137.0 1226.0 1192.0 1079.0 916.0 767.0 690.0 665.0 646.0 648.0 654.0 672.0 696.0 731.0 770.0 797.0 842.0 896.0 922.0 945.0 964.0 985.0 1033.0 1062.0 1074.0 1080.0 1093.0 1111.0 1130.0 1146.0 1163.0 1183.0 1203.0 1215.0 1232.0 1279.0 1338.0 1409.0 1513.0 1594.0 1656.0 1700.0 1733.0 1799.0 1842.0 1869.0 1883.0 1900.0 1879.0 93 | 0 1137.0 1225.0 1214.0 1117.0 958.0 777.0 686.0 645.0 641.0 635.0 655.0 665.0 684.0 707.0 737.0 773.0 809.0 871.0 904.0 937.0 958.0 973.0 1016.0 1032.0 1043.0 1052.0 1062.0 1082.0 1104.0 1130.0 1146.0 1193.0 1214.0 1238.0 1283.0 1331.0 1396.0 1455.0 1561.0 1651.0 1718.0 1757.0 1800.0 1863.0 1920.0 1948.0 1963.0 1988.0 2018.0 94 | 0 1137.0 1221.0 1192.0 1060.0 885.0 735.0 677.0 652.0 643.0 646.0 659.0 684.0 699.0 730.0 759.0 787.0 822.0 867.0 919.0 951.0 980.0 1018.0 1055.0 1087.0 1094.0 1099.0 1090.0 1086.0 1090.0 1100.0 1115.0 1138.0 1178.0 1213.0 1265.0 1321.0 1384.0 1462.0 1527.0 1575.0 1623.0 1670.0 1719.0 1783.0 1849.0 1866.0 1892.0 1907.0 1937.0 95 | 0 1137.0 1222.0 1234.0 1233.0 1177.0 1028.0 847.0 702.0 632.0 609.0 604.0 612.0 630.0 654.0 685.0 708.0 742.0 782.0 819.0 838.0 846.0 863.0 900.0 911.0 915.0 921.0 928.0 936.0 949.0 964.0 984.0 1001.0 1034.0 1057.0 1100.0 1161.0 1213.0 1262.0 1307.0 1380.0 1417.0 1453.0 1496.0 1540.0 1561.0 1579.0 1585.0 1598.0 1619.0 96 | 0 1137.0 1216.0 1200.0 1081.0 890.0 770.0 704.0 674.0 671.0 677.0 694.0 713.0 731.0 764.0 801.0 817.0 844.0 890.0 936.0 960.0 989.0 1025.0 1070.0 1085.0 1099.0 1109.0 1116.0 1135.0 1135.0 1128.0 1130.0 1160.0 1179.0 1213.0 1262.0 1330.0 1395.0 1459.0 1544.0 1640.0 1683.0 1705.0 1732.0 1774.0 1808.0 1836.0 1848.0 1870.0 1913.0 97 | 0 1137.0 1220.0 1201.0 1074.0 904.0 770.0 698.0 680.0 674.0 683.0 699.0 716.0 727.0 759.0 795.0 828.0 863.0 914.0 961.0 987.0 1010.0 1041.0 1091.0 1111.0 1116.0 1121.0 1134.0 1158.0 1166.0 1181.0 1190.0 1209.0 1241.0 1265.0 1328.0 1394.0 1467.0 1542.0 1635.0 1738.0 1797.0 1822.0 1846.0 1899.0 1947.0 1974.0 1986.0 2007.0 2049.0 98 | 0 1137.0 1227.0 1197.0 1083.0 895.0 760.0 678.0 664.0 664.0 671.0 683.0 707.0 722.0 753.0 784.0 817.0 859.0 917.0 971.0 985.0 953.0 928.0 946.0 960.0 962.0 963.0 973.0 989.0 1018.0 1034.0 1053.0 1085.0 1104.0 1131.0 1161.0 1214.0 1248.0 1247.0 1236.0 1278.0 1326.0 1358.0 1385.0 1434.0 1475.0 1488.0 1500.0 1514.0 1535.0 99 | 0 1137.0 1226.0 1211.0 1093.0 899.0 762.0 689.0 666.0 672.0 678.0 697.0 701.0 706.0 735.0 769.0 808.0 850.0 903.0 951.0 968.0 985.0 1022.0 1069.0 1088.0 1094.0 1095.0 1082.0 1087.0 1090.0 1109.0 1141.0 1172.0 1195.0 1217.0 1253.0 1310.0 1367.0 1448.0 1534.0 1616.0 1665.0 1698.0 1726.0 1773.0 1803.0 1820.0 1834.0 1856.0 1882.0 100 | 0 1137.0 1222.0 1194.0 1062.0 856.0 732.0 651.0 642.0 643.0 646.0 661.0 676.0 702.0 730.0 763.0 799.0 837.0 890.0 944.0 975.0 996.0 1025.0 995.0 900.0 825.0 808.0 806.0 820.0 834.0 849.0 860.0 876.0 903.0 938.0 962.0 1003.0 1065.0 1110.0 1176.0 1236.0 1289.0 1292.0 1194.0 1096.0 1028.0 1018.0 1018.0 1021.0 1036.0 101 | 0 1137.0 1223.0 1213.0 1090.0 918.0 748.0 695.0 673.0 662.0 662.0 674.0 690.0 717.0 750.0 780.0 783.0 754.0 746.0 755.0 780.0 800.0 831.0 870.0 886.0 894.0 897.0 902.0 916.0 881.0 824.0 782.0 781.0 795.0 820.0 855.0 893.0 931.0 961.0 1014.0 1064.0 1088.0 1056.0 1001.0 989.0 1009.0 1014.0 1020.0 1030.0 1053.0 102 | 0 1137.0 1220.0 1202.0 1079.0 892.0 743.0 684.0 682.0 669.0 680.0 693.0 713.0 734.0 765.0 794.0 831.0 873.0 923.0 978.0 1005.0 1037.0 1072.0 1109.0 1095.0 1095.0 1101.0 1106.0 1129.0 1146.0 1175.0 1210.0 1248.0 1269.0 1303.0 1341.0 1400.0 1453.0 1512.0 1595.0 1681.0 1752.0 1798.0 1828.0 1882.0 1921.0 1937.0 1963.0 1983.0 2019.0 103 | 0 1137.0 1220.0 1215.0 1114.0 942.0 791.0 693.0 652.0 643.0 646.0 665.0 680.0 702.0 718.0 755.0 788.0 829.0 878.0 924.0 948.0 969.0 991.0 1037.0 1050.0 1054.0 1066.0 1074.0 1090.0 1105.0 1128.0 1152.0 1174.0 1207.0 1246.0 1283.0 1338.0 1389.0 1463.0 1536.0 1632.0 1687.0 1732.0 1782.0 1843.0 1882.0 1904.0 1908.0 1931.0 1970.0 104 | 0 1137.0 1217.0 1197.0 1077.0 870.0 734.0 664.0 653.0 646.0 650.0 667.0 688.0 702.0 725.0 755.0 775.0 815.0 877.0 927.0 959.0 990.0 1021.0 1066.0 1075.0 1056.0 1051.0 1057.0 1073.0 1096.0 1116.0 1138.0 1171.0 1201.0 1239.0 1281.0 1318.0 1369.0 1423.0 1511.0 1607.0 1667.0 1714.0 1776.0 1836.0 1875.0 1859.0 1859.0 1875.0 1895.0 105 | 0 1137.0 1221.0 1217.0 1105.0 907.0 770.0 692.0 661.0 656.0 655.0 674.0 689.0 706.0 743.0 780.0 813.0 857.0 911.0 951.0 986.0 1008.0 1035.0 1086.0 1104.0 1112.0 1122.0 1135.0 1163.0 1187.0 1213.0 1234.0 1267.0 1307.0 1339.0 1396.0 1466.0 1538.0 1613.0 1709.0 1795.0 1859.0 1918.0 1974.0 2057.0 2113.0 2135.0 2160.0 2185.0 2234.0 106 | 0 1137.0 1222.0 1194.0 1059.0 887.0 750.0 675.0 647.0 652.0 662.0 670.0 688.0 709.0 736.0 772.0 799.0 846.0 904.0 937.0 951.0 975.0 1002.0 1048.0 1074.0 1087.0 1099.0 1102.0 1122.0 1146.0 1169.0 1188.0 1211.0 1230.0 1237.0 1274.0 1314.0 1375.0 1452.0 1539.0 1639.0 1706.0 1741.0 1793.0 1853.0 1905.0 1925.0 1949.0 1955.0 1930.0 107 | 0 1137.0 1225.0 1233.0 1226.0 1175.0 1020.0 845.0 743.0 658.0 623.0 609.0 621.0 638.0 645.0 675.0 704.0 741.0 787.0 815.0 839.0 855.0 876.0 908.0 920.0 922.0 923.0 935.0 951.0 955.0 971.0 993.0 1015.0 1041.0 1070.0 1108.0 1149.0 1202.0 1271.0 1356.0 1416.0 1470.0 1506.0 1538.0 1588.0 1618.0 1630.0 1634.0 1648.0 1678.0 108 | 0 1137.0 1223.0 1198.0 1056.0 870.0 739.0 671.0 638.0 637.0 640.0 651.0 659.0 681.0 715.0 751.0 776.0 821.0 878.0 913.0 929.0 954.0 975.0 1028.0 1047.0 1055.0 1056.0 1072.0 1093.0 1114.0 1127.0 1140.0 1165.0 1181.0 1199.0 1221.0 1265.0 1317.0 1383.0 1497.0 1596.0 1648.0 1699.0 1733.0 1799.0 1854.0 1879.0 1884.0 1901.0 1879.0 109 | 0 1137.0 1224.0 1214.0 1093.0 892.0 750.0 687.0 654.0 646.0 653.0 667.0 683.0 706.0 731.0 769.0 792.0 844.0 898.0 945.0 975.0 1000.0 1034.0 1075.0 1085.0 1094.0 1101.0 1116.0 1133.0 1158.0 1182.0 1214.0 1239.0 1269.0 1316.0 1356.0 1423.0 1481.0 1557.0 1651.0 1756.0 1823.0 1858.0 1918.0 1988.0 2021.0 2051.0 2061.0 2079.0 2107.0 110 | 0 1137.0 1222.0 1200.0 1078.0 895.0 753.0 689.0 653.0 649.0 658.0 671.0 694.0 712.0 744.0 772.0 807.0 855.0 903.0 950.0 983.0 1014.0 1040.0 1086.0 1104.0 1117.0 1127.0 1142.0 1172.0 1191.0 1222.0 1240.0 1260.0 1297.0 1329.0 1389.0 1446.0 1508.0 1602.0 1692.0 1792.0 1863.0 1918.0 1970.0 2042.0 2087.0 2125.0 2148.0 2170.0 2212.0 111 | 0 1137.0 1224.0 1219.0 1143.0 990.0 805.0 733.0 698.0 677.0 669.0 675.0 696.0 711.0 734.0 771.0 795.0 835.0 894.0 931.0 963.0 987.0 1008.0 1036.0 1054.0 1055.0 1060.0 1064.0 1079.0 1093.0 1116.0 1129.0 1155.0 1191.0 1222.0 1267.0 1316.0 1366.0 1427.0 1521.0 1577.0 1656.0 1696.0 1742.0 1800.0 1840.0 1845.0 1859.0 1875.0 1898.0 112 | 0 1137.0 1223.0 1204.0 1066.0 881.0 752.0 675.0 647.0 649.0 653.0 671.0 683.0 713.0 742.0 776.0 808.0 849.0 908.0 953.0 972.0 1004.0 1040.0 1079.0 1099.0 1116.0 1121.0 1140.0 1156.0 1182.0 1200.0 1225.0 1255.0 1287.0 1331.0 1380.0 1447.0 1518.0 1591.0 1678.0 1794.0 1845.0 1893.0 1950.0 2036.0 2090.0 2115.0 2139.0 2169.0 2201.0 113 | 0 1137.0 1226.0 1239.0 1226.0 1163.0 1023.0 841.0 705.0 653.0 627.0 625.0 628.0 642.0 664.0 696.0 713.0 757.0 790.0 837.0 864.0 877.0 904.0 948.0 959.0 960.0 965.0 975.0 994.0 1002.0 1019.0 1035.0 1064.0 1083.0 1114.0 1151.0 1199.0 1250.0 1310.0 1376.0 1473.0 1522.0 1563.0 1612.0 1671.0 1717.0 1722.0 1727.0 1731.0 1761.0 114 | 0 1137.0 1229.0 1211.0 1090.0 916.0 776.0 704.0 682.0 674.0 677.0 696.0 713.0 733.0 747.0 731.0 729.0 758.0 806.0 851.0 877.0 900.0 932.0 981.0 983.0 937.0 897.0 863.0 870.0 886.0 905.0 923.0 934.0 962.0 986.0 993.0 987.0 994.0 1028.0 1078.0 1134.0 1174.0 1201.0 1250.0 1308.0 1348.0 1309.0 1239.0 1203.0 1212.0 115 | 0 1137.0 1219.0 1199.0 1064.0 889.0 761.0 695.0 657.0 656.0 655.0 671.0 692.0 713.0 743.0 773.0 806.0 854.0 905.0 952.0 975.0 1000.0 1037.0 1085.0 1101.0 1103.0 1106.0 1114.0 1139.0 1161.0 1190.0 1207.0 1238.0 1272.0 1310.0 1348.0 1419.0 1486.0 1562.0 1658.0 1748.0 1797.0 1845.0 1895.0 1969.0 2031.0 2044.0 2056.0 2070.0 2103.0 116 | 0 1137.0 1222.0 1202.0 1062.0 895.0 765.0 699.0 676.0 676.0 680.0 693.0 711.0 729.0 753.0 794.0 829.0 873.0 932.0 974.0 1012.0 1023.0 979.0 933.0 904.0 883.0 874.0 882.0 899.0 916.0 930.0 946.0 963.0 992.0 1022.0 1054.0 1104.0 1164.0 1230.0 1321.0 1325.0 1250.0 1173.0 1169.0 1190.0 1214.0 1219.0 1225.0 1234.0 1250.0 117 | 0 1137.0 1220.0 1206.0 1102.0 931.0 792.0 713.0 678.0 673.0 669.0 684.0 700.0 717.0 746.0 778.0 813.0 855.0 900.0 946.0 982.0 1008.0 1025.0 1082.0 1100.0 1110.0 1117.0 1126.0 1153.0 1177.0 1202.0 1230.0 1255.0 1287.0 1319.0 1365.0 1428.0 1490.0 1561.0 1650.0 1732.0 1805.0 1865.0 1901.0 1959.0 2025.0 2048.0 2059.0 2079.0 2125.0 118 | 0 1137.0 1221.0 1198.0 1062.0 862.0 721.0 666.0 643.0 639.0 637.0 657.0 676.0 697.0 715.0 751.0 782.0 822.0 872.0 927.0 956.0 971.0 995.0 1022.0 1037.0 1034.0 1048.0 1068.0 1085.0 1113.0 1133.0 1148.0 1173.0 1200.0 1241.0 1280.0 1319.0 1381.0 1445.0 1523.0 1612.0 1660.0 1699.0 1743.0 1808.0 1870.0 1890.0 1909.0 1939.0 1970.0 119 | 0 1137.0 1226.0 1203.0 1082.0 909.0 751.0 670.0 639.0 640.0 642.0 657.0 671.0 691.0 720.0 753.0 786.0 826.0 891.0 932.0 962.0 984.0 1015.0 1063.0 1084.0 1094.0 1101.0 1110.0 1130.0 1158.0 1184.0 1205.0 1234.0 1270.0 1309.0 1356.0 1419.0 1475.0 1560.0 1667.0 1762.0 1824.0 1880.0 1923.0 2004.0 2069.0 2094.0 2101.0 2123.0 2160.0 120 | 0 1137.0 1224.0 1209.0 1093.0 923.0 779.0 691.0 674.0 660.0 668.0 682.0 701.0 722.0 748.0 776.0 812.0 857.0 908.0 968.0 1002.0 1020.0 1052.0 1106.0 1131.0 1141.0 1156.0 1171.0 1195.0 1221.0 1244.0 1269.0 1294.0 1336.0 1378.0 1427.0 1472.0 1548.0 1620.0 1713.0 1822.0 1905.0 1954.0 2004.0 2095.0 2160.0 2183.0 2206.0 2241.0 2276.0 121 | 0 1137.0 1228.0 1201.0 1102.0 915.0 760.0 695.0 663.0 662.0 662.0 676.0 696.0 714.0 738.0 778.0 815.0 856.0 911.0 971.0 1001.0 1022.0 991.0 935.0 879.0 869.0 872.0 886.0 897.0 912.0 926.0 938.0 959.0 970.0 994.0 1033.0 1074.0 1127.0 1197.0 1266.0 1303.0 1229.0 1162.0 1141.0 1173.0 1198.0 1200.0 1208.0 1219.0 1240.0 122 | 0 1137.0 1220.0 1208.0 1069.0 909.0 763.0 675.0 655.0 644.0 647.0 667.0 682.0 705.0 732.0 755.0 777.0 811.0 870.0 910.0 936.0 962.0 991.0 1045.0 1050.0 1015.0 999.0 993.0 1006.0 1030.0 1052.0 1071.0 1104.0 1130.0 1177.0 1200.0 1234.0 1274.0 1327.0 1418.0 1497.0 1553.0 1603.0 1651.0 1739.0 1793.0 1774.0 1760.0 1748.0 1762.0 123 | 0 1137.0 1223.0 1186.0 1053.0 857.0 733.0 656.0 642.0 644.0 652.0 665.0 684.0 700.0 732.0 772.0 798.0 849.0 902.0 953.0 978.0 1006.0 1040.0 1082.0 1107.0 1108.0 1125.0 1136.0 1153.0 1175.0 1201.0 1225.0 1249.0 1280.0 1317.0 1366.0 1437.0 1503.0 1584.0 1685.0 1770.0 1853.0 1903.0 1956.0 2039.0 2090.0 2115.0 2140.0 2167.0 2194.0 124 | 0 1137.0 1231.0 1222.0 1125.0 920.0 767.0 693.0 660.0 651.0 656.0 669.0 687.0 713.0 738.0 779.0 812.0 851.0 910.0 944.0 984.0 1009.0 1035.0 1082.0 1098.0 1100.0 1103.0 1116.0 1135.0 1155.0 1168.0 1190.0 1229.0 1262.0 1299.0 1363.0 1425.0 1492.0 1552.0 1640.0 1716.0 1795.0 1847.0 1898.0 1977.0 2016.0 2035.0 2048.0 2074.0 2105.0 125 | 0 1137.0 1223.0 1206.0 1055.0 888.0 754.0 681.0 655.0 648.0 654.0 670.0 692.0 717.0 749.0 788.0 817.0 850.0 903.0 941.0 981.0 1004.0 1018.0 975.0 866.0 802.0 789.0 792.0 800.0 806.0 818.0 832.0 850.0 879.0 903.0 939.0 982.0 1025.0 1072.0 1138.0 1199.0 1241.0 1176.0 1078.0 1024.0 1014.0 1000.0 1002.0 1015.0 1032.0 126 | 0 1137.0 1219.0 1204.0 1082.0 908.0 758.0 699.0 670.0 660.0 668.0 681.0 694.0 720.0 745.0 772.0 812.0 858.0 906.0 967.0 993.0 1022.0 1041.0 1099.0 1124.0 1135.0 1151.0 1171.0 1186.0 1215.0 1241.0 1276.0 1294.0 1324.0 1365.0 1407.0 1471.0 1535.0 1616.0 1720.0 1818.0 1886.0 1937.0 1982.0 2066.0 2123.0 2158.0 2182.0 2212.0 2256.0 127 | 0 1137.0 1224.0 1205.0 1046.0 864.0 730.0 673.0 651.0 645.0 651.0 674.0 686.0 708.0 739.0 776.0 809.0 854.0 900.0 954.0 984.0 1012.0 1036.0 1088.0 1112.0 1115.0 1119.0 1142.0 1154.0 1180.0 1203.0 1237.0 1272.0 1310.0 1355.0 1402.0 1459.0 1525.0 1589.0 1677.0 1782.0 1858.0 1901.0 1956.0 2053.0 2106.0 2132.0 2140.0 2167.0 2200.0 128 | 0 1137.0 1218.0 1201.0 1076.0 902.0 757.0 691.0 660.0 652.0 655.0 669.0 690.0 708.0 743.0 779.0 803.0 847.0 905.0 946.0 983.0 1012.0 1041.0 1080.0 1102.0 1117.0 1131.0 1143.0 1166.0 1182.0 1205.0 1228.0 1267.0 1303.0 1344.0 1399.0 1452.0 1528.0 1588.0 1701.0 1781.0 1854.0 1911.0 1970.0 2044.0 2108.0 2133.0 2162.0 2182.0 2224.0 129 | 0 1137.0 1224.0 1200.0 1094.0 910.0 758.0 696.0 650.0 644.0 653.0 664.0 690.0 710.0 733.0 771.0 805.0 838.0 890.0 938.0 961.0 987.0 1018.0 1065.0 1095.0 1101.0 1106.0 1113.0 1127.0 1157.0 1179.0 1195.0 1229.0 1262.0 1304.0 1355.0 1406.0 1466.0 1532.0 1618.0 1715.0 1785.0 1831.0 1890.0 1966.0 2018.0 2047.0 2061.0 2087.0 2122.0 130 | -------------------------------------------------------------------------------- /C_files/edsc/DataSetInformation.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const int DIMENSION = 144; 4 | const int ROWTRAINING = 288; 5 | const int ROWTESTING = 72; 6 | const char* trainingFileName="C_files/edsc/Data/train"; 7 | const char* testingFileName="C_files/edsc/Data/test"; 8 | const char* resultFileName="C_files/edsc/Data/result.txt"; 9 | const char* path ="C_files/edsc"; 10 | const int NofClasses = 2; 11 | const int Classes[] = {1,0}; 12 | const int ClassIndexes[] = {0,144}; 13 | const int ClassNumber[] = {144,144}; 14 | -------------------------------------------------------------------------------- /C_files/edsc/Euclidean.cpp: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "Euclidean.h" 3 | 4 | 5 | 6 | double Euclidean(double * a, double * b, int length) 7 | { 8 | double ret = 0; 9 | for (int i=0; i 0 ? sqrt(ret) : 0; 15 | //return ret > 0 ? ret : 0; 16 | } 17 | -------------------------------------------------------------------------------- /C_files/edsc/Euclidean.h: -------------------------------------------------------------------------------- 1 | double Euclidean(double * a, double * b, int length); -------------------------------------------------------------------------------- /C_files/edsc/quickSort.cpp: -------------------------------------------------------------------------------- 1 | void quicksort( double a[], int start, int end) 2 | { 3 | // the base case 4 | 5 | if (start>=end) 6 | return; 7 | double pivot=a[end]; // use the last element as the pivot; 8 | 9 | int storedIndex=start; // the first element of S2 10 | for (int i=start;i= 1.8 is required to run the algorithms that are implemented using java. 28 | 29 | ## Installation 30 | 1. Install the `virtualenv` package: 31 | 32 | ```bash 33 | pip3 install virtualenv 34 | ``` 35 | 36 | 2. Create a new virtual environment: 37 | 38 | ```bash 39 | virtualenv venv 40 | ``` 41 | 42 | 3. Activate virtual environment: 43 | 44 | ``` 45 | . venv/bin/activate 46 | ``` 47 | 48 | 4. Install required packages: 49 | 50 | ```bash 51 | pip3 install -r requirements.txt 52 | ``` 53 | 54 | 5. Locally install `timeline`: 55 | 56 | ```bash 57 | pip install --editable . 58 | ``` 59 | 60 | ## Downloading the data 61 | 62 | For downloading the data run the script `download_data.sh` found in the script folder. The downloaded data can be found inside folder `data`. 63 | 10 datasets are available, derived from the [UCR_UEA library](https://www.timeseriesclassification.com/). Multivariate datasets from the Biological and Maritime field are also provided. 64 | 65 | ## Experimental Setup 66 | 67 | Note that only ECTS was implemented by us, using the paper of the algorithm as a guide. The rest of the algorithms derive from sources we provide in the following table. All credit goes to the original creators of the algorithms papers. 68 | 69 | | Algorithm | Parameters | 70 | |---|---| 71 | | ECTS [\[paper\]](https://link.springer.com/article/10.1007/s10115-011-0400-x) | support = 0 | 72 | | EDSC [\[paper\]](https://epubs.siam.org/doi/10.1137/1.9781611972818.22) [\[code\]](https://drive.google.com/file/d/0BxY8OirJ0-gdbnBYNnRNbW9xeTQ/view) | CHE k=3, min_length=5, max_length=len(time_series)/2 | 73 | | TEASER [\[paper\]](https://link.springer.com/article/10.1007/s10618-020-00690-z) [\[code\]](https://github.com/patrickzib/SFA) | S=20 (for the UCR_UEA), S=10 (for the biological and maritime) | 74 | | ECEC [\[paper\]](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8765556) [\[code\]](https://github.com/junweilvhfut/ECEC)| training_times=20, length = len(time_series)/20,a=0.8 | 75 | | MLSTM [\[paper\]](https://www.sciencedirect.com/science/article/abs/pii/S0893608019301200?via%3Dihub) [\[code\]](https://github.com/titu1994/MLSTM-FCN) | LSTM cells = [8, 64, 128], tested_lengths = [0.4,0.5,0.6] % | 76 | | ECONOMY-K [\[paper\]](https://link.springer.com/chapter/10.1007/978-3-319-23528-8_27) [\[code\]](https://tslearn.readthedocs.io/en/stable/user_guide/early.html) | k = [1, 2, 3], λ = 100, cost = 0.001 | 77 | ## Menu Guide 78 | 79 | After running the Virtual Enviroment commands stated above, by running `ets` a menu with all programming options appears. 80 | A running command is constructed as follows: 81 | 82 | `ets ` 83 | 84 | If you want to see the algorithm's menu run: 85 | 86 | `ets --help` 87 | 88 | ### Quick commands rundown used for the experiments 89 | 90 | `-i ` : Only one file is given for cross validation with a given number of folds. 91 | 92 | `-t ` : The training file used. A `-e` command is also required. 93 | 94 | `-e ` : The testing file used. A `-t` command is also required. 95 | 96 | `-o ` : The desired output stream file. Default output steam is the console. 97 | 98 | `-s `: The seperator of each collumn in the file/s. 99 | 100 | `-d` & `-h`: Commands that indicate the collumn of the classes in the input file/s. It can be either the `` of the collumn for `-d` or the `` for `-h`. 101 | 102 | `-v `: In case of multivariate input, describes the number of variables and should always be followed by `-g`. All Multivariate input files, each time-series, should take up `-v` consequent lines for each univariate time-series variable, bearing the same labels 103 | 104 | `-g `: The methods used to deal with multivariate time-series. We used `vote` which conducts the voting as explained in the paper and `normal` which passes the whole multivariate input in the algorithm, currently possible only by MLSTM. Also MLSTM requires `-g normal` for univariate time-series as well. 105 | 106 | `--java` & `--cplus`: Command that is required for non-python implementations. `--java ` for Teaser and ECEC,`--cplus` for EDSC. 107 | 108 | `-c `: The class for which the F1-score will be calculated. If -1 is passed then the F1-score of all classes is calculated (not supported for multivariate time-series yet). 109 | 110 | `--make-cv`: Takes the training and testing file, merges them and conducts cross validation. 111 | 112 | `--folds` : Used when there are premade folds available. 113 | 114 | ### Test Run for UCR_UEA 115 | 116 | `ects` : `ets -t "training file name" -e "testing file name" --make-cv -h Class -c -1 -g vote ects -u 0.0` 117 | 118 | `edsc` : `ets -t "training file name" -e "testing file name" --make-cv -h Class -c -1 --cplus -g vote edsccplus` 119 | 120 | `ecec` : `ets -t "training file name" -e "testing file name" --make-cv -h Class -c -1 --java -g vote ecec` 121 | 122 | `teaser` : `ets t "training file name" -e "testing file name" --make-cv -h Class -c -1 --java -g vote teaser -s 20` 123 | 124 | `mlstm` : `ets t "training file name" -e "testing file name" --make-cv -h Class -c -1 -g normal mlstm` 125 | 126 | `eco-k` : `ets t "training file name" -e "testing file name" --make-cv -h Class -c -1 -g vote economy-k` 127 | 128 | 129 | ### Test Run for Maritime and Biological 130 | 131 | `ects` : `ets -i "file location" -g vote -v (3 for Biological or 5 Maritime) -d 0 -c -1 ects -u 0.0` 132 | 133 | `edsc` : `ets -i "file location" -g vote -v (3 for Biological or 5 Maritime) -d 0 -c -1 --cplus edsccplus` 134 | 135 | `ecec` : `ets -i "file location" -g vote -v (3 for Biological or 5 Maritime) -d 0 -c -1 --java ecec` 136 | 137 | `teaser` : `ets -i "file location" -g vote -v (3 for Biological or 5 Maritime) -d 0 -c -1 --java teaser -s 10` 138 | 139 | `mlstm` : `ets -i "file location" -v (3 for Biological or 5 Maritime) -d 0 -c -1 -g normal mlstm` 140 | 141 | `eco-k` : `ets -i "file location"" -g vote -v (3 for Biological or 5 Maritime) -d 0 -c -1 economy-k` 142 | 143 | ### Disclaimer 144 | 145 | Any false product and misuse of the used algorithms is on the authors of the paper. Please inform us if you detect any misconduct or misuse of the code/datasets used in this repository. 146 | -------------------------------------------------------------------------------- /ets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/__init__.py -------------------------------------------------------------------------------- /ets/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /ets/__pycache__/cli.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/__pycache__/cli.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/.gitignore: -------------------------------------------------------------------------------- 1 | data/*.mat 2 | data/*/*.mat 3 | data/*/*.npy 4 | data/*/*.train 5 | data/*/*.test 6 | data/*/*.xlsx 7 | data/CCVdataset/*.txt 8 | !data/note.txt 9 | !data/model_dt.csv 10 | weights/*.h5 11 | weights/*/*.h5 12 | .idea/ 13 | utils/*.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/__init__.py -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/__pycache__/mlstm_impl.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/__pycache__/mlstm_impl.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/mlstm_impl.py: -------------------------------------------------------------------------------- 1 | import time 2 | from keras import backend as K 3 | from keras.models import Model 4 | from keras.layers import Input, Dense, LSTM, multiply, concatenate, Activation, Masking, Reshape 5 | from keras.layers import Conv1D, BatchNormalization, GlobalAveragePooling1D, Permute, Dropout 6 | 7 | from ets.algorithms.MLSTM.utils.generic_utils import load_dataset_at 8 | from ets.algorithms.MLSTM.utils.keras_utils import train_model, evaluate_model, set_trainable, loss_model 9 | from ets.algorithms.MLSTM.utils.layer_utils import AttentionLSTM 10 | import os 11 | 12 | DATASET_INDEX = 0 13 | 14 | TRAINABLE = True 15 | 16 | 17 | def generate_model(size, cell=8): 18 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 19 | lines = f.read() 20 | lines = lines.split("\n") 21 | MAX_NB_VARIABLES = 0 22 | NB_CLASSES_LIST = 0 23 | MAX_TIMESTEPS_LIST = 0 24 | for line in lines: 25 | if "VARIABLES" in line: 26 | line = line.split("=") 27 | MAX_NB_VARIABLES = int(line[1]) 28 | if "CLASSES" in line: 29 | line = line.split("=") 30 | NB_CLASSES_LIST = int(line[1]) 31 | if "TIMESTEPS" in line: 32 | line = line.split("=") 33 | MAX_TIMESTEPS_LIST = int(line[1]) 34 | f.close() 35 | MAX_NB_VARIABLES = MAX_NB_VARIABLES 36 | NB_CLASS = NB_CLASSES_LIST 37 | ip = Input(shape=(MAX_NB_VARIABLES, size)) 38 | 39 | x = Masking()(ip) 40 | print(cell) 41 | x = AttentionLSTM(cell)(x) 42 | x = Dropout(0.8)(x) 43 | 44 | y = Permute((2, 1))(ip) 45 | y = Conv1D(128, 8, padding='same', kernel_initializer='he_uniform')(y) 46 | y = BatchNormalization()(y) 47 | y = Activation('relu')(y) 48 | y = squeeze_excite_block(y) 49 | 50 | y = Conv1D(256, 5, padding='same', kernel_initializer='he_uniform')(y) 51 | y = BatchNormalization()(y) 52 | y = Activation('relu')(y) 53 | y = squeeze_excite_block(y) 54 | 55 | y = Conv1D(128, 3, padding='same', kernel_initializer='he_uniform')(y) 56 | y = BatchNormalization()(y) 57 | y = Activation('relu')(y) 58 | 59 | y = GlobalAveragePooling1D()(y) 60 | 61 | x = concatenate([x, y]) 62 | 63 | out = Dense(NB_CLASS, activation='softmax')(x) 64 | 65 | model = Model(ip, out) 66 | model.summary() 67 | 68 | # add load model code here to fine-tune 69 | 70 | return model 71 | 72 | 73 | def squeeze_excite_block(input): 74 | ''' Create a squeeze-excite block 75 | Args: 76 | input: input tensor 77 | filters: number of output filters 78 | k: width factor 79 | 80 | Returns: a keras tensor 81 | ''' 82 | filters = input._keras_shape[-1] # channel_axis = -1 for TF 83 | 84 | se = GlobalAveragePooling1D()(input) 85 | se = Reshape((1, filters))(se) 86 | se = Dense(filters // 16, activation='relu', kernel_initializer='he_normal', use_bias=False)(se) 87 | se = Dense(filters, activation='sigmoid', kernel_initializer='he_normal', use_bias=False)(se) 88 | se = multiply([input, se]) 89 | return se 90 | 91 | 92 | def run(earliness, finalcell=None): 93 | X_train, y_train, X_test, is_timeseries = load_dataset_at(DATASET_INDEX, 94 | fold_index=None, 95 | normalize_timeseries=False) 96 | start = time.time() 97 | # Number of cells 98 | CELLS = [8, 64, 128] 99 | base_log_name = '%s_%d_%s_cells_new_datasets.csv' 100 | base_weights_dir = 'ets/algorithms/MLSTM/weights/%s_%d_%s_cells_weights/' 101 | # Normalization scheme 102 | # Normalize = False means no normalization will be done 103 | # Normalize = True / 1 means sample wise z-normalization 104 | # Normalize = 2 means dataset normalization. 105 | normalize_dataset = False 106 | current_loss = 1e10 107 | if finalcell is None: 108 | for cell in CELLS: 109 | successes = [] 110 | failures = [] 111 | 112 | if not os.path.exists(base_log_name % ("alstm", cell, earliness)): 113 | file = open(base_log_name % ("alstm", cell, earliness), 'w') 114 | file.write('%s,%s,%s,%s\n' % ('dataset_id', 'dataset_name', 'dataset_name_', 'test_accuracy')) 115 | file.close() 116 | 117 | # release GPU Memory 118 | K.clear_session() 119 | 120 | weights_dir = base_weights_dir % ("alstm", cell, earliness) 121 | if not os.path.exists(weights_dir): 122 | os.makedirs(weights_dir) 123 | 124 | dataset_name_ = weights_dir + "current" 125 | 126 | model = generate_model(len(X_test[0][0]), cell) 127 | 128 | train_model(model, DATASET_INDEX, dataset_name_, epochs=600, batch_size=128, 129 | normalize_timeseries=normalize_dataset) 130 | 131 | model_loss = loss_model(model, DATASET_INDEX, dataset_name_, batch_size=128, normalize_timeseries=True) 132 | 133 | if model_loss < current_loss: 134 | finalcell = cell 135 | current_loss = model_loss 136 | 137 | model = generate_model(len(X_test[0][0]), finalcell) 138 | weights_dir = base_weights_dir % ("alstm", finalcell, earliness) 139 | dataset_name_ = weights_dir + "current" 140 | train = time.time() - start 141 | train_model(model, DATASET_INDEX, dataset_name_, epochs=600, batch_size=128, 142 | normalize_timeseries=normalize_dataset) 143 | res = evaluate_model(model, DATASET_INDEX, dataset_prefix=dataset_name_, batch_size=128, 144 | normalize_timeseries=normalize_dataset) 145 | test = time.time() - start - train 146 | return res, train, test, finalcell 147 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/requirements.txt: -------------------------------------------------------------------------------- 1 | tensorflow-gpu>=1.4.0 2 | keras>=2.1.2 3 | scipy 4 | numpy 5 | pandas 6 | scikit-learn>=0.18.2 7 | h5py 8 | matplotlib 9 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/__pycache__/generic_utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/utils/__pycache__/generic_utils.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/__pycache__/keras_utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/utils/__pycache__/keras_utils.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/__pycache__/layer_utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/MLSTM/utils/__pycache__/layer_utils.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/constants.txt: -------------------------------------------------------------------------------- 1 | TRAIN_FILES=./ets/algorithms/MLSTM/data/current_dataset/ 2 | TEST_FILES=./ets/algorithms/MLSTM/data/current_dataset/ 3 | MAX_NB_VARIABLES=5 4 | MAX_TIMESTEPS_LIST=30 5 | NB_CLASSES_LIST=2 6 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/embedding_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pickle 3 | import numpy as np 4 | np.random.seed(1000) 5 | 6 | from ets.algorithms.MLSTM.utils.generic_utils import load_dataset_at 7 | 8 | from keras.preprocessing.text import Tokenizer 9 | from keras.preprocessing.sequence import pad_sequences 10 | 11 | 12 | def load_embedding_matrix(embedding_path, word_index, max_nb_words, embedding_dim, print_error_words=True): 13 | if not os.path.exists('data/embedding_matrix max words %d embedding dim %d.npy' % (max_nb_words, embedding_dim)): 14 | embeddings_index = {} 15 | error_words = [] 16 | 17 | f = open(embedding_path, encoding='utf8') 18 | for line in f: 19 | values = line.split() 20 | word = values[0] 21 | try: 22 | coefs = np.asarray(values[1:], dtype='float32') 23 | embeddings_index[word] = coefs 24 | except Exception: 25 | error_words.append(word) 26 | 27 | f.close() 28 | 29 | if len(error_words) > 0: 30 | print("%d words were not added." % (len(error_words))) 31 | if print_error_words: 32 | print("Words are : \n", error_words) 33 | 34 | print('Preparing embedding matrix.') 35 | 36 | # prepare embedding matrix 37 | nb_words = min(max_nb_words, len(word_index)) 38 | embedding_matrix = np.zeros((nb_words, embedding_dim)) 39 | for word, i in word_index.items(): 40 | if i >= nb_words: 41 | continue 42 | embedding_vector = embeddings_index.get(word) 43 | if embedding_vector is not None: 44 | # words not found in embedding index will be all-zeros. 45 | embedding_matrix[i] = embedding_vector 46 | 47 | np.save('data/embedding_matrix max words %d embedding dim %d.npy' % (max_nb_words, 48 | embedding_dim), 49 | embedding_matrix) 50 | 51 | print('Saved embedding matrix') 52 | 53 | else: 54 | embedding_matrix = np.load('data/embedding_matrix max words %d embedding dim %d.npy' % (max_nb_words, 55 | embedding_dim)) 56 | 57 | print('Loaded embedding matrix') 58 | 59 | return embedding_matrix 60 | 61 | 62 | def create_ngram_set(input_list, ngram_value=2): 63 | return set(zip(*[input_list[i:] for i in range(ngram_value)])) 64 | 65 | 66 | def add_ngram(sequences, token_indice, ngram_range=2): 67 | new_sequences = [] 68 | for input_list in sequences: 69 | new_list = input_list[:] 70 | for i in range(len(new_list) - ngram_range + 1): 71 | for ngram_value in range(2, ngram_range + 1): 72 | ngram = tuple(new_list[i:i + ngram_value]) 73 | if ngram in token_indice: 74 | new_list.append(token_indice[ngram]) 75 | new_sequences.append(new_list) 76 | 77 | return new_sequences 78 | 79 | 80 | def prepare_tokenized_data(texts, max_nb_words, max_sequence_length, ngram_range=1): 81 | if not os.path.exists('data/tokenizer.pkl'): 82 | tokenizer = Tokenizer(nb_words=max_nb_words) 83 | tokenizer.fit_on_texts(texts) 84 | 85 | with open('data/tokenizer.pkl', 'wb') as f: 86 | pickle.dump(tokenizer, f) 87 | 88 | print('Saved tokenizer.pkl') 89 | else: 90 | with open('data/tokenizer.pkl', 'rb') as f: 91 | tokenizer = pickle.load(f) 92 | print('Loaded tokenizer.pkl') 93 | 94 | sequences = tokenizer.texts_to_sequences(texts) 95 | word_index = tokenizer.word_index 96 | print('Found %s unique 1-gram tokens.' % len(word_index)) 97 | 98 | ngram_set = set() 99 | for input_list in sequences: 100 | for i in range(2, ngram_range + 1): 101 | set_of_ngram = create_ngram_set(input_list, ngram_value=i) 102 | ngram_set.update(set_of_ngram) 103 | 104 | # Dictionary mapping n-gram token to a unique integer. 105 | # Integer values are greater than max_features in order 106 | # to avoid collision with existing features. 107 | start_index = max_nb_words + 1 108 | token_indice = {v: k + start_index for k, v in enumerate(ngram_set)} 109 | indice_token = {token_indice[k]: k for k in token_indice} 110 | word_index.update(token_indice) 111 | 112 | max_features = np.max(list(indice_token.keys())) + 1 113 | print('Now there are:', max_features, 'features') 114 | 115 | # Augmenting X_train and X_test_mat with n-grams features 116 | sequences = add_ngram(sequences, token_indice, ngram_range) 117 | print('Average sequence length: {}'.format(np.mean(list(map(len, sequences)), dtype=int))) 118 | print('Max sequence length: {}'.format(np.max(list(map(len, sequences))))) 119 | 120 | data = pad_sequences(sequences, maxlen=max_sequence_length) 121 | 122 | 123 | return (data, word_index) 124 | 125 | 126 | # def __load_embeddings(dataset_prefix, verbose=False): 127 | # 128 | # embedding_path = npy_path # change to numpy data format (which contains the preloaded embedding matrix) 129 | # if os.path.exists(embedding_path): 130 | # # embedding matrix exists, no need to create again. 131 | # print("Loading embedding matrix for dataset \'%s\'" % (dataset_prefix)) 132 | # embedding_matrix = np.load(embedding_path) 133 | # return embedding_matrix 134 | # 135 | # with open(txt_path, 'r', encoding='utf8') as f: 136 | # header = f.readline() 137 | # splits = header.split(' ') 138 | # 139 | # vocab_size = int(splits[0]) 140 | # embedding_size = int(splits[1]) 141 | # 142 | # embeddings_index = {} 143 | # error_words = [] 144 | # 145 | # for line in f: 146 | # values = line.split() 147 | # word = values[0] 148 | # try: 149 | # coefs = np.asarray(values[1:], dtype='float32') 150 | # embeddings_index[word] = coefs 151 | # except Exception: 152 | # error_words.append(word) 153 | # 154 | # if len(error_words) > 0: 155 | # print("%d words were not added." % (len(error_words))) 156 | # if verbose: 157 | # print("Words are : \n", error_words) 158 | # 159 | # if verbose: print('Preparing embedding matrix.') 160 | # 161 | # embedding_matrix = np.zeros((vocab_size, embedding_size)) 162 | # 163 | # for key, vector in embeddings_index.items(): 164 | # if vector is not None: 165 | # # words not found in embedding index will be all-zeros. 166 | # key = int(key) 167 | # embedding_matrix[key] = vector 168 | # 169 | # if verbose: print('Saving embedding matrix for dataset \'%s\'' % (dataset_prefix)) 170 | # 171 | # np.save(embedding_path, embedding_matrix) 172 | # return embedding_matrix 173 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/generic_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import os 4 | import matplotlib as mpl 5 | import matplotlib.pylab as plt 6 | 7 | mpl.style.use('seaborn-paper') 8 | 9 | 10 | def load_dataset_at(index, fold_index=None, normalize_timeseries=False, verbose=True) -> (np.array, np.array): 11 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 12 | lines = f.read() 13 | lines = lines.split("\n") 14 | train = None 15 | test = None 16 | for line in lines: 17 | print(line) 18 | if "TRAIN" in line: 19 | line = line.split("=") 20 | train = line[1] 21 | if "TEST" in line: 22 | line = line.split("=") 23 | test = line[1] 24 | f.close() 25 | if verbose: print("Loading train / test dataset : ", train, test) 26 | if fold_index is None: 27 | x_train_path = train + "X_train.npy" 28 | y_train_path = train+ "y_train.npy" 29 | x_test_path = test + "X_test.npy" 30 | else: 31 | x_train_path = train + "X_train_%d.npy" % fold_index 32 | y_train_path = train + "y_train_%d.npy" % fold_index 33 | x_test_path = test + "X_test_%d.npy" % fold_index 34 | import os 35 | 36 | path = os.getcwd() 37 | 38 | print(os.path.isdir("./ets/algorithms/MLSTM/data/current_dataset"),x_train_path) 39 | if os.path.exists(x_train_path): 40 | 41 | X_train = np.load(x_train_path) 42 | y_train = np.load(y_train_path) 43 | X_test = np.load(x_test_path) 44 | elif os.path.exists(x_train_path[1:]): 45 | X_train = np.load(x_train_path[1:]) 46 | y_train = np.load(y_train_path[1:]) 47 | X_test = np.load(x_test_path[1:]) 48 | else: 49 | raise FileNotFoundError('File %s not found!' % (train)) 50 | 51 | is_timeseries = True 52 | 53 | # extract labels Y and normalize to [0 - (MAX - 1)] range 54 | nb_classes = len(np.unique(y_train)) 55 | y_train = (y_train - y_train.min()) / (y_train.max() - y_train.min()) * (nb_classes - 1) 56 | 57 | if is_timeseries: 58 | # scale the values 59 | if normalize_timeseries: 60 | X_train_mean = X_train.mean() 61 | X_train_std = X_train.std() 62 | X_train = (X_train - X_train_mean) / (X_train_std + 1e-8) 63 | 64 | if verbose: print("Finished processing train dataset..") 65 | 66 | 67 | if is_timeseries: 68 | # scale the values 69 | if normalize_timeseries: 70 | X_test = (X_test - X_train_mean) / (X_train_std + 1e-8) 71 | 72 | if verbose: 73 | print("Finished loading test dataset..") 74 | print() 75 | print("Number of train samples : ", X_train.shape[0], "Number of test samples : ", X_test.shape[0]) 76 | print("Number of classes : ", nb_classes) 77 | print("Sequence length : ", X_train.shape[-1]) 78 | 79 | return X_train, y_train, X_test, is_timeseries 80 | 81 | 82 | def calculate_dataset_metrics(X_train): 83 | max_nb_variables = X_train.shape[1] 84 | max_timesteps = X_train.shape[-1] 85 | 86 | return max_timesteps, max_nb_variables 87 | 88 | 89 | def cutoff_choice(dataset_id, sequence_length): 90 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 91 | lines = f.readlines() 92 | MAX_NB_VARIABLES = 0 93 | for line in lines: 94 | if "VARIABLES" in line: 95 | line = line.split("=") 96 | MAX_NB_VARIABLES = int(line[1]) 97 | f.close() 98 | print("Original sequence length was :", sequence_length, "New sequence Length will be : ", 99 | MAX_NB_VARIABLES) 100 | choice = input('Options : \n' 101 | '`pre` - cut the sequence from the beginning\n' 102 | '`post`- cut the sequence from the end\n' 103 | '`anything else` - stop execution\n' 104 | 'To automate choice: add flag `cutoff` = choice as above\n' 105 | 'Choice = ') 106 | 107 | choice = str(choice).lower() 108 | return choice 109 | 110 | 111 | def cutoff_sequence(X_train, X_test, choice, dataset_id, sequence_length): 112 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 113 | lines = f.readlines() 114 | MAX_NB_VARIABLES = 0 115 | for line in lines: 116 | if "VARIABLES" in line: 117 | line = line.split("=") 118 | MAX_NB_VARIABLES = int(line[1]) 119 | f.close() 120 | assert MAX_NB_VARIABLES< sequence_length, "If sequence is to be cut, max sequence" \ 121 | "length must be less than original sequence length." 122 | cutoff = sequence_length - MAX_NB_VARIABLES[dataset_id] 123 | if choice == 'pre': 124 | if X_train is not None: 125 | X_train = X_train[:, :, cutoff:] 126 | if X_test is not None: 127 | X_test = X_test[:, :, cutoff:] 128 | else: 129 | if X_train is not None: 130 | X_train = X_train[:, :, :-cutoff] 131 | if X_test is not None: 132 | X_test = X_test[:, :, :-cutoff] 133 | print("New sequence length :", MAX_NB_VARIABLES[dataset_id]) 134 | return X_train, X_test 135 | 136 | 137 | if __name__ == "__main__": 138 | pass -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/keras_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import pandas as pd 4 | import matplotlib as mpl 5 | import matplotlib.pyplot as plt 6 | 7 | mpl.style.use('seaborn-paper') 8 | 9 | from sklearn.preprocessing import LabelEncoder 10 | 11 | import warnings 12 | 13 | warnings.simplefilter('ignore', category=DeprecationWarning) 14 | 15 | from keras.models import Model 16 | from keras.layers import Permute 17 | from keras.optimizers import Adam 18 | from keras.utils import to_categorical 19 | from keras.preprocessing.sequence import pad_sequences 20 | from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau 21 | from keras import backend as K 22 | 23 | from ets.algorithms.MLSTM.utils.generic_utils import load_dataset_at, calculate_dataset_metrics, cutoff_choice, \ 24 | cutoff_sequence 25 | 26 | 27 | def multi_label_log_loss(y_pred, y_true): 28 | return K.sum(K.binary_crossentropy(y_pred, y_true), axis=-1) 29 | 30 | 31 | def loss_model(model: Model, dataset_id, dataset_prefix, batch_size=128, train_data_subset=None, 32 | cutoff=None, normalize_timeseries=False): 33 | X_train, y_train, _, is_timeseries = load_dataset_at(dataset_id, 34 | normalize_timeseries=normalize_timeseries) 35 | 36 | y_train = to_categorical(y_train, len(np.unique(y_train))) 37 | 38 | optm = Adam(lr=1e-3) 39 | model.compile(optimizer=optm, loss='categorical_crossentropy', metrics=['accuracy']) 40 | 41 | model.load_weights("%s_weights.h5" % dataset_prefix) 42 | # print("Weights loaded from ", "./weights/%s_weights.h5" % dataset_prefix) 43 | 44 | if train_data_subset is not None: 45 | X_train = X_train[:train_data_subset] 46 | y_train = y_train[:train_data_subset] 47 | 48 | # print("\nEvaluating : ") 49 | loss, accuracy = model.evaluate(X_train, y_train, batch_size=batch_size) 50 | # print() 51 | # print("Final Loss : ", loss) 52 | 53 | return loss 54 | 55 | 56 | def _average_gradient_norm(model, X_train, y_train, batch_size): 57 | # just checking if the model was already compiled 58 | if not hasattr(model, "train_function"): 59 | raise RuntimeError("You must compile your model before using it.") 60 | 61 | weights = model.trainable_weights # weight tensors 62 | 63 | get_gradients = model.optimizer.get_gradients(model.total_loss, weights) # gradient tensors 64 | 65 | input_tensors = [ 66 | # input data 67 | model.inputs[0], 68 | # how much to weight each sample by 69 | model.sample_weights[0], 70 | # labels 71 | model.targets[0], 72 | # train or test mode 73 | K.learning_phase() 74 | ] 75 | 76 | grad_fct = K.function(inputs=input_tensors, outputs=get_gradients) 77 | 78 | steps = 0 79 | total_norm = 0 80 | s_w = None 81 | 82 | nb_steps = X_train.shape[0] // batch_size 83 | 84 | if X_train.shape[0] % batch_size == 0: 85 | pad_last = False 86 | else: 87 | pad_last = True 88 | 89 | def generator(X_train, y_train, pad_last): 90 | for i in range(nb_steps): 91 | X = X_train[i * batch_size: (i + 1) * batch_size, ...] 92 | y = y_train[i * batch_size: (i + 1) * batch_size, ...] 93 | 94 | yield (X, y) 95 | 96 | if pad_last: 97 | X = X_train[nb_steps * batch_size:, ...] 98 | y = y_train[nb_steps * batch_size:, ...] 99 | 100 | yield (X, y) 101 | 102 | datagen = generator(X_train, y_train, pad_last) 103 | 104 | while steps < nb_steps: 105 | X, y = next(datagen) 106 | # set sample weights to one 107 | # for every input 108 | if s_w is None: 109 | s_w = np.ones(X.shape[0]) 110 | 111 | gradients = grad_fct([X, s_w, y, 0]) 112 | total_norm += np.sqrt(np.sum([np.sum(np.square(g)) for g in gradients])) 113 | steps += 1 114 | 115 | if pad_last: 116 | X, y = next(datagen) 117 | # set sample weights to one 118 | # for every input 119 | if s_w is None: 120 | s_w = np.ones(X.shape[0]) 121 | 122 | gradients = grad_fct([X, s_w, y, 0]) 123 | total_norm += np.sqrt(np.sum([np.sum(np.square(g)) for g in gradients])) 124 | steps += 1 125 | 126 | return total_norm / float(steps) 127 | 128 | 129 | def train_model(model: Model, dataset_id, dataset_prefix, dataset_fold_id=None, epochs=50, batch_size=128, 130 | val_subset=None, 131 | cutoff=None, normalize_timeseries=False, learning_rate=1e-3, monitor='loss', optimization_mode='auto', 132 | compile_model=True): 133 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 134 | lines = f.readlines() 135 | MAX_NB_VARIABLES = 0 136 | for line in lines: 137 | if "VARIABLES" in line: 138 | line = line.split("=") 139 | MAX_NB_VARIABLES = int(line[1]) 140 | f.close() 141 | X_train, y_train, X_test, is_timeseries = load_dataset_at(dataset_id, 142 | fold_index=dataset_fold_id, 143 | normalize_timeseries=normalize_timeseries) 144 | max_timesteps, max_nb_variables = calculate_dataset_metrics(X_train) 145 | 146 | if max_nb_variables != MAX_NB_VARIABLES: 147 | if cutoff is None: 148 | choice = cutoff_choice(dataset_id, max_nb_variables) 149 | else: 150 | assert cutoff in ['pre', 'post'], 'Cutoff parameter value must be either "pre" or "post"' 151 | choice = cutoff 152 | 153 | if choice not in ['pre', 'post']: 154 | return 155 | else: 156 | X_train, X_test = cutoff_sequence(X_train, X_test, choice, dataset_id, max_nb_variables) 157 | 158 | classes = np.unique(y_train) 159 | le = LabelEncoder() 160 | y_ind = le.fit_transform(y_train.ravel()) 161 | recip_freq = len(y_train) / (len(le.classes_) * 162 | np.bincount(y_ind).astype(np.float64)) 163 | class_weight = recip_freq[le.transform(classes)] 164 | 165 | # print("Class weights : ", class_weight) 166 | 167 | y_train = to_categorical(y_train, len(np.unique(y_train))) 168 | if is_timeseries: 169 | factor = 1. / np.cbrt(2) 170 | else: 171 | factor = 1. / np.sqrt(2) 172 | 173 | if dataset_fold_id is None: 174 | weight_fn = "%s_weights.h5" % dataset_prefix 175 | else: 176 | weight_fn = "%s_fold_%d_weights.h5" % (dataset_prefix, dataset_fold_id) 177 | 178 | model_checkpoint = ModelCheckpoint(weight_fn, verbose=1, mode=optimization_mode, 179 | monitor=monitor, save_best_only=True, save_weights_only=True) 180 | reduce_lr = ReduceLROnPlateau(monitor=monitor, patience=100, mode=optimization_mode, 181 | factor=factor, cooldown=0, min_lr=1e-4, verbose=2) 182 | callback_list = [model_checkpoint, reduce_lr] 183 | 184 | optm = Adam(lr=learning_rate) 185 | 186 | if compile_model: 187 | model.compile(optimizer=optm, loss='categorical_crossentropy', metrics=['accuracy']) 188 | 189 | model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, callbacks=callback_list, 190 | class_weight=class_weight, verbose=0) 191 | 192 | 193 | def evaluate_model(model: Model, dataset_id, dataset_prefix, dataset_fold_id=None, batch_size=128, 194 | test_data_subset=None, 195 | cutoff=None, normalize_timeseries=False): 196 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 197 | lines = f.readlines() 198 | MAX_NB_VARIABLES = 0 199 | for line in lines: 200 | if "VARIABLES" in line: 201 | line = line.split("=") 202 | MAX_NB_VARIABLES = int(line[1]) 203 | f.close() 204 | _, _, X_test, is_timeseries = load_dataset_at(dataset_id, 205 | fold_index=dataset_fold_id, 206 | normalize_timeseries=normalize_timeseries) 207 | max_timesteps, max_nb_variables = calculate_dataset_metrics(X_test) 208 | 209 | if max_nb_variables != MAX_NB_VARIABLES: 210 | if cutoff is None: 211 | choice = cutoff_choice(dataset_id, max_nb_variables) 212 | else: 213 | assert cutoff in ['pre', 'post'], 'Cutoff parameter value must be either "pre" or "post"' 214 | choice = cutoff 215 | 216 | if choice not in ['pre', 'post']: 217 | return 218 | else: 219 | _, X_test = cutoff_sequence(None, X_test, choice, dataset_id, max_nb_variables) 220 | 221 | if not is_timeseries: 222 | X_test = pad_sequences(X_test, maxlen=MAX_NB_VARIABLES[dataset_id], padding='post', truncating='post') 223 | optm = Adam(lr=1e-3) 224 | model.compile(optimizer=optm, loss='categorical_crossentropy', metrics=['accuracy']) 225 | 226 | if dataset_fold_id is None: 227 | weight_fn = "%s_weights.h5" % dataset_prefix 228 | else: 229 | weight_fn = "./ets/algorithms/MLSTM/weights/%s_fold_%d_weights.h5" % (dataset_prefix, dataset_fold_id) 230 | model.load_weights(weight_fn) 231 | 232 | if test_data_subset is not None: 233 | X_test = X_test[:test_data_subset] 234 | 235 | pre = model.predict(X_test, batch_size=batch_size) 236 | classes = pre.argmax(axis=-1) 237 | 238 | result = [] 239 | for item in classes: 240 | result.append((len(X_test[0][0]), item)) 241 | 242 | return result 243 | 244 | 245 | def set_trainable(layer, value): 246 | layer.trainable = value 247 | 248 | # case: container 249 | if hasattr(layer, 'layers'): 250 | for l in layer.layers: 251 | set_trainable(l, value) 252 | 253 | # case: wrapper (which is a case not covered by the PR) 254 | if hasattr(layer, 'layer'): 255 | set_trainable(layer.layer, value) 256 | 257 | 258 | def compute_average_gradient_norm(model: Model, dataset_id, dataset_fold_id=None, batch_size=128, 259 | cutoff=None, normalize_timeseries=False, learning_rate=1e-3): 260 | f = open("./ets/algorithms/MLSTM/utils/constants.txt", "r") 261 | lines = f.readlines() 262 | MAX_NB_VARIABLES = 0 263 | for line in lines: 264 | if "VARIABLES" in line: 265 | line = line.split("=") 266 | MAX_NB_VARIABLES = int(line[1]) 267 | f.close() 268 | X_train, y_train, X_test, is_timeseries = load_dataset_at(dataset_id, 269 | fold_index=dataset_fold_id, 270 | normalize_timeseries=normalize_timeseries) 271 | max_timesteps, sequence_length = calculate_dataset_metrics(X_train) 272 | 273 | if sequence_length != MAX_NB_VARIABLES: 274 | if cutoff is None: 275 | choice = cutoff_choice(dataset_id, sequence_length) 276 | else: 277 | assert cutoff in ['pre', 'post'], 'Cutoff parameter value must be either "pre" or "post"' 278 | choice = cutoff 279 | 280 | if choice not in ['pre', 'post']: 281 | return 282 | else: 283 | X_train, X_test = cutoff_sequence(X_train, X_test, choice, dataset_id, sequence_length) 284 | 285 | y_train = to_categorical(y_train, len(np.unique(y_train))) 286 | 287 | optm = Adam(lr=learning_rate) 288 | model.compile(optimizer=optm, loss='categorical_crossentropy', metrics=['accuracy']) 289 | 290 | average_gradient = _average_gradient_norm(model, X_train, y_train, batch_size) 291 | # print("Average gradient norm : ", average_gradient) 292 | 293 | 294 | class MaskablePermute(Permute): 295 | 296 | def __init__(self, dims, **kwargs): 297 | super(MaskablePermute, self).__init__(dims, **kwargs) 298 | self.supports_masking = True 299 | 300 | 301 | def f1_score(y_true, y_pred): 302 | def recall(y_true, y_pred): 303 | """Recall metric. 304 | 305 | Only computes a batch-wise average of recall. 306 | 307 | Computes the recall, a metric for multi-label classification of 308 | how many relevant items are selected. 309 | """ 310 | true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) 311 | possible_positives = K.sum(K.round(K.clip(y_true, 0, 1))) 312 | recall = true_positives / (possible_positives + K.epsilon()) 313 | return recall 314 | 315 | def precision(y_true, y_pred): 316 | """Precision metric. 317 | 318 | Only computes a batch-wise average of precision. 319 | 320 | Computes the precision, a metric for multi-label classification of 321 | how many selected items are relevant. 322 | """ 323 | true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) 324 | predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1))) 325 | precision = true_positives / (predicted_positives + K.epsilon()) 326 | return precision 327 | 328 | precision = precision(y_true, y_pred) 329 | recall = recall(y_true, y_pred) 330 | 331 | return 2 * ((precision * recall) / (precision + recall)) 332 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/layer_utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import numpy as np 3 | 4 | from keras import backend as K 5 | from keras import activations 6 | from keras import initializers 7 | from keras import regularizers 8 | from keras import constraints 9 | from keras.engine import Layer 10 | from keras.engine import InputSpec 11 | from keras.legacy import interfaces 12 | from keras.layers import Recurrent 13 | 14 | 15 | def _time_distributed_dense(x, w, b=None, dropout=None, 16 | input_dim=None, output_dim=None, 17 | timesteps=None, training=None): 18 | """Apply `y . w + b` for every temporal slice y of x. 19 | 20 | # Arguments 21 | x: input tensor. 22 | w: weight matrix. 23 | b: optional bias vector. 24 | dropout: wether to apply dropout (same dropout mask 25 | for every temporal slice of the input). 26 | input_dim: integer; optional dimensionality of the input. 27 | output_dim: integer; optional dimensionality of the output. 28 | timesteps: integer; optional number of timesteps. 29 | training: training phase tensor or boolean. 30 | 31 | # Returns 32 | Output tensor. 33 | """ 34 | if not input_dim: 35 | input_dim = K.shape(x)[2] 36 | if not timesteps: 37 | timesteps = K.shape(x)[1] 38 | if not output_dim: 39 | output_dim = K.int_shape(w)[1] 40 | 41 | if dropout is not None and 0. < dropout < 1.: 42 | # apply the same dropout pattern at every timestep 43 | ones = K.ones_like(K.reshape(x[:, 0, :], (-1, input_dim))) 44 | dropout_matrix = K.dropout(ones, dropout) 45 | expanded_dropout_matrix = K.repeat(dropout_matrix, timesteps) 46 | x = K.in_train_phase(x * expanded_dropout_matrix, x, training=training) 47 | 48 | # collapse time dimension and batch dimension together 49 | x = K.reshape(x, (-1, input_dim)) 50 | x = K.dot(x, w) 51 | if b is not None: 52 | x = K.bias_add(x, b) 53 | # reshape to 3D tensor 54 | if K.backend() == 'tensorflow': 55 | x = K.reshape(x, K.stack([-1, timesteps, output_dim])) 56 | x.set_shape([None, None, output_dim]) 57 | else: 58 | x = K.reshape(x, (-1, timesteps, output_dim)) 59 | return x 60 | 61 | 62 | class AttentionLSTM(Recurrent): 63 | """Long-Short Term Memory unit - with Attention. 64 | 65 | # Arguments 66 | units: Positive integer, dimensionality of the output space. 67 | activation: Activation function to use 68 | (see [activations](keras/activations.md)). 69 | If you pass None, no activation is applied 70 | (ie. "linear" activation: `a(x) = x`). 71 | recurrent_activation: Activation function to use 72 | for the recurrent step 73 | (see [activations](keras/activations.md)). 74 | attention_activation: Activation function to use 75 | for the attention step. If you pass None, no activation is applied 76 | (ie. "linear" activation: `a(x) = x`). 77 | (see [activations](keras/activations.md)). 78 | use_bias: Boolean, whether the layer uses a bias vector. 79 | kernel_initializer: Initializer for the `kernel` weights matrix, 80 | used for the linear transformation of the inputs. 81 | (see [initializers](../initializers.md)). 82 | recurrent_initializer: Initializer for the `recurrent_kernel` 83 | weights matrix, 84 | used for the linear transformation of the recurrent state. 85 | (see [initializers](../initializers.md)). 86 | bias_initializer: Initializer for the bias vector 87 | (see [initializers](../initializers.md)). 88 | attention_initializer: Initializer for the `attention_kernel` weights 89 | matrix, used for the linear transformation of the inputs. 90 | (see [initializers](../initializers.md)). 91 | unit_forget_bias: Boolean. 92 | If True, add 1 to the bias of the forget gate at initialization. 93 | Setting it to true will also force `bias_initializer="zeros"`. 94 | This is recommended in [Jozefowicz et al.](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf) 95 | kernel_regularizer: Regularizer function applied to 96 | the `kernel` weights matrix 97 | (see [regularizer](../regularizers.md)). 98 | recurrent_regularizer: Regularizer function applied to 99 | the `recurrent_kernel` weights matrix 100 | (see [regularizer](../regularizers.md)). 101 | bias_regularizer: Regularizer function applied to the bias vector 102 | (see [regularizer](../regularizers.md)). 103 | activity_regularizer: Regularizer function applied to 104 | the output of the layer (its "activation"). 105 | (see [regularizer](../regularizers.md)). 106 | attention_regularizer: Regularizer function applied to 107 | the `attention_kernel` weights matrix 108 | (see [regularizer](../regularizers.md)). 109 | kernel_constraint: Constraint function applied to 110 | the `kernel` weights matrix 111 | (see [constraints](../constraints.md)). 112 | recurrent_constraint: Constraint function applied to 113 | the `recurrent_kernel` weights matrix 114 | (see [constraints](../constraints.md)). 115 | bias_constraint: Constraint function applied to the bias vector 116 | (see [constraints](../constraints.md)). 117 | attention_constraint: Constraint function applied to 118 | the `attention_kernel` weights matrix 119 | (see [constraints](../constraints.md)). 120 | dropout: Float between 0 and 1. 121 | Fraction of the units to drop for 122 | the linear transformation of the inputs. 123 | recurrent_dropout: Float between 0 and 1. 124 | Fraction of the units to drop for 125 | the linear transformation of the recurrent state. 126 | return_attention: Returns the attention vector instead of 127 | the internal state. 128 | 129 | # References 130 | - [Long short-term memory](http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf) (original 1997 paper) 131 | - [Learning to forget: Continual prediction with LSTM](http://www.mitpressjournals.org/doi/pdf/10.1162/089976600300015015) 132 | - [Supervised sequence labeling with recurrent neural networks](http://www.cs.toronto.edu/~graves/preprint.pdf) 133 | - [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287) 134 | - [Bahdanau, Cho & Bengio (2014), "Neural Machine Translation by Jointly Learning to Align and Translate"](https://arxiv.org/pdf/1409.0473.pdf) 135 | - [Xu, Ba, Kiros, Cho, Courville, Salakhutdinov, Zemel & Bengio (2016), "Show, Attend and Tell: Neural Image Caption Generation with Visual Attention"](http://arxiv.org/pdf/1502.03044.pdf) 136 | """ 137 | @interfaces.legacy_recurrent_support 138 | def __init__(self, units, 139 | activation='tanh', 140 | recurrent_activation='hard_sigmoid', 141 | attention_activation='tanh', 142 | use_bias=True, 143 | kernel_initializer='glorot_uniform', 144 | recurrent_initializer='orthogonal', 145 | attention_initializer='orthogonal', 146 | bias_initializer='zeros', 147 | unit_forget_bias=True, 148 | kernel_regularizer=None, 149 | recurrent_regularizer=None, 150 | bias_regularizer=None, 151 | activity_regularizer=None, 152 | attention_regularizer=None, 153 | kernel_constraint=None, 154 | recurrent_constraint=None, 155 | bias_constraint=None, 156 | attention_constraint=None, 157 | dropout=0., 158 | recurrent_dropout=0., 159 | return_attention=False, 160 | implementation=1, 161 | **kwargs): 162 | super(AttentionLSTM, self).__init__(**kwargs) 163 | self.units = units 164 | self.activation = activations.get(activation) 165 | self.recurrent_activation = activations.get(recurrent_activation) 166 | self.attention_activation = activations.get(attention_activation) 167 | self.use_bias = use_bias 168 | 169 | self.kernel_initializer = initializers.get(kernel_initializer) 170 | self.recurrent_initializer = initializers.get(recurrent_initializer) 171 | self.attention_initializer = initializers.get(attention_initializer) 172 | self.bias_initializer = initializers.get(bias_initializer) 173 | self.unit_forget_bias = unit_forget_bias 174 | 175 | self.kernel_regularizer = regularizers.get(kernel_regularizer) 176 | self.recurrent_regularizer = regularizers.get(recurrent_regularizer) 177 | self.bias_regularizer = regularizers.get(bias_regularizer) 178 | self.activity_regularizer = regularizers.get(activity_regularizer) 179 | self.attention_regularizer = regularizers.get(attention_regularizer) 180 | 181 | self.kernel_constraint = constraints.get(kernel_constraint) 182 | self.recurrent_constraint = constraints.get(recurrent_constraint) 183 | self.bias_constraint = constraints.get(bias_constraint) 184 | self.attention_constraint = constraints.get(attention_constraint) 185 | 186 | self.dropout = min(1., max(0., dropout)) 187 | self.recurrent_dropout = min(1., max(0., recurrent_dropout)) 188 | self.return_attention = return_attention 189 | self.state_spec = [InputSpec(shape=(None, self.units)), 190 | InputSpec(shape=(None, self.units))] 191 | self.implementation = implementation 192 | 193 | def build(self, input_shape): 194 | if isinstance(input_shape, list): 195 | input_shape = input_shape[0] 196 | 197 | batch_size = input_shape[0] if self.stateful else None 198 | self.timestep_dim = input_shape[1] 199 | self.input_dim = input_shape[2] 200 | self.input_spec[0] = InputSpec(shape=(batch_size, None, self.input_dim)) 201 | 202 | self.states = [None, None] 203 | if self.stateful: 204 | self.reset_states() 205 | 206 | self.kernel = self.add_weight(shape=(self.input_dim, self.units * 4), 207 | name='kernel', 208 | initializer=self.kernel_initializer, 209 | regularizer=self.kernel_regularizer, 210 | constraint=self.kernel_constraint) 211 | self.recurrent_kernel = self.add_weight( 212 | shape=(self.units, self.units * 4), 213 | name='recurrent_kernel', 214 | initializer=self.recurrent_initializer, 215 | regularizer=self.recurrent_regularizer, 216 | constraint=self.recurrent_constraint) 217 | 218 | # add attention kernel 219 | self.attention_kernel = self.add_weight( 220 | shape=(self.input_dim, self.units * 4), 221 | name='attention_kernel', 222 | initializer=self.attention_initializer, 223 | regularizer=self.attention_regularizer, 224 | constraint=self.attention_constraint) 225 | 226 | # add attention weights 227 | # weights for attention model 228 | self.attention_weights = self.add_weight(shape=(self.input_dim, self.units), 229 | name='attention_W', 230 | initializer=self.attention_initializer, 231 | regularizer=self.attention_regularizer, 232 | constraint=self.attention_constraint) 233 | 234 | self.attention_recurrent_weights = self.add_weight(shape=(self.units, self.units), 235 | name='attention_U', 236 | initializer=self.recurrent_initializer, 237 | regularizer=self.recurrent_regularizer, 238 | constraint=self.recurrent_constraint) 239 | 240 | if self.use_bias: 241 | if self.unit_forget_bias: 242 | def bias_initializer(shape, *args, **kwargs): 243 | return K.concatenate([ 244 | self.bias_initializer((self.units,), *args, **kwargs), 245 | initializers.Ones()((self.units,), *args, **kwargs), 246 | self.bias_initializer((self.units * 2,), *args, **kwargs), 247 | ]) 248 | else: 249 | bias_initializer = self.bias_initializer 250 | self.bias = self.add_weight(shape=(self.units * 4,), 251 | name='bias', 252 | initializer=self.bias_initializer, 253 | regularizer=self.bias_regularizer, 254 | constraint=self.bias_constraint) 255 | 256 | self.attention_bias = self.add_weight(shape=(self.units,), 257 | name='attention_b', 258 | initializer=self.bias_initializer, 259 | regularizer=self.bias_regularizer, 260 | constraint=self.bias_constraint) 261 | 262 | self.attention_recurrent_bias = self.add_weight(shape=(self.units, 1), 263 | name='attention_v', 264 | initializer=self.bias_initializer, 265 | regularizer=self.bias_regularizer, 266 | constraint=self.bias_constraint) 267 | else: 268 | self.bias = None 269 | self.attention_bias = None 270 | self.attention_recurrent_bias = None 271 | 272 | self.kernel_i = self.kernel[:, :self.units] 273 | self.kernel_f = self.kernel[:, self.units: self.units * 2] 274 | self.kernel_c = self.kernel[:, self.units * 2: self.units * 3] 275 | self.kernel_o = self.kernel[:, self.units * 3:] 276 | 277 | self.recurrent_kernel_i = self.recurrent_kernel[:, :self.units] 278 | self.recurrent_kernel_f = self.recurrent_kernel[:, self.units: self.units * 2] 279 | self.recurrent_kernel_c = self.recurrent_kernel[:, self.units * 2: self.units * 3] 280 | self.recurrent_kernel_o = self.recurrent_kernel[:, self.units * 3:] 281 | 282 | self.attention_i = self.attention_kernel[:, :self.units] 283 | self.attention_f = self.attention_kernel[:, self.units: self.units * 2] 284 | self.attention_c = self.attention_kernel[:, self.units * 2: self.units * 3] 285 | self.attention_o = self.attention_kernel[:, self.units * 3:] 286 | 287 | if self.use_bias: 288 | self.bias_i = self.bias[:self.units] 289 | self.bias_f = self.bias[self.units: self.units * 2] 290 | self.bias_c = self.bias[self.units * 2: self.units * 3] 291 | self.bias_o = self.bias[self.units * 3:] 292 | else: 293 | self.bias_i = None 294 | self.bias_f = None 295 | self.bias_c = None 296 | self.bias_o = None 297 | 298 | self.built = True 299 | 300 | def preprocess_input(self, inputs, training=None): 301 | return inputs 302 | 303 | def get_constants(self, inputs, training=None): 304 | constants = [] 305 | if self.implementation != 0 and 0 < self.dropout < 1: 306 | input_shape = K.int_shape(inputs) 307 | input_dim = input_shape[-1] 308 | ones = K.ones_like(K.reshape(inputs[:, 0, 0], (-1, 1))) 309 | ones = K.tile(ones, (1, int(input_dim))) 310 | 311 | def dropped_inputs(): 312 | return K.dropout(ones, self.dropout) 313 | 314 | dp_mask = [K.in_train_phase(dropped_inputs, 315 | ones, 316 | training=training) for _ in range(4)] 317 | constants.append(dp_mask) 318 | else: 319 | constants.append([K.cast_to_floatx(1.) for _ in range(4)]) 320 | 321 | if 0 < self.recurrent_dropout < 1: 322 | ones = K.ones_like(K.reshape(inputs[:, 0, 0], (-1, 1))) 323 | ones = K.tile(ones, (1, self.units)) 324 | 325 | def dropped_inputs(): 326 | return K.dropout(ones, self.recurrent_dropout) 327 | rec_dp_mask = [K.in_train_phase(dropped_inputs, 328 | ones, 329 | training=training) for _ in range(4)] 330 | constants.append(rec_dp_mask) 331 | else: 332 | constants.append([K.cast_to_floatx(1.) for _ in range(4)]) 333 | 334 | # append the input as well for use later 335 | constants.append(inputs) 336 | return constants 337 | 338 | def step(self, inputs, states): 339 | h_tm1 = states[0] 340 | c_tm1 = states[1] 341 | dp_mask = states[2] 342 | rec_dp_mask = states[3] 343 | x_input = states[4] 344 | 345 | # alignment model 346 | h_att = K.repeat(h_tm1, self.timestep_dim) 347 | att = _time_distributed_dense(x_input, self.attention_weights, self.attention_bias, 348 | output_dim=K.int_shape(self.attention_weights)[1]) 349 | attention_ = self.attention_activation(K.dot(h_att, self.attention_recurrent_weights) + att) 350 | attention_ = K.squeeze(K.dot(attention_, self.attention_recurrent_bias), 2) 351 | 352 | alpha = K.exp(attention_) 353 | 354 | if dp_mask is not None: 355 | alpha *= dp_mask[0] 356 | 357 | alpha /= K.sum(alpha, axis=1, keepdims=True) 358 | alpha_r = K.repeat(alpha, self.input_dim) 359 | alpha_r = K.permute_dimensions(alpha_r, (0, 2, 1)) 360 | 361 | # make context vector (soft attention after Bahdanau et al.) 362 | z_hat = x_input * alpha_r 363 | context_sequence = z_hat 364 | z_hat = K.sum(z_hat, axis=1) 365 | 366 | if self.implementation == 2: 367 | z = K.dot(inputs * dp_mask[0], self.kernel) 368 | z += K.dot(h_tm1 * rec_dp_mask[0], self.recurrent_kernel) 369 | z += K.dot(z_hat, self.attention_kernel) 370 | 371 | if self.use_bias: 372 | z = K.bias_add(z, self.bias) 373 | 374 | z0 = z[:, :self.units] 375 | z1 = z[:, self.units: 2 * self.units] 376 | z2 = z[:, 2 * self.units: 3 * self.units] 377 | z3 = z[:, 3 * self.units:] 378 | 379 | i = self.recurrent_activation(z0) 380 | f = self.recurrent_activation(z1) 381 | c = f * c_tm1 + i * self.activation(z2) 382 | o = self.recurrent_activation(z3) 383 | else: 384 | if self.implementation == 0: 385 | x_i = inputs[:, :self.units] 386 | x_f = inputs[:, self.units: 2 * self.units] 387 | x_c = inputs[:, 2 * self.units: 3 * self.units] 388 | x_o = inputs[:, 3 * self.units:] 389 | elif self.implementation == 1: 390 | x_i = K.dot(inputs * dp_mask[0], self.kernel_i) + self.bias_i 391 | x_f = K.dot(inputs * dp_mask[1], self.kernel_f) + self.bias_f 392 | x_c = K.dot(inputs * dp_mask[2], self.kernel_c) + self.bias_c 393 | x_o = K.dot(inputs * dp_mask[3], self.kernel_o) + self.bias_o 394 | else: 395 | raise ValueError('Unknown `implementation` mode.') 396 | 397 | i = self.recurrent_activation(x_i + K.dot(h_tm1 * rec_dp_mask[0], self.recurrent_kernel_i) 398 | + K.dot(z_hat, self.attention_i)) 399 | f = self.recurrent_activation(x_f + K.dot(h_tm1 * rec_dp_mask[1], self.recurrent_kernel_f) 400 | + K.dot(z_hat, self.attention_f)) 401 | c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * rec_dp_mask[2], self.recurrent_kernel_c) 402 | + K.dot(z_hat, self.attention_c)) 403 | o = self.recurrent_activation(x_o + K.dot(h_tm1 * rec_dp_mask[3], self.recurrent_kernel_o) 404 | + K.dot(z_hat, self.attention_o)) 405 | h = o * self.activation(c) 406 | if 0 < self.dropout + self.recurrent_dropout: 407 | h._uses_learning_phase = True 408 | 409 | if self.return_attention: 410 | return context_sequence, [h, c] 411 | else: 412 | return h, [h, c] 413 | 414 | def get_config(self): 415 | config = {'units': self.units, 416 | 'activation': activations.serialize(self.activation), 417 | 'recurrent_activation': activations.serialize(self.recurrent_activation), 418 | 'attention_activation': activations.serialize(self.attention_activation), 419 | 'use_bias': self.use_bias, 420 | 'kernel_initializer': initializers.serialize(self.kernel_initializer), 421 | 'recurrent_initializer': initializers.serialize(self.recurrent_initializer), 422 | 'bias_initializer': initializers.serialize(self.bias_initializer), 423 | 'attention_initializer': initializers.serialize(self.attention_initializer), 424 | 'unit_forget_bias': self.unit_forget_bias, 425 | 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer), 426 | 'recurrent_regularizer': regularizers.serialize(self.recurrent_regularizer), 427 | 'bias_regularizer': regularizers.serialize(self.bias_regularizer), 428 | 'activity_regularizer': regularizers.serialize(self.activity_regularizer), 429 | 'attention_regularizer': regularizers.serialize(self.attention_regularizer), 430 | 'kernel_constraint': constraints.serialize(self.kernel_constraint), 431 | 'recurrent_constraint': constraints.serialize(self.recurrent_constraint), 432 | 'bias_constraint': constraints.serialize(self.bias_constraint), 433 | 'attention_constraint': constraints.serialize(self.attention_constraint), 434 | 'dropout': self.dropout, 435 | 'recurrent_dropout': self.recurrent_dropout, 436 | 'return_attention': self.return_attention} 437 | base_config = super(AttentionLSTM, self).get_config() 438 | return dict(list(base_config.items()) + list(config.items())) 439 | -------------------------------------------------------------------------------- /ets/algorithms/MLSTM/utils/note.txt: -------------------------------------------------------------------------------- 1 | Will contain utility scripts for data set loading, convertion, and static constants and so on. 2 | 3 | Difficult Datasets : 4 | 5 | 1) Medical Image dataset - gets stuck at 66%. Fine tune to 67, then restart training to get to 71. Then fine tune again. 6 | 2) Sony AIBO 1 - restart multiple times 7 | 3) Distal phalanx age group - restart multiple times. 8 | 4) Mote Strain - many restarts. Fine tune to 91%. 9 | 5) Proximal phalanx - multiple restarts, multiple finetuning attempts. -------------------------------------------------------------------------------- /ets/algorithms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__init__.py -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/cfsr.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/cfsr.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/early_classifier.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/early_classifier.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/ecdire.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/ecdire.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/ecec.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/ecec.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/ects.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/ects.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/ects_c.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/ects_c.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/edsc.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/edsc.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/edsc_c.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/edsc_c.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/mlstm.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/mlstm.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/nn.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/nn.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/teaser.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/teaser.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/temp.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/temp.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/__pycache__/utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eukla/ETS/a36b753eead222cf399663d95f83cde94f084868/ets/algorithms/__pycache__/utils.cpython-37.pyc -------------------------------------------------------------------------------- /ets/algorithms/early_classifier.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import pandas as pd 3 | from typing import Tuple, Sequence 4 | 5 | 6 | class EarlyClassifier(metaclass=abc.ABCMeta): 7 | """ 8 | EarlyClassifier is an abstract class that should be extended 9 | by any algorithm for early time-series classification. 10 | """ 11 | 12 | @abc.abstractmethod 13 | def train(self, train_data: pd.DataFrame, labels: Sequence[int]) -> None: 14 | """ 15 | Trains the classifier. 16 | 17 | :param train_data: training time-series data 18 | :param labels: training time-series labels 19 | """ 20 | 21 | @abc.abstractmethod 22 | def predict(self, test_data: pd.DataFrame) -> Sequence[Tuple[int, int]]: 23 | """ 24 | Predict the class of the given time-series as early as possible. 25 | 26 | :param test_data: time-series to predict 27 | :return: a sequence of early predictions for the given time-series 28 | """ 29 | -------------------------------------------------------------------------------- /ets/algorithms/ecec.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import subprocess 3 | from typing import List, Tuple, Sequence 4 | 5 | import coloredlogs 6 | import pandas as pd 7 | 8 | # Configure the logger (change level to DEBUG for more information) 9 | logger = logging.getLogger(__name__) 10 | coloredlogs.install(level=logging.INFO, logger=logger, 11 | fmt='%(asctime)s - %(hostname)s - %(name)s[%(process)d] - [%(levelname)s]: %(message)s') 12 | 13 | 14 | class ECEC(): 15 | """ 16 | The ECEC algorithm. 17 | 18 | Publications: 19 | 20 | An Effective Confidence-Based Early Classification of Time Series (2019) 21 | """ 22 | 23 | def __init__(self, timestamps: Sequence[int]): 24 | 25 | self.timestamps = timestamps 26 | 27 | def predict(self, test_data: pd.DataFrame) -> List[Tuple[int, int]]: 28 | predictions = [] 29 | bin_output = subprocess.check_output(["java", "-jar", "Java/ecec_test.main.jar", "./train", "./test"]) 30 | output = bin_output.decode("utf-8") 31 | truncated_output = output.split("\n") 32 | new = truncated_output.copy() 33 | counter = 0 34 | for item in truncated_output: 35 | if item == '-1 -1': 36 | new.pop(counter) 37 | break 38 | else: 39 | new.pop(counter) 40 | counter -= 1 41 | counter += 1 42 | predictions = [] 43 | for item in new: 44 | if item == '\n': 45 | continue 46 | if "TimeTrain" in item: 47 | final = item.split(" ") 48 | train = final[1] 49 | continue 50 | if "TimeTest" in item: 51 | final = item.split(" ") 52 | test = final[1] 53 | break 54 | if item == '': 55 | continue 56 | final = item.split(" ") 57 | predictions.append([float(final[1]), float(final[0])]) 58 | return predictions, train, test 59 | -------------------------------------------------------------------------------- /ets/algorithms/ects.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import coloredlogs 3 | import numpy as np 4 | import pandas as pd 5 | from multiprocessing import Pool 6 | import threading 7 | from scipy.spatial import distance 8 | from sklearn.neighbors import NearestNeighbors 9 | from typing import Tuple, List, Sequence, Dict, Optional 10 | from ets.algorithms.early_classifier import EarlyClassifier 11 | import multiprocessing as mp 12 | # Configure the logger (change level to DEBUG for more information) 13 | logger = logging.getLogger(__name__) 14 | coloredlogs.install(level=logging.INFO, logger=logger, 15 | fmt='%(asctime)s - %(hostname)s - %(name)s[%(process)d] - [%(levelname)s]: %(message)s') 16 | x = 0 17 | class ECTS(EarlyClassifier): 18 | 19 | """ 20 | The ECTS algorithm. 21 | 22 | Publications: 23 | 24 | Early classification on time series(2012) 25 | """ 26 | 27 | def __init__(self, timestamps, support: float, relaxed: bool): 28 | """ 29 | Creates an ECTS instance. 30 | 31 | :param timestamps: a list of timestamps for early predictions 32 | :param support: minimum support threshold 33 | :param relaxed: whether we use the Relaxed version or the normal 34 | """ 35 | self.rnn: Dict[int, Dict[int, List]] = dict() 36 | self.nn: Dict[int, Dict[int, List]] = dict() 37 | self.data: Optional[pd.DataFrame] = None 38 | self.labels: Optional[pd.Series] = None 39 | self.mpl: Dict[int, Optional[int]] = dict() 40 | self.timestamps = timestamps 41 | self.support = support 42 | self.clusters: Dict[int, List[int]] = dict() 43 | self.occur: Dict[int, int] = dict() 44 | self.relaxed = relaxed 45 | self.correct: Optional[List[Optional[int]]] = None 46 | 47 | def train(self, train_data: pd.DataFrame, labels: Sequence[int]) -> None: 48 | 49 | """ 50 | Function that trains the model using Agglomerating Hierarchical clustering 51 | 52 | :param train_data: a Dataframe containing-series 53 | :param labels: a Sequence containing the labels of the data 54 | """ 55 | self.data = train_data 56 | 57 | self.labels = labels 58 | if self.relaxed: 59 | self.__leave_one_out() 60 | for index, value in self.labels.value_counts().items(): 61 | self.occur[index] = value 62 | 63 | # Finding the RNN of each item 64 | time_pos = 0 65 | for e in self.timestamps: 66 | product = self.__nn_non_cluster(time_pos) # Changed to timestamps position 67 | self.rnn[e] = product[1] 68 | self.nn[e] = product[0] 69 | time_pos += 1 70 | temp = {} 71 | finished = {} # Dictionaries that signifies if an mpl has been found 72 | for e in reversed(self.timestamps): 73 | for index, row in self.data.iterrows(): 74 | if index not in temp: 75 | self.mpl[index] = e 76 | finished[index] = 0 # Still MPL is not found 77 | 78 | else: 79 | if finished[index] == 1: # MPL has been calculated for this time-series so nothing to do here 80 | continue 81 | 82 | if self.rnn[e][index] is not None: 83 | self.rnn[e][index].sort() 84 | # Sorting it in order to establish that the RNN is in the same order as the value 85 | if temp[index] is not None: 86 | temp[index].sort() 87 | 88 | if self.rnn[e][index] == temp[index]: # Still going back the timestamps 89 | self.mpl[index] = e 90 | 91 | else: # Found k-1 92 | finished[index] = 1 # MPL has been found! 93 | temp[index] = self.rnn[e][index] 94 | self.__mpl_clustering() 95 | 96 | def __leave_one_out(self): 97 | nn = [] 98 | for index, row in self.data.iterrows(): # Comparing each time-series 99 | 100 | data_copy = self.data.copy() 101 | data_copy = data_copy.drop(data_copy.index[index]) 102 | for index2, row2 in data_copy.iterrows(): 103 | temp_dist = distance.euclidean(row, row2) 104 | 105 | if not nn: 106 | nn = [(self.labels[index2], temp_dist)] 107 | elif temp_dist >= nn[0][1]: 108 | nn = [(self.labels[index2], temp_dist)] 109 | if nn[0][0] == self.labels[index]: 110 | if not self.correct: 111 | self.correct = [index] 112 | else: 113 | self.correct.append(index) 114 | nn.clear() 115 | 116 | def __nn_non_cluster(self, prefix: int): 117 | """Finds the NN of each time_series and stores it in a dictionary 118 | 119 | :param prefix: the prefix with which we will conduct the NN 120 | 121 | :return: two dicts holding the NN and RNN""" 122 | nn = {} 123 | rnn = {} 124 | pd.set_option("display.max_rows", None, "display.max_columns", None) 125 | neigh = NearestNeighbors(n_neighbors=2, metric='euclidean').fit(self.data.iloc[:, 0:prefix + 1]) 126 | def something(row): 127 | return neigh.kneighbors([row]) 128 | 129 | result_data = self.data.iloc[:, 0:prefix + 1].apply(something, axis=1) 130 | for index, value in result_data.items(): 131 | if index not in nn: 132 | nn[index] = [] 133 | if index not in rnn: 134 | rnn[index] = [] 135 | for item in value[1][0]: 136 | if item != index: 137 | nn[index].append(item) 138 | if item not in rnn: 139 | rnn[item] = [index] 140 | else: 141 | rnn[item].append(index) 142 | return nn, rnn 143 | 144 | def __cluster_distance(self, cluster_a: Sequence[int], cluster_b: Sequence[int]): 145 | """ 146 | Computes the distance between two clusters as the minimum among all 147 | inter-cluster pair-wise distances. 148 | 149 | :param cluster_a: a cluster 150 | :param cluster_b: another cluster 151 | :return: the distance 152 | """ 153 | 154 | min_distance = float("inf") 155 | for i in cluster_a: 156 | for j in cluster_b: 157 | d = distance.euclidean(self.data.iloc[i], self.data.iloc[j]) 158 | if min_distance > d: 159 | min_distance = d 160 | 161 | return min_distance 162 | 163 | def nn_cluster(self, cl_key: int, cluster_index: Sequence[int]): 164 | """Finds the nearest neighbor to a cluster 165 | :param cluster_index: List of indexes contained in the list 166 | :param cl_key: The key of the list in the cluster dictionary 167 | """ 168 | global x 169 | dist = float("inf") 170 | candidate = [] # List that stores multiple candidates 171 | 172 | for key, value in self.clusters.items(): # For each other cluster 173 | 174 | if cl_key == key: # Making sure its a different to our current cluster 175 | continue 176 | temp = self.__cluster_distance(cluster_index, value) # Find their Distance 177 | 178 | if dist > temp: # If its smaller than the previous, store it 179 | dist = temp 180 | candidate = [key] 181 | 182 | elif dist == temp: # If its the same, store it as well 183 | candidate.append(key) 184 | x-=1 185 | return candidate 186 | 187 | def __rnn_cluster(self, e: int, cluster: List[int]): 188 | """ 189 | Calculates the RNN of a cluster for a certain prefix. 190 | 191 | :param e: the prefix for which we want to find the RNN 192 | :param cluster: the cluster that we want to find the RNN 193 | """ 194 | 195 | rnn = set() 196 | complete = set() 197 | for item in cluster: 198 | rnn.union(self.rnn[e][item]) 199 | for item in rnn: 200 | if item not in cluster: 201 | complete.add(item) 202 | return complete 203 | 204 | def __mpl_calculation(self, cluster: List[int]): 205 | """Finds the MPL of discriminative clusters 206 | 207 | :param cluster: The cluster of which we want to find it's MPL""" 208 | # Checking if the support condition is met 209 | index = self.labels[cluster[0]] 210 | if self.support > len(cluster) / self.occur[index]: 211 | return 212 | mpl_rnn = self.timestamps[len( 213 | self.timestamps) - 1] # Initializing the variables that will indicate the minimum timestamp from which each rule applies 214 | mpl_nn = self.timestamps[len(self.timestamps) - 1] 215 | """Checking the RNN rule for the clusters""" 216 | 217 | curr_rnn = self.__rnn_cluster(self.timestamps[len(self.timestamps) - 1], cluster) # Finding the RNN for the L 218 | 219 | if self.relaxed: 220 | curr_rnn = curr_rnn.intersection(self.correct) 221 | 222 | for e in reversed(self.timestamps): 223 | 224 | temp = self.__rnn_cluster(e, cluster) # Finding the RNN for the next timestamp 225 | if self.relaxed: 226 | temp = temp.intersection(self.correct) 227 | 228 | if not curr_rnn - temp: # If their division is an empty set, then the RNN is the same so the 229 | # MPL is e 230 | mpl_rnn = e 231 | else: 232 | break 233 | curr_rnn = temp 234 | 235 | """Then we check the 1-NN consistency""" 236 | rule_broken = 0 237 | for e in reversed(self.timestamps): # For each timestamp 238 | 239 | for series in cluster: # For each time-series 240 | 241 | for my_tuple in self.nn[e][series]: # We check the corresponding NN to the series 242 | if my_tuple not in cluster: 243 | rule_broken = 1 244 | break 245 | if rule_broken == 1: 246 | break 247 | if rule_broken == 1: 248 | break 249 | else: 250 | mpl_nn = e 251 | for series in cluster: 252 | pos = max(mpl_rnn, mpl_nn) # The value at which at least one rule is in effect 253 | if self.mpl[series] > pos: 254 | self.mpl[series] = pos 255 | 256 | def __mpl_clustering(self): 257 | """Executes the hierarchical clustering""" 258 | pool = Pool(mp.cpu_count()) 259 | n = self.data.shape[0] 260 | redirect = {} # References an old cluster pair candidate to its new place 261 | discriminative = 0 # Value that stores the number of discriminative values found 262 | """Initially make as many clusters as there are items""" 263 | for index, row in self.data.iterrows(): 264 | self.clusters[index] = [index] 265 | redirect[index] = index 266 | result = [] 267 | """Clustering loop""" 268 | while n > 1: # For each item 269 | closest = {} 270 | my_list = list(self.clusters.items()) 271 | res = pool.starmap(self.nn_cluster, my_list) 272 | for key,p in zip(self.clusters.keys(),res): 273 | closest[key] = p 274 | logger.debug(closest) 275 | for key, value in closest.items(): 276 | for item in list(value): 277 | if key in closest[item]: # Mutual pair found 278 | closest[item].remove(key) 279 | if redirect[item]==redirect[key]: #If 2 time-series are in the same cluster(in case they had an 3d neighboor that invited them in the cluster) 280 | continue 281 | for time_series in self.clusters[redirect[item]]: 282 | self.clusters[redirect[key]].append(time_series) # Commence merging 283 | del self.clusters[redirect[item]] 284 | n = n - 1 285 | redirect[item] = redirect[key] # The item can now be found in another cluster 286 | for element in self.clusters[redirect[key]]: # Checking if cluster is discriminative 287 | result.append(self.labels.loc[element]) 288 | 289 | x = np.array(result) 290 | if len(np.unique(x)) == 1: # If the unique class labels is 1, then the 291 | # cluster is discriminative 292 | discriminative += 1 293 | self.__mpl_calculation(self.clusters[redirect[key]]) 294 | 295 | for neighboors_neigboor in closest: # The items in the cluster that has been assimilated can 296 | # be found in the super-cluster 297 | if redirect[neighboors_neigboor] == item: 298 | redirect[neighboors_neigboor] = key 299 | result.clear() 300 | if discriminative == 0: # No discriminative clusters found 301 | break 302 | discriminative = 0 303 | pool.terminate() 304 | def predict(self, test_data: pd.DataFrame) -> List[Tuple[int, int]]: 305 | """ 306 | Prediction phase. 307 | Finds the 1-NN of the test data and if the MPL oof the closest time-series allows the prediction, then return that prediction 308 | """ 309 | predictions = [] 310 | nn = [] 311 | candidates = [] # will hold the potential predictions 312 | cand_min_mpl = [] 313 | #test_data = test_data.rename(columns=lambda x: x - 1) 314 | for test_index, test_row in test_data.iterrows(): 315 | for e in self.timestamps: 316 | neigh = NearestNeighbors(n_neighbors=1, metric='euclidean').fit(self.data.iloc[:, 0:e + 1]) 317 | neighbors = neigh.kneighbors([test_row[0:e + 1]]) 318 | candidates.clear() 319 | cand_min_mpl.clear() 320 | nn = neighbors[1] 321 | for i in nn: 322 | if e >= self.mpl[i[0]]: 323 | candidates.append((self.mpl[i[0]], self.labels[i[0]])) # Storing candidates by mpl and by label 324 | if len(candidates) > 1: # List is not empty so wee found candidates 325 | candidates.sort(key=lambda x: x[0]) 326 | for candidate in candidates: 327 | 328 | if candidate[0] == candidates[0][0]: 329 | cand_min_mpl.append(candidate) # Keeping the candidates with the minimum mpl 330 | else: 331 | break # From here on the mpl is going to get bigger 332 | 333 | predictions.append( 334 | (e, max(set(cand_min_mpl), key=cand_min_mpl.count))) # The second argument is the max label 335 | break 336 | elif len(candidates) == 1: # We don't need to to do the above if we have only one nn 337 | predictions.append((e, candidates[0][1])) 338 | break 339 | if candidates == 0: 340 | predictions.append((self.timestamps[-1], 0)) 341 | return predictions 342 | -------------------------------------------------------------------------------- /ets/algorithms/edsc_c.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import subprocess 3 | import os 4 | import coloredlogs 5 | import numpy as np 6 | import pandas as pd 7 | from multiprocessing import Pool 8 | import threading 9 | from scipy.spatial import distance 10 | from sklearn.neighbors import NearestNeighbors 11 | from ets.algorithms.utils import DataSetCreation_EDSC 12 | from typing import Tuple, List, Sequence, Dict, Optional 13 | from ets.algorithms.early_classifier import EarlyClassifier 14 | import multiprocessing as mp 15 | from subprocess import call, check_output 16 | 17 | # Configure the logger (change level to DEBUG for more information) 18 | logger = logging.getLogger(__name__) 19 | coloredlogs.install(level=logging.INFO, logger=logger, 20 | fmt='%(asctime)s - %(hostname)s - %(name)s[%(process)d] - [%(levelname)s]: %(message)s') 21 | 22 | 23 | class EDSC_C(EarlyClassifier): 24 | "Uses the ECTS_C ready implementation" 25 | 26 | def predict(self, test_data: pd.DataFrame) -> Sequence[Tuple[int, int]]: 27 | pass 28 | 29 | def __init__(self, timestamps): 30 | self.train_d = pd.DataFrame() 31 | self.test = pd.DataFrame() 32 | self.time_stamps = timestamps 33 | self.labels = pd.Series() 34 | 35 | def train(self, train_data: pd.DataFrame, labels: Sequence[int]) -> None: 36 | self.train_d = train_data 37 | self.labels = labels 38 | 39 | def predict2(self, test_data: pd.DataFrame, labels: pd.Series, numbers: pd.Series, types:int): 40 | self.test_d = test_data 41 | dimension = len(self.time_stamps) 42 | rowtraining = self.train_d.shape[0] 43 | rowtesting = self.test_d.shape[0] 44 | labels_c = None 45 | if(types == 1): 46 | labels_c = sorted(self.labels.unique()) 47 | elif(types == 0): 48 | labels_c = sorted(self.labels.unique(), reverse = True) 49 | DataSetCreation_EDSC(dimension, rowtraining, rowtesting, labels_c, numbers) 50 | predictions = [] 51 | self.train_d.insert(loc=0, value=self.labels, column="Class") 52 | self.test_d.insert(loc=0, value=labels, column="Class") 53 | self.train_d.to_csv("C_files/edsc/Data/train", sep=" ", header=False, index_label=False, index=False) 54 | self.test_d.to_csv("C_files/edsc/Data/test", sep=" ", header=False, index_label=False, index=False) 55 | os.system("g++ C_files/edsc/ByInstanceDP.cpp C_files/edsc/quickSort.cpp C_files/edsc/Euclidean.cpp -o edsc") 56 | bin_output = check_output(["./edsc"]) 57 | output = bin_output.decode("utf-8") 58 | truncated_output = output.split("\n") 59 | found = False 60 | train=0 61 | test = 0 62 | for item in truncated_output: 63 | if "" == item and found: 64 | found=False 65 | if found: 66 | res = item.split(" ") 67 | if int(res[1]) == -4: 68 | occurrences = self.labels.value_counts() 69 | predictions.append((self.time_stamps[-1], occurrences.idxmax())) 70 | else: 71 | predictions.append((int(res[0]), int(res[1]))) 72 | 73 | if "finish2" in item: 74 | res = item.split(" ") 75 | test = res[0] 76 | break 77 | if "finish" in item and not found: 78 | res = item.split(" ") 79 | train = res[0] 80 | found = True 81 | return predictions,train,test 82 | -------------------------------------------------------------------------------- /ets/algorithms/mlstm.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import keras 4 | from sklearn.model_selection import StratifiedKFold 5 | 6 | from ets.algorithms.MLSTM.mlstm_impl import run 7 | from ets.algorithms.utils import accuracy, harmonic_mean 8 | from ets.algorithms.utils import topy 9 | 10 | 11 | class MLSTM(): 12 | 13 | def __init__(self, timestamps, earliness, folds): 14 | self.timestamps = timestamps 15 | self.folds = folds 16 | self.predict_model = keras.Model 17 | if earliness is None: 18 | self.earliness = [0.4, 0.5, 0.6] 19 | else: 20 | self.earliness = earliness 21 | 22 | def true_predict(self, train_d, test_d, train_l): 23 | res = {} 24 | earl = self.earliness 25 | timesteps = test_d[0].shape[1] 26 | if not os.path.exists("./ets/algorithms/MLSTM/data"): 27 | os.mkdir("./ets/algorithms/MLSTM/data") 28 | if not os.path.exists("./ets/algorithms/MLSTM/weights"): 29 | os.mkdir("./ets/algorithms/MLSTM/weights") 30 | 31 | train_time = 0 32 | test_time = 0 33 | indices = zip(StratifiedKFold(5).split(train_d[0], train_l), range(1, self.folds + 1)) 34 | variables = len(train_d) 35 | for ((train_indices, test_indices), i) in indices: 36 | h_max = 0 37 | res[i] = None # For each fold 38 | fold_train_data = [train_d[i].iloc[train_indices].reset_index(drop=True) for i in 39 | range(0, variables)] 40 | fold_test_data = [train_d[i].iloc[test_indices].reset_index(drop=True) for i in 41 | range(0, variables)] 42 | fold_train_labels = train_l[train_indices].reset_index(drop=True) 43 | fold_test_labels = train_l[test_indices].reset_index(drop=True) 44 | for earliness in earl: 45 | sizes = int(len(self.timestamps) * earliness) 46 | new_d = [] 47 | for data in fold_train_data: 48 | temp = data.iloc[:, 0:self.timestamps[sizes]] 49 | new_d.append(temp) 50 | new_t = [] 51 | for data in fold_test_data: 52 | temp = data.iloc[:, 0:self.timestamps[sizes]] 53 | new_t.append(temp) 54 | topy(new_d, fold_train_labels, new_t, timesteps) 55 | result = run(earliness) # 1)prediction 2) train time 3) test time 4) LSTM cell 56 | results = [] 57 | labels = sorted(fold_train_labels.unique()) 58 | for item in result[0]: 59 | results.append((item[0], labels[item[1]])) 60 | acc = accuracy(results, fold_test_labels.to_list()) 61 | harmonic_means = harmonic_mean(acc, sizes / len(self.timestamps)) 62 | if h_max < harmonic_means: 63 | h_max = harmonic_means 64 | best_earl = earliness 65 | best_cell = result[3] 66 | res[i] = (h_max, best_earl, best_cell) 67 | train_time += result[1] 68 | train_time += result[2] 69 | """We need to pick the best earliness and cells for the final prediction""" 70 | counts = {} 71 | best_folds = {} 72 | for earliness in earl: # initallizing 73 | counts[earliness] = 0 74 | best_folds[earliness] = [] 75 | 76 | for i in range(1, self.folds + 1): # find the most common picked earliness among folds 77 | counts[res[i][1]] += 1 78 | best_folds[res[i][1]].append(i) 79 | count = 0 80 | best_earl = 0 81 | for earliness in earl: 82 | if count < counts[earliness]: 83 | count = counts[earliness] 84 | best_earl = earliness 85 | best_score = 0 # find the best LSTM cells 86 | best_cell = 0 87 | for item in best_folds[best_earl]: 88 | if best_score < res[item][0]: 89 | best_score = res[item][0] 90 | best_cell = res[item][2] 91 | print(best_earl, best_cell) 92 | sizes = int(len(self.timestamps) * best_earl) 93 | new_d = [] 94 | for data in train_d: 95 | temp = data.iloc[:, 0:self.timestamps[sizes]] 96 | new_d.append(temp) 97 | new_t = [] 98 | for data in test_d: 99 | temp = data.iloc[:, 0:self.timestamps[sizes]] 100 | new_t.append(temp) 101 | topy(new_d, train_l, new_t, timesteps) 102 | result = run(best_earl, best_cell) 103 | results = [] 104 | labels = sorted(train_l.unique()) 105 | for item in result[0]: 106 | results.append((item[0], labels[item[1]])) 107 | train_time += result[1] 108 | test_time += result[2] 109 | print(train_time, test_time) 110 | return results, train_time, test_time, best_earl, best_cell 111 | -------------------------------------------------------------------------------- /ets/algorithms/non_myopic.py: -------------------------------------------------------------------------------- 1 | from ets.algorithms.early_classifier import EarlyClassifier 2 | from tslearn.early_classification import NonMyopicEarlyClassifier 3 | from tslearn.datasets import UCR_UEA_datasets 4 | from tslearn.preprocessing import TimeSeriesScalerMeanVariance 5 | from tslearn.utils import to_time_series_dataset 6 | 7 | import pandas as pd 8 | import numpy as np 9 | from typing import Sequence, Tuple 10 | 11 | 12 | class Trigger(EarlyClassifier): 13 | """ 14 | The algorithm from Dachraoui et al. 2015 15 | 16 | Publications: 17 | 18 | Early classification of time series as a non myopic sequential decision making problem(2015) 19 | 20 | Code: 21 | https://tslearn.readthedocs.io/en/stable/user_guide/early.html#examples-involving-early-classification-estimators 22 | """ 23 | 24 | def __init__(self, n_clusters: int, cost_time_parameter: float, lamb: float, random_state: bool): 25 | self.n_clusters = n_clusters 26 | self.cost_time_parameter = cost_time_parameter 27 | self.lamb = lamb 28 | self.random_state = random_state 29 | self.classifier = NonMyopicEarlyClassifier 30 | 31 | def train(self, train_data: pd.DataFrame, labels: Sequence[int]) -> None: 32 | self.classifier = NonMyopicEarlyClassifier(n_clusters=self.n_clusters, 33 | cost_time_parameter=self.cost_time_parameter, lamb=self.lamb, 34 | random_state=self.random_state) 35 | np.random.seed(0) 36 | train_data = train_data.values.tolist() 37 | train_data = to_time_series_dataset(train_data) 38 | labels = labels.values 39 | self.classifier.fit(train_data, labels) 40 | 41 | def predict(self, test_data: pd.DataFrame) -> Sequence[Tuple[int, int]]: 42 | np.random.seed(0) 43 | test_data = test_data.values.tolist() 44 | test_data = to_time_series_dataset(test_data) 45 | pred, times = self.classifier.predict_class_and_earliness(test_data) 46 | results = [] 47 | for preds, earl in zip(pred, times): 48 | results.append((earl, preds)) 49 | return results 50 | -------------------------------------------------------------------------------- /ets/algorithms/teaser.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from typing import Sequence, Optional 3 | 4 | import pandas as pd 5 | 6 | from ets.algorithms.early_classifier import EarlyClassifier 7 | 8 | 9 | class TEASER(EarlyClassifier): 10 | """ 11 | The TEASER algorithm. 12 | 13 | Publications: 14 | 15 | TEASER: early and accurate time series classification(2020) 16 | """ 17 | 18 | def train(self, train_data: pd.DataFrame, labels: Sequence[int]) -> None: 19 | pass 20 | 21 | def __init__(self, timestamps, S: int, normalize: bool): 22 | """ 23 | Creates the Teaser object 24 | 25 | :param timestamps: The list of timestamps for classification 26 | :param S: The total number of slave-master classifier pairs 27 | :param normalize: The version of TEASER 28 | """ 29 | self.timestamps = timestamps 30 | self.S = S 31 | self.normalize = normalize 32 | self.dataset: Optional[pd.DataFrame] = None 33 | self.labels: Sequence[int] 34 | 35 | def predict(self, test_data): 36 | if self.normalize: 37 | bin_output = subprocess.check_output(["java", "-jar", "Java/sfa.main.jar", str(self.S), "./train", "./test"]) 38 | else: 39 | bin_output = subprocess.check_output( 40 | ["java", "-jar", "Java/sfa.main_non_norm.jar", str(self.S), "./train", "./test"]) 41 | output = bin_output.decode("utf-8") 42 | train = 0 43 | truncated_output = output.split("\n") 44 | new = truncated_output.copy() 45 | counter = 0 46 | for item in truncated_output: 47 | if item == '-1 -1': 48 | new.pop(counter) 49 | break 50 | elif "TimeTrain" in item: 51 | out = item.split(" ") 52 | new.pop(counter) 53 | counter -= 1 54 | train = out[1] 55 | else: 56 | new.pop(counter) 57 | counter -= 1 58 | counter += 1 59 | final_list = [] 60 | final_c = 0 61 | test = 0 62 | for item in new: 63 | if final_c == 0: 64 | found = item.find("Class") 65 | if found == -1: 66 | final_list.append(item) 67 | else: 68 | final_c = 1 69 | elif "TimeTest" in item: 70 | out = item.split(" ") 71 | test = out[1] 72 | break 73 | predictions = [] 74 | for item in final_list: 75 | final = item.split(" ") 76 | predictions.append([float(final[0]), float(final[1])]) 77 | return predictions, train, test 78 | -------------------------------------------------------------------------------- /ets/algorithms/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import os 3 | import sys 4 | from cmath import nan 5 | from typing import Sequence, Tuple, Optional 6 | from os import path 7 | import numpy as np 8 | import pandas as pd 9 | from scipy.io.arff import loadarff 10 | from sklearn import preprocessing 11 | 12 | 13 | def arff_parser(file_name): 14 | """ 15 | 16 | Program that reads arff files and turns it into dataframes readble for our framework 17 | 18 | :param file_name: Name of the .arff file 19 | :param type_file: 0 for train file and 1 for test 20 | """ 21 | 22 | files = os.listdir("./data/UCR_UEA") 23 | for file in files: 24 | if ".py" in file: 25 | continue 26 | if file in file_name: 27 | # read the data 28 | raw_data = loadarff(file_name) 29 | df = pd.DataFrame(raw_data[0]) 30 | # encode the labels 31 | labels = df.iloc[:, -1] 32 | encoder = preprocessing.LabelEncoder() 33 | new = pd.Series(encoder.fit_transform(labels), name="Class") 34 | df.drop(df.columns[[-1]], axis=1, inplace=True) 35 | df['Class'] = new 36 | new_df = None 37 | # prepare the new dataframe where each (number_of_variable) rows will represent a time-series 38 | columns = None 39 | for index, row in df.iterrows(): 40 | label = [row[-1]] 41 | if len(row) > 2: 42 | attributes = [row[:-1]] 43 | variables = 1 44 | else: 45 | attributes = row[0] 46 | variables = len(attributes) 47 | attributes = np.asarray(attributes) 48 | if columns is None: 49 | columns = ['Class'] + list(range(0, len(attributes[0]))) 50 | for attribute in attributes: 51 | attribute = label + list(attribute) 52 | if new_df is None: 53 | new_df = pd.DataFrame(np.reshape(attribute, (1, len(attribute))), columns=columns) 54 | else: 55 | # data = np.reshape(attribute, (1, len(attribute))) 56 | data = pd.Series(attribute, index=columns, name=str(index)) 57 | new_df = new_df.append(data) 58 | new_df = nan_handler(new_df) 59 | return new_df, variables 60 | return None,None 61 | 62 | 63 | def nan_handler(df: pd.DataFrame): 64 | pd.set_option("display.max_rows", None, "display.max_columns", None) 65 | df = df.reset_index(drop =True) 66 | for index_r, row in df.iterrows(): # for each row 67 | prev = 0 68 | next = 0 69 | for index_c, item in row.iteritems(): # for each NaN 70 | if math.isnan(item): 71 | for index_a, real in row[index_c:].iteritems(): # find the next not NaN 72 | if not math.isnan(real): 73 | next = real 74 | break 75 | average = (next + prev) / 2 76 | prev = average 77 | df.iloc[int(index_r), index_c+1] = average 78 | else: 79 | prev = item 80 | return df 81 | 82 | def earliness(predictions: Sequence[Tuple[int, int]], ts_length: int) -> Optional[float]: 83 | """ 84 | Computes the earliness. 85 | 86 | :param predictions: a sequence of prediction tuples of the form (timestamp, class) 87 | :param ts_length: the length of the time-series 88 | :return: the mean timestamp in which predictions are made 89 | """ 90 | 91 | # If the time-series length is zero or no predictions are provided, 92 | # the earliness can not be defined. 93 | if ts_length == 0 or not predictions: 94 | return None 95 | 96 | return sum([(t) / (ts_length + 1) for t, _ in predictions]) / len(predictions) 97 | 98 | 99 | def DataSetCreation_EDSC(dimension, rowtraining, rowtesting, classes, numbers): 100 | """Code created in order to run the ECTS and EDSC static code. It created the DatasetInformation.h dynamically""" 101 | f = open("C_files/edsc/DataSetInformation.h", "w+") 102 | f.write("#include \n\n") 103 | f.write("const int DIMENSION = {};\n".format(dimension)) 104 | f.write("const int ROWTRAINING = {};\n".format(rowtraining)) 105 | f.write("const int ROWTESTING = {};\n".format(rowtesting)) 106 | f.write( 107 | """const char* trainingFileName="C_files/edsc/Data/train";\nconst char* testingFileName="C_files/edsc/Data/test";\nconst char* resultFileName="C_files/edsc/Data/result.txt";\nconst char* path ="C_files/edsc";\n""") 108 | f.write("const int NofClasses = {};\n".format(len(classes))) 109 | f.write("const int Classes[] = {") 110 | f.write(str(int(classes[0]))) 111 | for i in classes[1:]: 112 | f.write(",{}".format(int(i))) 113 | f.write("};\n") 114 | f.write("const int ClassIndexes[] = {") 115 | sum = 0 116 | f.write("{}".format(sum)) 117 | for index, values in list(numbers.items())[:-1]: 118 | sum += int(values) 119 | f.write(",{}".format(sum)) 120 | f.write("};\n") 121 | f.write("const int ClassNumber[] = {") 122 | f.write("{}".format(list(numbers.items())[0][1])) 123 | for index, value in list(numbers.items())[1:]: 124 | f.write(",{}".format(int(value))) 125 | f.write("};\n") 126 | f.close() 127 | 128 | 129 | def topy(train, train_labels, test, timesteps): 130 | """ 131 | Preprocessign data for the MLSTM 132 | """ 133 | training = [] 134 | variables = len(train) 135 | classes = train_labels.value_counts() 136 | classes = classes.count() 137 | for index in range(train[0].shape[0]): 138 | feature_list = [] 139 | for feature in train: 140 | feature_list.append(feature.iloc[index].tolist()) 141 | training.append(feature_list) 142 | testing = [] 143 | for index in range(test[0].shape[0]): 144 | feature_list = [] 145 | for feature in test: 146 | feature_list.append(feature.iloc[index].tolist()) 147 | testing.append(feature_list) 148 | train_labels = train_labels.tolist() 149 | path = "./ets/algorithms/MLSTM/data/current_dataset" 150 | try: 151 | os.mkdir(path, 0o755) 152 | except OSError: 153 | print("Creation of the directory %s failed" % path) 154 | else: 155 | print("Successfully created the directory %s" % path) 156 | np.save('./ets/algorithms/MLSTM/data/current_dataset/X_test.npy', testing) 157 | np.save('./ets/algorithms/MLSTM/data/current_dataset/y_train.npy', train_labels) 158 | np.save('./ets/algorithms/MLSTM/data/current_dataset/X_train.npy', training) 159 | f2 = open("./ets/algorithms/MLSTM/utils/constants.txt", "w") 160 | f2.write("TRAIN_FILES=./ets/algorithms/MLSTM/data/current_dataset/\n") 161 | f2.write("TEST_FILES=./ets/algorithms/MLSTM/data/current_dataset/\n") 162 | f2.write("MAX_NB_VARIABLES=" + str(variables) + "\n") 163 | f2.write("MAX_TIMESTEPS_LIST=" + str(timesteps) + "\n") 164 | f2.write("NB_CLASSES_LIST=" + str(classes) + "\n") 165 | f2.close() 166 | 167 | 168 | def temp_accuracy(predictions: Sequence[int], ground_truth_labels: Sequence[int]) -> Optional[float]: 169 | """ 170 | Computes the accuracy. 171 | 172 | :param predictions: a sequence of prediction tuples of the form (timestamp, class) 173 | :param ground_truth_labels: a sequence of ground truth labels 174 | :return: the percentage of correctly classified instances 175 | """ 176 | 177 | # If no predictions or ground truth is provided, 178 | # the accuracy can not be defined. 179 | if not ground_truth_labels or not list(predictions): 180 | return None 181 | 182 | correct = sum([1 for (prediction, y) in zip(predictions, ground_truth_labels) if prediction == y]) 183 | return correct / len(ground_truth_labels) 184 | 185 | 186 | def accuracy(predictions: Sequence[Tuple[int, int]], ground_truth_labels: Sequence[int]) -> Optional[float]: 187 | """ 188 | Computes the accuracy. 189 | 190 | :param predictions: a sequence of prediction tuples of the form (timestamp, class) 191 | :param ground_truth_labels: a sequence of ground truth labels 192 | :return: the percentage of correctly classified instances 193 | """ 194 | 195 | # If no predictions or ground truth is provided, 196 | # the accuracy can not be defined. 197 | if not ground_truth_labels or not predictions: 198 | return None 199 | 200 | correct = sum([1 for ((_, prediction), y) in zip(predictions, ground_truth_labels) if prediction == y]) 201 | return correct / len(ground_truth_labels) 202 | 203 | 204 | def harmonic_mean(acc: float, earl: float): 205 | """ 206 | Computes the harmonic mean as illustrated by Patrick Schäfer et al. 2020 207 | "TEASER: early and accurate time series classification" 208 | 209 | :param acc: The accuracy of the prediction 210 | :param earl: The earliness of the prediction 211 | """ 212 | return (2 * (1 - earl) * acc) / ((1 - earl) + acc) 213 | 214 | 215 | def counts(target_class: int, 216 | predictions: Sequence[Tuple[int, int]], 217 | ground_truth_labels: Sequence[int]) -> Tuple[int, int, int, int]: 218 | """ 219 | Counts the correct and erroneous predictions according to a given target class. 220 | 221 | :param target_class: a class of interest 222 | :param predictions: a sequence of prediction tuples of the form (timestamp, class) 223 | :param ground_truth_labels: a sequence of ground truth labels 224 | :return: a tuple holding the true positives, true negatives, false positives, false negatives. 225 | """ 226 | 227 | tp, tn, fp, fn = 0, 0, 0, 0 228 | for ((_, prediction), y) in zip(predictions, ground_truth_labels): 229 | if prediction == target_class and y == target_class: 230 | tp += 1 231 | elif prediction != target_class and y != target_class: 232 | tn += 1 233 | elif prediction == target_class and y != target_class: 234 | fp += 1 235 | else: 236 | fn += 1 237 | 238 | return tp, tn, fp, fn 239 | 240 | 241 | def precision(tp: int, fp: int) -> Optional[float]: 242 | """ 243 | Computes the precision. 244 | 245 | :param tp: true positives 246 | :param fp: false positives 247 | :return: a precision value, or None if counts are zero 248 | """ 249 | try: 250 | return tp / (tp + fp) 251 | except ZeroDivisionError: 252 | return 0 253 | 254 | 255 | def recall(tp: int, fn: int) -> Optional[float]: 256 | """ 257 | Computes the recall. 258 | 259 | :param tp: true positives 260 | :param fn: false negatives 261 | :return: a recall value, or None if counts are zero 262 | """ 263 | try: 264 | return tp / (tp + fn) 265 | except ZeroDivisionError: 266 | return 0 267 | 268 | 269 | def f_measure(tp: int, fp: int, fn: int, beta: int = 1) -> Optional[float]: 270 | """ 271 | Computes the F-measure. 272 | 273 | :param tp: true positives 274 | :param fp: false positives 275 | :param fn: false negatives 276 | :param beta: beta parameter (default is 1) 277 | :return: f-beta measure, or None if precision or recall is zero 278 | """ 279 | 280 | pr = precision(tp, fp) 281 | re = recall(tp, fn) 282 | if pr is None or re is None or (pr == 0 and re == 0): 283 | return 0 284 | else: 285 | return ((1 + beta ** 2) * pr * re) / (beta ** 2 * pr + re) 286 | 287 | 288 | # 289 | # Transformation functions 290 | # 291 | 292 | 293 | def df_merge(df_seq: Sequence[pd.DataFrame]) -> pd.DataFrame: 294 | """ 295 | Merge a list of data frames by computing their average. 296 | 297 | :param df_seq: a sequence of data frames 298 | :return: a data frame holding the average of the given data frames 299 | """ 300 | df_sum = pd.DataFrame() 301 | for df in df_seq: 302 | df_sum = df.add(df_sum, fill_value=0) 303 | return df_sum.div(len(df_seq)) 304 | 305 | 306 | def df_dimensionality_reduction(df: pd.DataFrame, dimensions: int) -> pd.DataFrame: 307 | """ 308 | Dimensionality reduction on a data frame using the Piecewise Aggregate Approximation (PAA). 309 | 310 | :param df: a data frame to reduce 311 | :param dimensions: number of dimensions to retain 312 | :return: a reduced data frame 313 | """ 314 | 315 | columns = df.shape[1] 316 | 317 | # If the df columns are already less than the desired dimensions, we should not change anything 318 | if columns <= dimensions: 319 | return df 320 | 321 | # Compute segment size 322 | segment_size = round(columns / dimensions) 323 | 324 | reduced_data = pd.DataFrame() 325 | for _, row in df.iterrows(): 326 | 327 | pos = 0 328 | aggregated_series = [] 329 | 330 | for d in range(0, dimensions): 331 | 332 | # For the final dimension, find the average of the remaining timestamps 333 | if d == dimensions - 1: 334 | avg = sum(row[pos:columns]) / (columns - pos) 335 | aggregated_series.append(avg) 336 | 337 | # Or else calculate the average of segment size 338 | else: 339 | avg = sum(row[pos:pos + segment_size]) / segment_size 340 | aggregated_series.append(avg) 341 | pos = pos + segment_size 342 | 343 | reduced_data = reduced_data.append(pd.Series(aggregated_series), ignore_index=True) 344 | 345 | return reduced_data 346 | -------------------------------------------------------------------------------- /ets/cli.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | import time 4 | from collections import Counter 5 | from datetime import timedelta 6 | from typing import Set, List, Tuple, Optional 7 | import click 8 | import coloredlogs 9 | import pandas as pd 10 | from sklearn.model_selection import StratifiedKFold 11 | import pickle as pkl 12 | import ets.algorithms.utils as utils 13 | from ets.algorithms.early_classifier import EarlyClassifier 14 | from ets.algorithms.ecec import ECEC 15 | from ets.algorithms.non_myopic import Trigger 16 | from ets.algorithms.ects import ECTS 17 | from ets.algorithms.edsc_c import EDSC_C 18 | from ets.algorithms.mlstm import MLSTM 19 | from ets.algorithms.teaser import TEASER 20 | 21 | # Configure the logger (change level to DEBUG for more information) 22 | logger = logging.getLogger(__name__) 23 | coloredlogs.install(level=logging.INFO, logger=logger, 24 | fmt='%(asctime)s - %(hostname)s - %(name)s[%(process)d] - [%(levelname)s]: %(message)s') 25 | 26 | delim_1 = " " 27 | delim_2 = " " 28 | 29 | 30 | class Config(object): 31 | def __init__(self): 32 | self.cv_data: Optional[List[pd.DataFrame]] = None 33 | self.cv_labels: Optional[pd.DataFrame] = None 34 | self.train_data: Optional[List[pd.DataFrame]] = None 35 | self.train_labels: Optional[pd.DataFrame] = None 36 | self.test_data: Optional[List[pd.DataFrame]] = None 37 | self.test_labels: Optional[pd.DataFrame] = None 38 | self.classes: Optional[Set[int]] = None 39 | self.num_classes: Optional[int] = None 40 | self.ts_length: Optional[int] = None 41 | self.variate: Optional[int] = None 42 | self.strategy: Optional[str] = None 43 | self.timestamps: Optional[List[int]] = None 44 | self.folds: Optional[int] = None 45 | self.target_class: Optional[int] = None 46 | self.output: Optional[click.File] = None 47 | self.java: Optional[bool] = None 48 | self.file: Optional[click.File] = None 49 | self.splits: Optional[dict] = None 50 | self.make_cv: Optional[bool] = None 51 | 52 | 53 | pass_config = click.make_pass_decorator(Config, ensure=True) 54 | 55 | 56 | @click.group() 57 | @click.option('-i', '--input-cv-file', type=click.Path(exists=True, dir_okay=False), 58 | help='Input CSV data file for cross-validation.') 59 | @click.option('-t', '--train-file', type=click.Path(exists=True, dir_okay=False), 60 | help='Train CSV data file.') 61 | @click.option('-e', '--test-file', type=click.Path(exists=True, dir_okay=False), 62 | help='Test CSV data file.') 63 | @click.option('-s', '--separator', type=click.STRING, default=',', show_default=True, 64 | help='Separator of the data files.') 65 | @click.option('-d', '--class-idx', type=click.IntRange(min=0), 66 | help='Class column index of the data files.') 67 | @click.option('-h', '--class-header', type=click.STRING, 68 | help='Class column header of the data files.') 69 | @click.option('-z', '--zero-replacement', type=click.FLOAT, default=1e-10, show_default=True, 70 | help='Zero values replacement.') 71 | @click.option('-r', '--reduction', type=click.IntRange(min=1), default=1, show_default=True, 72 | help='Dimensionality reduction.') 73 | @click.option('-p', '--percentage', type=click.FloatRange(min=0, max=1), multiple=True, 74 | help='Time-series percentage to be used for early prediction (multiple values can be given).') 75 | @click.option('-v', '--variate', type=click.IntRange(min=1), default=1, show_default=True, 76 | help='Number of series (attributes) per example.') 77 | @click.option('-g', '--strategy', type=click.Choice(['merge', 'vote', 'normal'], case_sensitive=False), 78 | help='Multi-variate training strategy.') 79 | @click.option('-f', '--folds', type=click.IntRange(min=2), default=5, show_default=True, 80 | help='Number of folds for cross-validation.') 81 | @click.option('-c', '--target-class', type=click.INT, 82 | help='Target class for computing counts. -1 stands for f1 for each class') 83 | @click.option('--java', is_flag=True, 84 | help='Algorithm implementation in java') 85 | @click.option('--cplus', is_flag=True, 86 | help='Algorithm implementation in C++') 87 | @click.option('--splits', type=click.Path(exists=True, dir_okay=False), help='Provided fold-indices file' 88 | ) 89 | @click.option('--make-cv', is_flag=True, 90 | help='If the dataset is divided and cross-validation is wanted' 91 | ) 92 | @click.option('-o', '--output', type=click.File(mode='w'), default='-', required=False, 93 | help='Results file (if not provided results shall be printed in the standard output).') 94 | @pass_config 95 | def cli(config: Config, 96 | input_cv_file: click.Path, 97 | train_file: click.Path, 98 | test_file: click.Path, 99 | separator: str, 100 | class_idx: int, 101 | class_header: str, 102 | zero_replacement: float, 103 | reduction: int, 104 | percentage: List[float], 105 | variate: int, 106 | strategy: click.Choice, 107 | folds: int, 108 | target_class: int, 109 | java: bool, 110 | cplus: bool, 111 | splits: click.Path, 112 | output: click.File, 113 | make_cv: bool) -> None: 114 | """ 115 | Library of Early Time-Series Classification algorithms. 116 | """ 117 | 118 | # Store generic parameters 119 | config.variate = variate 120 | config.strategy = strategy 121 | config.folds = folds 122 | config.target_class = target_class 123 | config.output = output 124 | config.java = java 125 | config.cplus = cplus 126 | config.splits = None 127 | config.make_cv = make_cv 128 | # Check if class header or class index is specified. 129 | if class_header is not None: 130 | class_column = class_header 131 | elif class_idx is not None: 132 | class_column = class_idx 133 | else: 134 | logger.error('Either class column header or class column index should be given.') 135 | 136 | file = None 137 | df = None 138 | if config.make_cv: 139 | config.file = train_file 140 | file = train_file 141 | 142 | try: 143 | if ".arff" in file: 144 | train, variate = utils.arff_parser(file) 145 | config.variate = variate 146 | # Open the train file and load the time-series data 147 | else: 148 | train = pd.read_csv(file, sep=separator, header=None if class_header is None else 0, engine='python') 149 | print(train.shape) 150 | file = test_file 151 | if ".arff" in file: 152 | test, _ = utils.arff_parser(file) 153 | else: 154 | # Open the test file and load the time-series data 155 | test = pd.read_csv(file, sep=separator, header=None if class_header is None else 0, engine='python') 156 | print(test.shape) 157 | df = pd.concat([train, test]).reset_index(drop=True) 158 | input_cv_file = True 159 | except pd.errors.ParserError: 160 | logger.error("Cannot parse file '" + str(file) + "'.") 161 | sys.exit(-1) 162 | 163 | if input_cv_file is not None: 164 | config.file = input_cv_file 165 | logger.warning("Found input CSV file for cross-validation. Ignoring options '-t' and '-e'.") 166 | try: 167 | if splits is not None: 168 | with open(str(splits), "rb") as file: 169 | config.splits = pkl.load(file) 170 | # arff file support 171 | if not config.make_cv: 172 | if ".arff" in config.file: 173 | df, variate = utils.arff_parser(file) 174 | config.variate = variate 175 | # Open the file and load the time-series data 176 | else: 177 | df = pd.read_csv(input_cv_file, sep=separator, header=None if class_header is None else 0, 178 | engine='python') 179 | logger.info("CSV file '" + str(input_cv_file) + "' for CV has dimensions " + str(df.shape) + ".") 180 | logger.debug('\n{}'.format(df)) 181 | # Obtain the time-series (replace 0s in order to avoid floating exceptions) 182 | data = df.drop([class_column], axis=1).replace(0, zero_replacement).T.reset_index(drop=True).T 183 | # Check if the data frame contains multi-variate time-series examples 184 | if variate > 1: 185 | config.cv_data = list() 186 | logger.info('Found ' + str(variate) + ' time-series per example.') 187 | for start in range(variate): 188 | config.cv_data.append(data.iloc[start::variate].reset_index(drop=True)) 189 | else: 190 | config.cv_data = [data] 191 | 192 | # Obtain the labels and compute unique classes 193 | config.cv_labels = df[class_column].iloc[::variate].reset_index(drop=True) 194 | config.classes = set(config.cv_labels.unique()) 195 | config.num_classes = len(config.classes) 196 | logger.info('Found ' + str(config.num_classes) + ' classes: ' + str(config.classes)) 197 | if config.target_class and config.target_class != -1 and config.target_class not in config.classes: 198 | logger.error("Target class '" + str(target_class) + "' does not exist in found classes.") 199 | sys.exit(1) 200 | 201 | # Store time-series length and define the timestamps used for early prediction 202 | config.ts_length = data.shape[1] 203 | if percentage: 204 | percentage += (1,) 205 | config.timestamps = sorted(list(set([int(p * (config.ts_length - 1)) for p in percentage]))) 206 | logger.info('Found timestamps ' + str(config.timestamps) + '.') 207 | else: 208 | config.timestamps = range(0, config.ts_length) 209 | logger.info( 210 | 'No percentages found, using all timestamps in range [0,' + str(config.ts_length - 1) + '].') 211 | 212 | if reduction != 1: 213 | logger.info("Dimensionality reduction from " + str(config.ts_length) + " to " + str(reduction) + "...") 214 | config.cv_data = [utils.df_dimensionality_reduction(df, reduction) for df in config.cv_data] 215 | 216 | except pd.errors.ParserError: 217 | logger.error("Cannot parse file '" + str(input_cv_file) + "'.") 218 | sys.exit(-1) 219 | 220 | elif (train_file is not None) and (test_file is not None): 221 | if splits is not None: 222 | logger.info("Ignoring the fold indices file provided.") 223 | try: 224 | config.file = train_file 225 | file = train_file 226 | 227 | if ".arff" in file: 228 | df, variate = utils.arff_parser(file) 229 | config.variate = variate 230 | # Open the train file and load the time-series data 231 | else: 232 | df = pd.read_csv(file, sep=separator, header=None if class_header is None else 0, engine='python') 233 | logger.info("CSV file '" + str(file) + "' has dimensions " + str(df.shape) + ".") 234 | logger.debug('\n{}'.format(df)) 235 | if not config.java: 236 | df = (df.sort_values(by=[0])).reset_index(drop=True) 237 | # Obtain the time-series (replace 0s in order to avoid floating exceptions) 238 | data = df.drop([class_column], axis=1).replace(0, zero_replacement).T.reset_index(drop=True).T 239 | 240 | # Check if the data frame contains multi-variate time-series examples 241 | if variate > 1: 242 | config.train_data = list() 243 | logger.info('Found ' + str(variate) + ' time-series per example.') 244 | for start in range(variate): 245 | config.train_data.append(data.iloc[start::variate].reset_index(drop=True)) 246 | else: 247 | config.train_data = [data] 248 | # Obtain the train labels and compute unique classes 249 | config.train_labels = df[class_column].iloc[::variate].reset_index(drop=True) 250 | config.classes = set(config.train_labels.unique()) 251 | config.num_classes = len(config.classes) 252 | logger.info('Found ' + str(config.num_classes) + ' classes: ' + str(config.classes)) 253 | if config.target_class and config.target_class not in config.classes and config.target_class != -1: 254 | logger.error("Target class '" + str(target_class) + "' does not exist in found classes.") 255 | sys.exit(1) 256 | 257 | file = test_file 258 | if ".arff" in file: 259 | df, _ = utils.arff_parser(file) 260 | else: 261 | # Open the test file and load the time-series data 262 | df = pd.read_csv(file, sep=separator, header=None if class_header is None else 0, engine='python') 263 | logger.info("CSV file '" + str(file) + "' has dimensions " + str(df.shape) + ".") 264 | logger.debug('\n{}'.format(df)) 265 | # Obtain the time-series (replace 0s in order to avoid floating exceptions) 266 | data = df.drop([class_column], axis=1).replace(0, zero_replacement).T.reset_index(drop=True).T 267 | # Check if the data frame contains multi-variate time-series examples 268 | if variate > 1: 269 | config.test_data = list() 270 | for start in range(variate): 271 | config.test_data.append(data.iloc[start::variate].reset_index(drop=True)) 272 | else: 273 | config.test_data = [data] 274 | 275 | # Obtain the test labels 276 | config.test_labels = df[class_column].iloc[::variate].reset_index(drop=True) 277 | test_classes = set(config.test_labels.unique()) 278 | 279 | if config.classes != test_classes: 280 | logger.error('Train classes ' + str(config.classes) 281 | + ' do not match the test classes ' + str(test_classes) + '.') 282 | sys.exit(-1) 283 | 284 | # Store time-series length and define the timestamps used for early prediction 285 | config.ts_length = data.shape[1] 286 | if percentage: 287 | percentage += (1,) 288 | config.timestamps = sorted(list(set([int(p * (config.ts_length - 1)) for p in percentage]))) 289 | logger.info('Found timestamps ' + str(config.timestamps) + '.') 290 | else: 291 | config.timestamps = range(0, config.ts_length) 292 | logger.info( 293 | 'No percentages found, using all timestamps in range [0,' + str(config.ts_length - 1) + '].') 294 | 295 | if reduction != 1: 296 | logger.info("Dimensionality reduction from " + str(config.ts_length) + " to " + str(reduction) + "...") 297 | config.train_data = [utils.df_dimensionality_reduction(df, reduction) for df in config.train_data] 298 | config.test_data = [utils.df_dimensionality_reduction(df, reduction) for df in config.test_data] 299 | 300 | except pd.errors.ParserError: 301 | logger.error("Cannot parse file '" + str(file) + "'.") 302 | sys.exit(-1) 303 | else: 304 | logger.error("No input data file provided. " 305 | "Use options '-i' / '--input-cv-file' or '-t' / --train-file and 'e' / '--test-file'") 306 | sys.exit(-1) 307 | 308 | 309 | @cli.command() 310 | @click.option('-s', '--class-no', type=click.IntRange(min=1), default=20, show_default=True, 311 | help='Number of classifiers') 312 | @click.option('-n', '--normalize', is_flag=True, 313 | help='Normalized version of the method') 314 | @pass_config 315 | def teaser(config: Config, class_no: int, normalize: bool) -> None: 316 | """ 317 | Run 'TEASER' algorithm. 318 | """ 319 | logger.info("Running teaser ...") 320 | classifier = TEASER(config.timestamps, class_no, normalize) 321 | if config.cv_data is not None: 322 | cv(config, classifier) 323 | else: 324 | train_and_test(config, classifier) 325 | 326 | 327 | @cli.command() 328 | @click.option('-u', '--support', type=click.FloatRange(min=0, max=1), default=0.0, show_default=True, 329 | help='Support threshold.') 330 | @click.option('--relaxed/--no-relaxed', default=False, 331 | help='Run relaxed ECTS.') 332 | @pass_config 333 | def ects(config: Config, support: float, relaxed: bool) -> None: 334 | """ 335 | Run 'ECTS' algorithm. 336 | """ 337 | 338 | logger.info("Running ECTS ...") 339 | classifier = ECTS(config.timestamps, support, relaxed) 340 | if config.cv_data is not None: 341 | cv(config, classifier) 342 | else: 343 | train_and_test(config, classifier) 344 | 345 | 346 | @cli.command() 347 | @pass_config 348 | def edsccplus(config: Config) -> None: 349 | """ 350 | Run 'EDSC' algorithm. 351 | """ 352 | classifier = EDSC_C(config.timestamps) 353 | logger.info("Running EDSC with CHE...") 354 | if config.cv_data is not None: 355 | cv(config, classifier) 356 | else: 357 | train_and_test(config, classifier) 358 | 359 | 360 | @cli.command() 361 | @click.option('-e', '--earliness', type=click.FloatRange(min=0, max=1), default=0, show_default=True, 362 | help='Size of prefix') 363 | @click.option('-f', '--folds', type=click.IntRange(min=1), default=1, show_default=True, 364 | help='Fold for earliness check') 365 | @pass_config 366 | def mlstm(config: Config, earliness, folds) -> None: 367 | """ 368 | Run 'MLSTM' algorithm. 369 | """ 370 | logger.info("Running MLSTM ...") 371 | if earliness == 0: 372 | classifier = MLSTM(config.timestamps, None, folds) 373 | else: 374 | classifier = MLSTM(config.timestamps, [earliness], folds) 375 | if config.cv_data is not None: 376 | cv(config, classifier) 377 | else: 378 | train_and_test(config, classifier) 379 | 380 | 381 | @cli.command() 382 | @pass_config 383 | def ecec(config: Config) -> None: 384 | """ 385 | Run 'ECEC' algorithm. 386 | """ 387 | logger.info("Running ECEC ...") 388 | classifier = ECEC(config.timestamps) 389 | if config.cv_data is not None: 390 | cv(config, classifier) 391 | else: 392 | train_and_test(config, classifier) 393 | 394 | 395 | @cli.command() 396 | @click.option('-c', '--clusters', type=click.IntRange(min=0), default=3, show_default=True, 397 | help='Number of clusters') 398 | @click.option('-t', '--cost-time', type=click.FloatRange(min=0, max=1), default=0.001, show_default=True, 399 | help='Cost time parameter') 400 | @click.option('-l', '--lamb', type=click.FloatRange(min=0), default=100, show_default=True, 401 | help='Size of prefix') 402 | @click.option('-r', '--random-state', is_flag=True, 403 | help='Random state') 404 | @pass_config 405 | def economy_k(config: Config, clusters, cost_time, lamb, random_state) -> None: 406 | """ 407 | Run 'ECONOMY-k' algorithm. 408 | """ 409 | logger.info("Running ECONOMY-k ...") 410 | classifier = Trigger(clusters, cost_time, lamb, random_state) 411 | if config.cv_data is not None: 412 | cv(config, classifier) 413 | else: 414 | train_and_test(config, classifier) 415 | 416 | 417 | def cv(config: Config, classifier: EarlyClassifier) -> None: 418 | sum_accuracy, sum_earliness, sum_precision, sum_recall, sum_f1 = 0, 0, 0, 0, 0 419 | all_predictions: List[Tuple[int, int]] = list() 420 | all_labels: List[int] = list() 421 | if config.splits: 422 | ind = [] 423 | for key in config.splits.keys(): 424 | ind.append((config.splits[key][0], config.splits[key][1])) 425 | indices = zip(ind, range(1, config.folds + 1)) 426 | else: 427 | print("Folds : {}".format(config.folds)) 428 | indices = zip(StratifiedKFold(config.folds).split(config.cv_data[0], config.cv_labels), 429 | range(1, config.folds + 1)) 430 | count = 0 431 | for ((train_indices, test_indices), i) in indices: 432 | predictions = [] 433 | count += 1 434 | click.echo('== Fold ' + str(i), file=config.output) 435 | if config.variate == 1 or config.strategy == 'merge' or config.strategy == 'normal': 436 | 437 | """ Merge is a method that turns a multivariate time-series to a univariate """ 438 | if config.variate > 1 and config.strategy == 'merge': 439 | logger.info("Merging multivariate time-series ...") 440 | config.cv_data = [utils.df_merge(config.cv_data)] 441 | """ Normal is used for algorithms that support multivariate time-series """ 442 | if config.variate > 1 and config.strategy == 'normal': 443 | fold_train_data = [config.cv_data[i].iloc[train_indices].reset_index(drop=True) for i in 444 | range(0, config.variate)] 445 | fold_test_data = [config.cv_data[i].iloc[test_indices].reset_index(drop=True) for i in 446 | range(0, config.variate)] 447 | fold_train_labels = config.cv_labels[train_indices].reset_index(drop=True) 448 | 449 | else: 450 | fold_train_data = config.cv_data[0].iloc[train_indices].reset_index(drop=True) 451 | fold_train_labels = config.cv_labels[train_indices].reset_index(drop=True) 452 | fold_test_data = config.cv_data[0].iloc[test_indices].reset_index(drop=True) 453 | 454 | """In case we call algorithms implemented in Java (TEASER, ECTS)""" 455 | if config.java is True: 456 | 457 | temp = pd.concat([fold_train_labels, fold_train_data], axis=1, sort=False) 458 | temp.to_csv('train', index=False, header=False, sep=delim_1) 459 | 460 | temp2 = pd.concat([config.cv_labels[test_indices].reset_index(drop=True), fold_test_data], axis=1, 461 | sort=False) 462 | temp2.to_csv('test', index=False, header=False, sep=delim_2) 463 | res = classifier.predict(pd.DataFrame()) 464 | predictions = res[0] 465 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 466 | file=config.output) 467 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 468 | file=config.output) 469 | 470 | 471 | elif config.cplus is True: 472 | """In case the method is implemented in C++ (EDSC)""" 473 | 474 | fold_test_labels = config.cv_labels[test_indices].reset_index(drop=True) 475 | 476 | classifier.train(fold_train_data, fold_train_labels) 477 | a = fold_train_labels.value_counts() 478 | a = a.sort_index(ascending=False) 479 | 480 | # The EDSC method returns the tuple (predictions, train time, test time) 481 | res = classifier.predict2(test_data=fold_test_data, labels=fold_train_labels, numbers=a, types=0) 482 | predictions = res[0] 483 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 484 | file=config.output) 485 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 486 | file=config.output) 487 | 488 | 489 | elif config.strategy == "normal": 490 | if isinstance(fold_train_data, pd.DataFrame): 491 | fold_train_data = [fold_train_data] 492 | fold_test_data = [fold_test_data] 493 | # Train the MLSTM 494 | result = classifier.true_predict(fold_train_data, fold_test_data, fold_train_labels) 495 | predictions = result[0] 496 | click.echo('Total training time := {}'.format(timedelta(seconds=result[1])), file=config.output) 497 | click.echo('Total testing time := {}'.format(timedelta(seconds=result[2])), file=config.output) 498 | click.echo('Best earl:={}'.format(result[3]), file=config.output) 499 | click.echo('Best cells:={}'.format(result[4]), file=config.output) 500 | else: 501 | """ For the ECTS method """ 502 | # Train the classifier 503 | start = time.time() 504 | classifier.train(fold_train_data, fold_train_labels) 505 | click.echo('Total training time := {}'.format(timedelta(seconds=time.time() - start)), 506 | file=config.output) 507 | 508 | # Make predictions 509 | start = time.time() 510 | predictions = classifier.predict(fold_test_data) 511 | click.echo('Total testing time := {}'.format(timedelta(seconds=time.time() - start)), 512 | file=config.output) 513 | 514 | else: 515 | 516 | """In case of a multivariate cv dataset is passed on one of the univariate based approaches""" 517 | votes = [] 518 | for ii in range(config.variate): 519 | 520 | fold_train_data = config.cv_data[ii].iloc[train_indices].reset_index(drop=True) 521 | fold_train_labels = config.cv_labels[train_indices].reset_index(drop=True) 522 | fold_test_data = config.cv_data[ii].iloc[test_indices].reset_index(drop=True) 523 | 524 | if config.java is True: 525 | """ For the java approaches""" 526 | temp = pd.concat([fold_train_labels, fold_train_data], axis=1, sort=False) 527 | temp.to_csv('train', index=False, header=False, sep=delim_1) 528 | 529 | temp2 = pd.concat([config.cv_labels[test_indices].reset_index(drop=True), fold_test_data], axis=1, 530 | sort=False) 531 | temp2.to_csv('test', index=False, header=False, sep=delim_2) 532 | res = classifier.predict(pd.DataFrame()) # The java methods return the tuple (predictions, 533 | # train time, test time) 534 | 535 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 536 | file=config.output) 537 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 538 | file=config.output) 539 | votes.append(res[0]) 540 | 541 | elif config.cplus is True: 542 | 543 | fold_test_labels = config.cv_labels[test_indices].reset_index(drop=True) 544 | classifier.train(fold_train_data, fold_train_labels) 545 | a = fold_train_labels.value_counts() 546 | a = a.sort_index(ascending=False) 547 | 548 | # The EDSC method returns the tuple (predictions, train time, test time) 549 | res = classifier.predict2(test_data=fold_test_data, labels=fold_test_labels, numbers=a, types=0) 550 | 551 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 552 | file=config.output) 553 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 554 | file=config.output) 555 | votes.append(res[0]) 556 | else: 557 | # Train the classifier 558 | start = time.time() 559 | classifier.train(fold_train_data, fold_train_labels) 560 | click.echo('Total training time := {}'.format(timedelta(seconds=time.time() - start)), 561 | file=config.output) 562 | 563 | # Make predictions 564 | start = time.time() 565 | votes.append(classifier.predict(fold_test_data)) 566 | click.echo('Total testing time := {}'.format(timedelta(seconds=time.time() - start)), 567 | file=config.output) 568 | 569 | # Make predictions from the votes of each test example 570 | for ii in range(len(votes[0])): 571 | max_timestamp = max(map(lambda x: x[ii][0], votes)) 572 | most_predicted = Counter(map(lambda x: x[ii][1], votes)).most_common(1)[0][0] 573 | predictions.append((max_timestamp, most_predicted)) 574 | all_predictions.extend(predictions) 575 | all_labels.extend(config.cv_labels[test_indices]) 576 | 577 | # Calculate accuracy and earliness 578 | accuracy = utils.accuracy(predictions, config.cv_labels[test_indices].tolist()) 579 | sum_accuracy += accuracy 580 | earliness = utils.earliness(predictions, config.ts_length - 1) 581 | sum_earliness += earliness 582 | click.echo('Accuracy: ' + str(round(accuracy, 4)) + ' Earliness: ' + str(round(earliness * 100, 4)) + '%', 583 | file=config.output) 584 | # Calculate counts, precision, recall and f1-score if a target class is provided 585 | if config.target_class == -1: 586 | items = config.cv_labels[train_indices].unique() 587 | for item in items: 588 | click.echo('For the class: ' + str(item), file=config.output) 589 | tp, tn, fp, fn = utils.counts(item, predictions, config.cv_labels[test_indices].tolist()) 590 | click.echo('TP: ' + str(tp) + ' TN: ' + str(tn) + ' FP: ' + str(fp) + ' FN: ' + str(fn), 591 | file=config.output) 592 | precision = utils.precision(tp, fp) 593 | click.echo('Precision: ' + str(round(precision, 4)), file=config.output) 594 | recall = utils.recall(tp, fn) 595 | click.echo('Recall: ' + str(round(recall, 4)), file=config.output) 596 | f1 = utils.f_measure(tp, fp, fn) 597 | click.echo('F1-score: ' + str(round(f1, 4)) + "\n", file=config.output) 598 | elif config.target_class: 599 | tp, tn, fp, fn = utils.counts(config.target_class, predictions, config.cv_labels[test_indices].tolist()) 600 | click.echo('TP: ' + str(tp) + ' TN: ' + str(tn) + ' FP: ' + str(fp) + ' FN: ' + str(fn), file=config.output) 601 | precision = utils.precision(tp, fp) 602 | sum_precision += precision 603 | click.echo('Precision: ' + str(round(precision, 4)), file=config.output) 604 | recall = utils.recall(tp, fn) 605 | sum_recall += recall 606 | click.echo('Recall: ' + str(round(recall, 4)), file=config.output) 607 | f1 = utils.f_measure(tp, fp, fn) 608 | sum_f1 += f1 609 | click.echo('F1-score: ' + str(round(f1, 4)), file=config.output) 610 | click.echo('Predictions' + str(predictions), file=config.output) 611 | click.echo('== Macro-average', file=config.output) 612 | macro_accuracy = sum_accuracy / config.folds 613 | macro_earliness = sum_earliness / config.folds 614 | click.echo('Accuracy: ' + str(round(macro_accuracy, 4)) + 615 | ' Earliness: ' + str(round(macro_earliness * 100, 4)) + '%', 616 | file=config.output) 617 | 618 | if config.target_class and config.target_class != -1: 619 | macro_precision = sum_precision / config.folds 620 | macro_recall = sum_recall / config.folds 621 | macro_f1 = sum_f1 / config.folds 622 | click.echo('Precision: ' + str(round(macro_precision, 4)), file=config.output) 623 | click.echo('Recall: ' + str(round(macro_recall, 4)), file=config.output) 624 | click.echo('F1-score: ' + str(round(macro_f1, 4)), file=config.output) 625 | 626 | click.echo('== Micro-average:', file=config.output) 627 | micro_accuracy = utils.accuracy(all_predictions, all_labels) 628 | micro_earliness = utils.earliness(all_predictions, config.ts_length - 1) 629 | click.echo('Accuracy: ' + str(round(micro_accuracy, 4)) + 630 | ' Earliness: ' + str(round(micro_earliness * 100, 4)) + '%', 631 | file=config.output) 632 | 633 | # Calculate counts, precision, recall and f1-score if a target class is provided 634 | if config.target_class and config.target_class != -1: 635 | tp, tn, fp, fn = utils.counts(config.target_class, all_predictions, all_labels) 636 | click.echo('TP: ' + str(tp) + ' TN: ' + str(tn) + ' FP: ' + str(fp) + ' FN: ' + str(fn), file=config.output) 637 | precision = utils.precision(tp, fp) 638 | click.echo('Precision: ' + str(round(precision, 4)), file=config.output) 639 | recall = utils.recall(tp, fn) 640 | click.echo('Recall: ' + str(round(recall, 4)), file=config.output) 641 | f1 = utils.f_measure(tp, fp, fn) 642 | click.echo('F1-score: ' + str(round(f1, 4)), file=config.output) 643 | 644 | 645 | def train_and_test(config: Config, classifier: EarlyClassifier) -> None: 646 | predictions = [] 647 | 648 | if config.variate == 1 or config.strategy == 'merge' or config.strategy == 'normal': 649 | predictions = [] 650 | if config.variate > 1 and config.strategy != "normal": 651 | logger.info("Merging multivariate time-series ...") 652 | config.train_data = [utils.df_merge(config.train_data)] 653 | config.test_data = [utils.df_merge(config.test_data)] 654 | 655 | if config.java is True: 656 | config.train_labels = config.train_labels.astype(int) 657 | temp = pd.concat([config.train_labels.reset_index(drop=True), config.train_data[0].reset_index(drop=True)], 658 | axis=1, sort=False) 659 | temp.to_csv('train', index=False, header=False, sep=delim_1) 660 | temp2 = pd.concat([config.test_labels.reset_index(drop=True), config.test_data[0].reset_index(drop=True)], 661 | axis=1, sort=False) 662 | temp2.to_csv('test', index=False, header=False, sep=delim_2) 663 | res = classifier.predict(pd.DataFrame()) 664 | predictions = res[0] 665 | 666 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 667 | file=config.output) 668 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 669 | file=config.output) 670 | 671 | elif config.cplus is True: 672 | 673 | a = config.train_labels.value_counts() 674 | a = a.sort_index() 675 | classifier.train(config.train_data[0], config.train_labels) 676 | 677 | res = classifier.predict2(test_data=config.test_data[0], labels=config.test_labels, numbers=a, types=1) 678 | predictions = res[0] 679 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 680 | file=config.output) 681 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 682 | file=config.output) 683 | 684 | elif config.strategy == 'normal': 685 | 686 | result = classifier.true_predict(config.train_data, config.test_data, config.train_labels) 687 | predictions = result[0] 688 | click.echo('Total training time := {}'.format(timedelta(seconds=result[1])), file=config.output) 689 | click.echo('Total testing time := {}'.format(timedelta(seconds=result[2])), file=config.output) 690 | click.echo('Best earl:={}'.format(result[3]), file=config.output) 691 | click.echo('Best cells:={}'.format(result[4]), file=config.output) 692 | else: 693 | # Train the classifier 694 | start = time.time() 695 | trip = classifier.train(config.train_data[0], config.train_labels) 696 | click.echo('Total training time := {}'.format(timedelta(seconds=time.time() - start)), file=config.output) 697 | 698 | # Make predictions 699 | start = time.time() 700 | predictions = classifier.predict(config.test_data[0]) 701 | click.echo('Total testing time := {}'.format(timedelta(seconds=time.time() - start)), file=config.output) 702 | 703 | else: 704 | logger.info("Voting over the multivariate time-series attributes ...") 705 | 706 | votes = [] 707 | for i in range(config.variate): 708 | if config.java is True: 709 | temp = pd.concat([config.train_labels, config.train_data[i]], axis=1, sort=False) 710 | temp.to_csv('train', index=False, header=False, sep=delim_1) 711 | temp2 = pd.concat([config.test_labels, config.test_data[i]], axis=1, sort=False) 712 | 713 | temp2.to_csv('test', index=False, header=False, sep=delim_2) 714 | res = classifier.predict(pd.DataFrame()) 715 | 716 | votes.append(res[0]) 717 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 718 | file=config.output) 719 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 720 | file=config.output) 721 | 722 | elif config.cplus is True: 723 | a = config.train_labels.value_counts() 724 | a = a.sort_index() 725 | 726 | classifier.train(config.train_data[i], config.train_labels) 727 | res = classifier.predict2(test_data=config.test_data[i], labels=config.test_labels, numbers=a, types=1) 728 | votes.append(res[0]) 729 | click.echo('Total training time := {}'.format(timedelta(seconds=float(res[1]))), 730 | file=config.output) 731 | click.echo('Total testing time := {}'.format(timedelta(seconds=float(res[2]))), 732 | file=config.output) 733 | else: 734 | # Train the classifier 735 | start = time.time() 736 | trip = classifier.train(config.train_data[i], config.train_labels) 737 | click.echo('Total training time := {}'.format(timedelta(seconds=time.time() - start)), 738 | file=config.output) 739 | 740 | # Make predictions 741 | start = time.time() 742 | votes.append(classifier.predict(config.test_data[i])) 743 | click.echo('Total testing time := {}'.format(timedelta(seconds=time.time() - start)), 744 | file=config.output) 745 | 746 | # Make predictions from the votes of each test example 747 | for i in range(len(votes[0])): 748 | max_timestamp = max(map(lambda x: x[i][0], votes)) 749 | most_predicted = Counter(map(lambda x: x[i][1], votes)).most_common(1)[0][0] 750 | predictions.append((max_timestamp, most_predicted)) 751 | 752 | accuracy = utils.accuracy(predictions, config.test_labels.tolist()) 753 | earliness = utils.earliness(predictions, config.ts_length - 1) 754 | harmonic = utils.harmonic_mean(accuracy, earliness) 755 | click.echo('Accuracy: ' + str(round(accuracy, 4)) + ' Earliness: ' + str(round(earliness * 100, 4)) + '%', 756 | file=config.output) 757 | click.echo('Harmonic mean: ' + str(round(harmonic, 4)), 758 | file=config.output) 759 | 760 | # Calculate counts, precision, recall and f1-score if a target class is provided 761 | if config.target_class == -1: 762 | items = config.train_labels.unique() 763 | for item in items: 764 | click.echo('For the class: ' + str(item), file=config.output) 765 | config.target_class = item 766 | tp, tn, fp, fn = utils.counts(config.target_class, predictions, config.test_labels) 767 | click.echo('TP: ' + str(tp) + ' TN: ' + str(tn) + ' FP: ' + str(fp) + ' FN: ' + str(fn), file=config.output) 768 | precision = utils.precision(tp, fp) 769 | click.echo('Precision: ' + str(round(precision, 4)), file=config.output) 770 | recall = utils.recall(tp, fn) 771 | click.echo('Recall: ' + str(round(recall, 4)), file=config.output) 772 | f1 = utils.f_measure(tp, fp, fn) 773 | click.echo('F1-score: ' + str(round(f1, 4)) + "\n", file=config.output) 774 | elif config.target_class: 775 | tp, tn, fp, fn = utils.counts(config.target_class, predictions, config.test_labels) 776 | click.echo('TP: ' + str(tp) + ' TN: ' + str(tn) + ' FP: ' + str(fp) + ' FN: ' + str(fn), file=config.output) 777 | precision = utils.precision(tp, fp) 778 | click.echo('Precision: ' + str(round(precision, 4)), file=config.output) 779 | recall = utils.recall(tp, fn) 780 | click.echo('Recall: ' + str(round(recall, 4)), file=config.output) 781 | f1 = utils.f_measure(tp, fp, fn) 782 | click.echo('F1-score: ' + str(round(f1, 4)), file=config.output) 783 | click.echo('Predictions' + str(predictions), file=config.output) 784 | 785 | 786 | if __name__ == '__main__': 787 | cli() 788 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | attrs==19.3.0 2 | click==7.1.1 3 | coloredlogs==14.0 4 | coverage==5.0.4 5 | deap==1.3.1 6 | dtw==1.4.0 7 | humanfriendly==8.1 8 | importlib-metadata==1.5.2 9 | joblib==0.14.1 10 | llvmlite==0.31.0 11 | more-itertools==8.2.0 12 | mypy==0.770 13 | mypy-extensions==0.4.3 14 | numba==0.48.0 15 | numpy==1.18.2 16 | packaging==20.3 17 | pandas==1.0.3 18 | pluggy==0.13.1 19 | py==1.8.1 20 | pyparsing==2.4.6 21 | pytest==5.4.1 22 | pytest-cov==2.8.1 23 | python-dateutil==2.8.1 24 | pyts==0.11.0 25 | pytz==2019.3 26 | scikit-learn==0.22.2.post1 27 | scipy==1.4.1 28 | six==1.14.0 29 | sklearn==0.0 30 | typed-ast==1.4.1 31 | typing-extensions==3.7.4.1 32 | wcwidth==0.1.9 33 | zipp==3.1.0 34 | keras==2.3.1 35 | matplotlib==3.3.3 36 | tensorflow==1.14.0 37 | h5py==2.10.0 38 | tslearn == 0.5.1.0 39 | -------------------------------------------------------------------------------- /scripts/download_data.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DATA_FOLDER="../data" 4 | BIO_REPO="https://owncloud.skel.iit.demokritos.gr/index.php/s/5o0E7MZdaabFpjX/download" 5 | UCR_REPO="https://owncloud.skel.iit.demokritos.gr/index.php/s/IVWeJ0UsdPbjhhU/download" 6 | MAR_REPO="https://owncloud.skel.iit.demokritos.gr/index.php/s/Yp6QWTA9LZGEOGY/download" 7 | 8 | if [[ ! -d "${DATA_FOLDER}" ]]; then 9 | 10 | # Create the data folder 11 | mkdir ${DATA_FOLDER} 12 | 13 | 14 | # Download the BIO archive 15 | wget --progress=bar:force --content-disposition -P ${DATA_FOLDER} ${BIO_REPO} 16 | 17 | # Unzip the data 18 | unzip "${DATA_FOLDER}/BioArchive.zip" -d ${DATA_FOLDER} 19 | 20 | # Remove the archive 21 | rm "${DATA_FOLDER}/BioArchive.zip" 22 | 23 | 24 | # Download the UCR archive 25 | wget --progress=bar:force --content-disposition -P ${DATA_FOLDER} ${UCR_REPO} 26 | 27 | # Unzip the data 28 | unzip "${DATA_FOLDER}/UCR_UEA.zip" -d ${DATA_FOLDER} 29 | 30 | # Remove the archive 31 | rm "${DATA_FOLDER}/UCR_UEA.zip" 32 | 33 | 34 | wget --progress=bar:force --content-disposition -P ${DATA_FOLDER} ${MAR_REPO} 35 | 36 | # Unzip the data 37 | unzip "${DATA_FOLDER}/Maritime_data.zip" -d ${DATA_FOLDER} 38 | 39 | # Remove the archive 40 | rm "${DATA_FOLDER}/Maritime_data.zip" 41 | fi 42 | -------------------------------------------------------------------------------- /scripts/organise.py: -------------------------------------------------------------------------------- 1 | from os import listdir 2 | from os.path import isfile, join 3 | import pandas as pd 4 | 5 | files = \ 6 | ['interesting/' + f for f in listdir('interesting') if isfile(join('interesting', f))] 7 | not_interesting_files = \ 8 | ['not_interesting/' + f for f in listdir('not_interesting') if isfile(join('not_interesting', f))] 9 | 10 | files.extend(not_interesting_files) 11 | 12 | alive = pd.DataFrame() 13 | apoptotic = pd.DataFrame() 14 | necrotic = pd.DataFrame() 15 | mts = pd.DataFrame() 16 | 17 | for file in files: 18 | 19 | c = 0 if 'not_interesting' in file else 1 20 | df = pd.read_csv(file) 21 | alive = alive.append(pd.Series([c]).append(df['Alive'], ignore_index=True), ignore_index=True) 22 | apoptotic = apoptotic.append(pd.Series([c]).append(df['Apoptotic'], ignore_index=True), ignore_index=True) 23 | necrotic = necrotic.append(pd.Series([c]).append(df['Necrotic'], ignore_index=True), ignore_index=True) 24 | 25 | dft = pd.concat( 26 | [pd.DataFrame([c, c, c], index=['Alive', 'Apoptotic', 'Necrotic']), df.transpose()[1:]], 27 | ignore_index=True, 28 | axis=1) 29 | mts = mts.append(dft, ignore_index=True) 30 | 31 | alive.to_csv('ALIVE.csv', index=False, header=False) 32 | apoptotic.to_csv('APOPTOTIC.csv', index=False, header=False) 33 | necrotic.to_csv('NECROTIC.csv', index=False, header=False) 34 | mts.to_csv('MTS.csv', index=False, header=False) 35 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_text = fh.read() 5 | 6 | setuptools.setup( 7 | name="ets", 8 | version="0.1", 9 | author="Evgenios Kladis, Evangelos Michelioudakis", 10 | description="A library of early time-series classification algorithms.", 11 | long_description=long_text, 12 | long_description_content_type="text/markdown", 13 | license='GPL3', 14 | packages=setuptools.find_packages(), 15 | entry_points=''' 16 | [console_scripts] 17 | ets=ets.cli:cli 18 | ''', 19 | classifiers=[ 20 | "Programming Language :: Python :: 3", 21 | "GNU General Public License v3': 'License :: OSI Approved :: GNU General Public License v3 (GPLv3", 22 | "Operating System :: OS Independent", 23 | ], 24 | python_requires='>=3.6' 25 | ) 26 | --------------------------------------------------------------------------------