Compare commits
1196 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a8d63b6c8 | ||
|
|
75f401481f | ||
|
|
89c4f67f59 | ||
|
|
a8adf16228 | ||
|
|
328e8e4c69 | ||
|
|
d5c143367d | ||
|
|
f6423056c0 | ||
|
|
c3eb4f7000 | ||
|
|
d29edc677c | ||
|
|
7089301b62 | ||
|
|
c60a356273 | ||
|
|
0e61c514a7 | ||
|
|
313764b3be | ||
|
|
75d9be55de | ||
|
|
197b4c6b18 | ||
|
|
5f179340a8 | ||
|
|
c332eb5a2b | ||
|
|
f14c160f4f | ||
|
|
3f32b3f0eb | ||
|
|
77d17f6264 | ||
|
|
f74e2439e0 | ||
|
|
13445e3522 | ||
|
|
11efa038bd | ||
|
|
f8d23b97be | ||
|
|
44ed6d5674 | ||
|
|
4fb1b8a5a7 | ||
|
|
7533191af7 | ||
|
|
14f9697025 | ||
|
|
93196eb811 | ||
|
|
3b73824842 | ||
|
|
344d7b4699 | ||
|
|
ae0ca486ed | ||
|
|
4b2eedc186 | ||
|
|
e1a52e896c | ||
|
|
fd4300b95a | ||
|
|
3b6b344561 | ||
|
|
a0aa305268 | ||
|
|
e9eb34fabc | ||
|
|
56bd442b31 | ||
|
|
8473b18c3d | ||
|
|
b9aeeda074 | ||
|
|
c342614a81 | ||
|
|
76650c096f | ||
|
|
bd5b07873e | ||
|
|
c9a73fe2a9 | ||
|
|
465e5dfb87 | ||
|
|
9cb872b879 | ||
|
|
661c062bd9 | ||
|
|
aaf0a73486 | ||
|
|
7cfeb5f012 | ||
|
|
4e1269b522 | ||
|
|
79704cdfb4 | ||
|
|
f34f9fb9f7 | ||
|
|
2e0ffcc303 | ||
|
|
422b0000a8 | ||
|
|
754f3a6e07 | ||
|
|
bdf14007b5 | ||
|
|
264c222fe0 | ||
|
|
949d1e3027 | ||
|
|
e034fdf74c | ||
|
|
e2c1aa8b51 | ||
|
|
9a48a40cf1 | ||
|
|
26a82621a2 | ||
|
|
ba04a1d552 | ||
|
|
9ef86072f4 | ||
|
|
19129b289c | ||
|
|
22ad94d281 | ||
|
|
64b9dcf7b5 | ||
|
|
6e3463097d | ||
|
|
1dde863c98 | ||
|
|
2ef81e0673 | ||
|
|
118eb2f1bb | ||
|
|
af2e9ebd82 | ||
|
|
5c14daffe2 | ||
|
|
c6631ad2ed | ||
|
|
5898f1c59e | ||
|
|
c85b9012c6 | ||
|
|
587999755f | ||
|
|
d816208797 | ||
|
|
a4d8c1b49f | ||
|
|
cc5112d405 | ||
|
|
2c0c06639c | ||
|
|
47f359ca9f | ||
|
|
84ae514d7e | ||
|
|
e4ea166d05 | ||
|
|
149589c583 | ||
|
|
03996dd4e8 | ||
|
|
51154f42fe | ||
|
|
611b317057 | ||
|
|
2b8b18583f | ||
|
|
be65949ba2 | ||
|
|
49bbd72d08 | ||
|
|
ffed95eec0 | ||
|
|
26b36714ea | ||
|
|
185fef3fce | ||
|
|
a13a3a4d76 | ||
|
|
8664217a5a | ||
|
|
ea9285dd4f | ||
|
|
9c26566eb0 | ||
|
|
07003e8342 | ||
|
|
bf322322fe | ||
|
|
2e7abffffb | ||
|
|
617aeb912b | ||
|
|
44d4a62631 | ||
|
|
bab69919d2 | ||
|
|
bf24d6ae98 | ||
|
|
840481d215 | ||
|
|
fc02f8a2dc | ||
|
|
95bcff90af | ||
|
|
6e79ba831a | ||
|
|
b92e2252b0 | ||
|
|
3ab8f0b13d | ||
|
|
28cdc10259 | ||
|
|
6750c8b743 | ||
|
|
5a78118396 | ||
|
|
79c7c9e5bb | ||
|
|
0839aed380 | ||
|
|
c2c61eefd9 | ||
|
|
b5fb437aa7 | ||
|
|
b588479f66 | ||
|
|
9da2f3e613 | ||
|
|
2f2ad21de4 | ||
|
|
da85a4e923 | ||
|
|
ad3f49e881 | ||
|
|
9bc2ac4bd0 | ||
|
|
6bab164d80 | ||
|
|
ff4dda2102 | ||
|
|
a6909e389f | ||
|
|
3434083d3e | ||
|
|
cf607e2448 | ||
|
|
6691d5c3f4 | ||
|
|
c55cc809e5 | ||
|
|
24e3c5773e | ||
|
|
811c6ef58b | ||
|
|
4149854633 | ||
|
|
43c073d8c5 | ||
|
|
5d7a69663b | ||
|
|
3e0732dea9 | ||
|
|
0527b17c9d | ||
|
|
1160d0bf25 | ||
|
|
8fc2456c87 | ||
|
|
b3c9e6a0db | ||
|
|
04ace6311b | ||
|
|
060350f64c | ||
|
|
e6de01baaf | ||
|
|
f2557ce530 | ||
|
|
db4c5bc627 | ||
|
|
49f3892942 | ||
|
|
f75d78f686 | ||
|
|
59610c49df | ||
|
|
79b35da308 | ||
|
|
c791894668 | ||
|
|
d7e5095e7c | ||
|
|
4af55518f2 | ||
|
|
25965227b3 | ||
|
|
714901eac5 | ||
|
|
de63993543 | ||
|
|
9f177d7353 | ||
|
|
babf1d7840 | ||
|
|
77136baf2c | ||
|
|
30a306b974 | ||
|
|
6eda06256e | ||
|
|
e27977d416 | ||
|
|
daeee84e4d | ||
|
|
33131e2e13 | ||
|
|
fb5291271e | ||
|
|
4b760762f9 | ||
|
|
71f402ac16 | ||
|
|
d27bfb61b0 | ||
|
|
1d504d6c6c | ||
|
|
6a5eb47789 | ||
|
|
605c23e0dc | ||
|
|
dfafce4cfd | ||
|
|
d8535313eb | ||
|
|
03dfffca15 | ||
|
|
bbb9ce1641 | ||
|
|
1625dab1cb | ||
|
|
5efc1ee3a4 | ||
|
|
c135703655 | ||
|
|
8842176888 | ||
|
|
f1114688a7 | ||
|
|
7c555d5bc6 | ||
|
|
11415f228f | ||
|
|
14a031a1ab | ||
|
|
55ab1c6a22 | ||
|
|
a2146708bd | ||
|
|
0b998d5249 | ||
|
|
0e0f0e75f6 | ||
|
|
7016bee98f | ||
|
|
ffe7af572c | ||
|
|
375a8a97a6 | ||
|
|
cc0722a4aa | ||
|
|
2cd109fb98 | ||
|
|
c449dc6874 | ||
|
|
311f7c8f47 | ||
|
|
612ccd0bb7 | ||
|
|
6f273a8c21 | ||
|
|
a31a978471 | ||
|
|
6321bc20ea | ||
|
|
73d5965961 | ||
|
|
c2fa67757a | ||
|
|
5829eb3cf2 | ||
|
|
9a5489ee15 | ||
|
|
90f7220736 | ||
|
|
084ed6224d | ||
|
|
29ad3ab2c3 | ||
|
|
d1c5280f4b | ||
|
|
00caf2c956 | ||
|
|
c3e56017cc | ||
|
|
3a951d0ab8 | ||
|
|
362eb4bd02 | ||
|
|
e3fa7753f5 | ||
|
|
6f92f1c117 | ||
|
|
e1b2ad2e5e | ||
|
|
a2714fe052 | ||
|
|
4454c7b72a | ||
|
|
5fb09dc0ab | ||
|
|
05b692590d | ||
|
|
a382c1698a | ||
|
|
cc1e608a3d | ||
|
|
f2ef958ebb | ||
|
|
9011acf52b | ||
|
|
3ce33563f2 | ||
|
|
16b9e92328 | ||
|
|
980898f3fb | ||
|
|
5f441a29a8 | ||
|
|
cbabaeba0c | ||
|
|
57987100bc | ||
|
|
a3b2e76230 | ||
|
|
400b1faecc | ||
|
|
97e4dcde98 | ||
|
|
2a6ac6fd34 | ||
|
|
79f2d0cf70 | ||
|
|
2dac506773 | ||
|
|
61db5aa575 | ||
|
|
6b9442a7f8 | ||
|
|
ab68a0ccc7 | ||
|
|
acdd23e789 | ||
|
|
aca0096b33 | ||
|
|
43d7a85bc9 | ||
|
|
8e3ce908fe | ||
|
|
6558ef3273 | ||
|
|
00e7e4eef0 | ||
|
|
51b0e7010c | ||
|
|
39359edbd8 | ||
|
|
04f7fe9c36 | ||
|
|
59d59a968d | ||
|
|
ec2fb5bc48 | ||
|
|
d02bd41623 | ||
|
|
96b17971ac | ||
|
|
845f80ec22 | ||
|
|
d35cab6911 | ||
|
|
5b3ece2ca9 | ||
|
|
f3e2878784 | ||
|
|
7b2e128c91 | ||
|
|
d913cbbfbc | ||
|
|
d47df5c1d8 | ||
|
|
e0a3f1c000 | ||
|
|
13486cf672 | ||
|
|
bbe2b2f0b6 | ||
|
|
e0555d2ddc | ||
|
|
4e86c8c866 | ||
|
|
db7a4e2ada | ||
|
|
7e30ada8c1 | ||
|
|
b398c145a9 | ||
|
|
a23e091be1 | ||
|
|
005b1276d0 | ||
|
|
852c5a4b32 | ||
|
|
c9830cd8b1 | ||
|
|
8cfa752fa0 | ||
|
|
f64516c8d0 | ||
|
|
357c89fa93 | ||
|
|
a08cc8aad4 | ||
|
|
909c6af330 | ||
|
|
fa03aaeb63 | ||
|
|
9911771b02 | ||
|
|
7aafd8f777 | ||
|
|
8a12a78427 | ||
|
|
7cbb9da0e6 | ||
|
|
6f5632dd6e | ||
|
|
435a0425b9 | ||
|
|
3402953633 | ||
|
|
0fd433ff0f | ||
|
|
d4161bdeec | ||
|
|
dda226ab85 | ||
|
|
3d8f2fb1b9 | ||
|
|
8cc8f227c3 | ||
|
|
8c6cbe7608 | ||
|
|
bec7332eea | ||
|
|
54f13ab9e7 | ||
|
|
c05c5bc7bc | ||
|
|
79f9fceb6b | ||
|
|
c211a80633 | ||
|
|
718a9d8c96 | ||
|
|
6499422e90 | ||
|
|
16008ebfb8 | ||
|
|
50337d1906 | ||
|
|
cf2a7851eb | ||
|
|
808e30f9fc | ||
|
|
56f7a414d1 | ||
|
|
f768edfede | ||
|
|
457ff82e33 | ||
|
|
300c16d0f6 | ||
|
|
99dc311f6d | ||
|
|
3ddddfce79 | ||
|
|
130ca7b00c | ||
|
|
f0647ec76d | ||
|
|
5c1af13f84 | ||
|
|
fb41e4e673 | ||
|
|
74bda4bfc5 | ||
|
|
514df14baf | ||
|
|
3a34c53f57 | ||
|
|
ae032b12b4 | ||
|
|
ac8e950227 | ||
|
|
51d8595372 | ||
|
|
bb43177eb1 | ||
|
|
e8560c7909 | ||
|
|
ae969a0e69 | ||
|
|
81dbf564a4 | ||
|
|
2cec10c46f | ||
|
|
b2d705ffb0 | ||
|
|
1540773340 | ||
|
|
4568692daf | ||
|
|
a894ab6898 | ||
|
|
e23a24be8c | ||
|
|
86871d4be9 | ||
|
|
770b3451ca | ||
|
|
04bdbca63f | ||
|
|
416e1434e7 | ||
|
|
10a1517502 | ||
|
|
0df2ed80c8 | ||
|
|
e80d3db64b | ||
|
|
12dc92f7e0 | ||
|
|
e3dc67c6a0 | ||
|
|
0f367a6ade | ||
|
|
c428a93adc | ||
|
|
5c9e50148a | ||
|
|
ced6d45e01 | ||
|
|
0515e4ec28 | ||
|
|
8c220f51fc | ||
|
|
cbf5eba9c0 | ||
|
|
8e0c3b08c7 | ||
|
|
5e309f1ce8 | ||
|
|
7d9457d72f | ||
|
|
f8fff6c6fc | ||
|
|
55e36893cd | ||
|
|
3b246c2420 | ||
|
|
fc4c88fceb | ||
|
|
ec9df13c70 | ||
|
|
ba805d0fca | ||
|
|
ecb3a271be | ||
|
|
51bb556898 | ||
|
|
ae3962f757 | ||
|
|
fdd520d774 | ||
|
|
728b65cec0 | ||
|
|
3d56caaab5 | ||
|
|
b7985466a4 | ||
|
|
803a6fe474 | ||
|
|
5f70b4df7a | ||
|
|
4a16b729fc | ||
|
|
a868d803d0 | ||
|
|
07ed143cd6 | ||
|
|
c7dc0cb50e | ||
|
|
19f5f027a6 | ||
|
|
90bc7f8f6b | ||
|
|
38ba66a5bd | ||
|
|
44d5ac7d37 | ||
|
|
758a77de9c | ||
|
|
be810e4f16 | ||
|
|
ed5781fa55 | ||
|
|
edf68b5933 | ||
|
|
592004b38f | ||
|
|
81257dcfb4 | ||
|
|
84e9ca000e | ||
|
|
c15b7aa9cc | ||
|
|
c50df8f3b5 | ||
|
|
ebc802756f | ||
|
|
7b9cee3cbd | ||
|
|
a71ba04109 | ||
|
|
61d9edcaa4 | ||
|
|
1e435ee3ec | ||
|
|
eae0aa256e | ||
|
|
1176f9ac1b | ||
|
|
6b02317ea8 | ||
|
|
76c320e9f0 | ||
|
|
02e98e5d45 | ||
|
|
d66c17881e | ||
|
|
17b5ca7351 | ||
|
|
b69219df05 | ||
|
|
80239aaf00 | ||
|
|
bb0d163d22 | ||
|
|
4c40fdb73a | ||
|
|
80595d6cc5 | ||
|
|
319091b3f4 | ||
|
|
790dc877c3 | ||
|
|
d52d0ee9ed | ||
|
|
ef7d26eb07 | ||
|
|
d9614dfbe8 | ||
|
|
cdbafafc04 | ||
|
|
54a9f30e92 | ||
|
|
10af94c77e | ||
|
|
2c7c27e297 | ||
|
|
b3a81a216d | ||
|
|
1cc0a44264 | ||
|
|
d063eaccb1 | ||
|
|
49f6b384e3 | ||
|
|
c17d0ef560 | ||
|
|
532615a32a | ||
|
|
ed5c98f0ee | ||
|
|
c7f2f3f5b7 | ||
|
|
41052f0d6e | ||
|
|
75d23c8bb2 | ||
|
|
a46706c82e | ||
|
|
2baea12d97 | ||
|
|
ba4ec551ed | ||
|
|
371ff20a3b | ||
|
|
52e9085579 | ||
|
|
6e27d7539f | ||
|
|
07bd149b68 | ||
|
|
5c29eeac18 | ||
|
|
29c7cfcbbf | ||
|
|
c8714f587a | ||
|
|
4b3a053913 | ||
|
|
9b2b81e6a4 | ||
|
|
2443cb9ca8 | ||
|
|
70d9732765 | ||
|
|
413f119c7e | ||
|
|
31c0408cb4 | ||
|
|
63c4ad7617 | ||
|
|
ce4d59ed69 | ||
|
|
2f2080a337 | ||
|
|
c36195795a | ||
|
|
724eda2435 | ||
|
|
46be6181b5 | ||
|
|
5218438716 | ||
|
|
b27b51f60e | ||
|
|
88e362732f | ||
|
|
a500fbc9b0 | ||
|
|
523afcbcd2 | ||
|
|
52227a8920 | ||
|
|
468bc7725a | ||
|
|
88447ca32e | ||
|
|
2230f1273f | ||
|
|
72961d914b | ||
|
|
5345990dae | ||
|
|
c9e09c9875 | ||
|
|
d3540aacc5 | ||
|
|
eb169e4f73 | ||
|
|
f5e96eba72 | ||
|
|
21d5ec7275 | ||
|
|
be58d6f9d6 | ||
|
|
5d9b80cd8b | ||
|
|
bdeb095a7d | ||
|
|
1ab0c3c248 | ||
|
|
51f0e469cb | ||
|
|
015c3e0b45 | ||
|
|
3077571976 | ||
|
|
52c8d09ba8 | ||
|
|
e5b1bd39a0 | ||
|
|
6f5b68095b | ||
|
|
d9e50fd7f3 | ||
|
|
5cd765e935 | ||
|
|
5af97e5e47 | ||
|
|
ef4dcce737 | ||
|
|
fb0ced2639 | ||
|
|
8e7f2679d5 | ||
|
|
e7d8ed71d6 | ||
|
|
df7c7930d0 | ||
|
|
219e58d453 | ||
|
|
1495a43cea | ||
|
|
634db18a0f | ||
|
|
fd173e260f | ||
|
|
67fbf8d264 | ||
|
|
6de1c86d18 | ||
|
|
c4d389c5df | ||
|
|
31d8e93ef3 | ||
|
|
96f4542a67 | ||
|
|
36c389ac46 | ||
|
|
a662340fda | ||
|
|
263b7befde | ||
|
|
2dc6c2dc52 | ||
|
|
72347e2d45 | ||
|
|
ef1021e759 | ||
|
|
5f28617d7d | ||
|
|
d75e3ed05d | ||
|
|
cee148ed64 | ||
|
|
0d95e863c9 | ||
|
|
4b4b36d047 | ||
|
|
82ceb4de0a | ||
|
|
084f5f4715 | ||
|
|
7e6f00ee11 | ||
|
|
9042b9e2c7 | ||
|
|
e4567bbc47 | ||
|
|
4f26d98150 | ||
|
|
d4677b6561 | ||
|
|
4adc4cf0b9 | ||
|
|
3128e1705b | ||
|
|
20043f63a6 | ||
|
|
c8ccb61b9e | ||
|
|
a62a66d545 | ||
|
|
844e8a153d | ||
|
|
05115adbff | ||
|
|
b4d0bb5a6d | ||
|
|
dedd87662b | ||
|
|
46bcba7173 | ||
|
|
3d708e4788 | ||
|
|
7ff91fe5f9 | ||
|
|
d530e0c14f | ||
|
|
5ed4dc4f60 | ||
|
|
0dc68b1aef | ||
|
|
98d8a8b871 | ||
|
|
50af394272 | ||
|
|
375c106fcc | ||
|
|
d1439a10a8 | ||
|
|
c44eb3ab91 | ||
|
|
fd3baf68f1 | ||
|
|
89216e239f | ||
|
|
6ba53329e5 | ||
|
|
0958fb35ae | ||
|
|
5a91ded214 | ||
|
|
7606bf8156 | ||
|
|
1bd0f9eecd | ||
|
|
8e9b7e2c67 | ||
|
|
063bebe7d3 | ||
|
|
7ff704a13f | ||
|
|
b684b5fada | ||
|
|
8756d5b160 | ||
|
|
cd0099f2a1 | ||
|
|
fa205cdaf8 | ||
|
|
f51e1893fe | ||
|
|
da98e84b19 | ||
|
|
a6c35a8d74 | ||
|
|
d747649892 | ||
|
|
ee8f189bba | ||
|
|
177259a0a7 | ||
|
|
173ef11681 | ||
|
|
47d6d09081 | ||
|
|
48c461ea85 | ||
|
|
2a46918c66 | ||
|
|
2db1673585 | ||
|
|
4a301240bd | ||
|
|
91fedd85b0 | ||
|
|
4f43f1d0ac | ||
|
|
d0ecb0cbc7 | ||
|
|
fcb7eaa555 | ||
|
|
38b773d80b | ||
|
|
9f62553f23 | ||
|
|
dba782e985 | ||
|
|
4a456b2a75 | ||
|
|
7d23ea7e9e | ||
|
|
b942005931 | ||
|
|
1456585249 | ||
|
|
b3f3e7d0cb | ||
|
|
77434964ab | ||
|
|
f18852376f | ||
|
|
0c38a916fe | ||
|
|
f97c4ccb60 | ||
|
|
d867579a69 | ||
|
|
f378fac6a1 | ||
|
|
4a15939c13 | ||
|
|
380e54a753 | ||
|
|
0825ab36f0 | ||
|
|
cfbf3595c7 | ||
|
|
39751f8786 | ||
|
|
a3fe14d6c6 | ||
|
|
cd57ea2784 | ||
|
|
0b17caaa27 | ||
|
|
b47725a65b | ||
|
|
c70022e6c4 | ||
|
|
c56c1b9482 | ||
|
|
0772b51c2c | ||
|
|
4695fa3c2a | ||
|
|
7a74c9523a | ||
|
|
0eb6240fd0 | ||
|
|
a7e79e089b | ||
|
|
7be496a051 | ||
|
|
5f2b2a6417 | ||
|
|
c3ec8ee76f | ||
|
|
5a49eb06ca | ||
|
|
1b07f86eb8 | ||
|
|
b2e68b8dc7 | ||
|
|
2d2f92631c | ||
|
|
f761432c11 | ||
|
|
fbf2707561 | ||
|
|
a06410055c | ||
|
|
ccd4b4be00 | ||
|
|
855be97011 | ||
|
|
a4840b0268 | ||
|
|
f3c5d9c1b6 | ||
|
|
c1b2d9cb86 | ||
|
|
115c63bcde | ||
|
|
162e91c5ca | ||
|
|
14040123e8 | ||
|
|
ea883b30a5 | ||
|
|
e25b2c4968 | ||
|
|
3b67028ad6 | ||
|
|
4f4a5409d7 | ||
|
|
88112f3d74 | ||
|
|
375192efa1 | ||
|
|
2936378b76 | ||
|
|
39fa45debe | ||
|
|
2557d81b3b | ||
|
|
91429bd63d | ||
|
|
ff95d6d0ab | ||
|
|
5473994a42 | ||
|
|
3c260c545d | ||
|
|
edca27fa32 | ||
|
|
db922e8c88 | ||
|
|
6ceb3438be | ||
|
|
0abb4338a9 | ||
|
|
7479cc68a7 | ||
|
|
e384f549f4 | ||
|
|
e57043ce62 | ||
|
|
8233d589b6 | ||
|
|
88e7c6012b | ||
|
|
b708543309 | ||
|
|
1678a6fbdb | ||
|
|
45e6a6bbad | ||
|
|
d04f7005de | ||
|
|
43c860b6cc | ||
|
|
5575257b08 | ||
|
|
9a75daa388 | ||
|
|
a1c0ee0e66 | ||
|
|
811faa7bda | ||
|
|
c870ef49da | ||
|
|
bd2a4db26c | ||
|
|
b05d5d3f24 | ||
|
|
28807733c3 | ||
|
|
423764ca2e | ||
|
|
49ef81edb6 | ||
|
|
6ce57d9cf8 | ||
|
|
29b73897f8 | ||
|
|
0ab719b59b | ||
|
|
de60db863b | ||
|
|
5d169afd7e | ||
|
|
13a341b88d | ||
|
|
8252d0d9f5 | ||
|
|
b67902ebdd | ||
|
|
2ca4016a1f | ||
|
|
425a5dd094 | ||
|
|
730bd72056 | ||
|
|
6e370b90fd | ||
|
|
c09c02300a | ||
|
|
96c43cf197 | ||
|
|
376ba6912e | ||
|
|
ad8766dfa4 | ||
|
|
476a6842ea | ||
|
|
c5dedeb318 | ||
|
|
07d62a4b89 | ||
|
|
84ab71dd7e | ||
|
|
bf19d821e0 | ||
|
|
09ed3f10cc | ||
|
|
28060d5595 | ||
|
|
5e9f4dc973 | ||
|
|
92e904dec9 | ||
|
|
68b666d7e5 | ||
|
|
2fc9dcc549 | ||
|
|
3d50a6a425 | ||
|
|
5169d08735 | ||
|
|
98ec6df168 | ||
|
|
e43830955f | ||
|
|
f28b7ed0cd | ||
|
|
9bc3d16599 | ||
|
|
1c4ed67779 | ||
|
|
6e9017c474 | ||
|
|
470ac2b46f | ||
|
|
485b30027f | ||
|
|
d9fe9c5d8a | ||
|
|
af166bf0a0 | ||
|
|
3a18b68f5f | ||
|
|
1b346d7041 | ||
|
|
8ddffb36e1 | ||
|
|
9cfe4bc6fe | ||
|
|
311b1761c9 | ||
|
|
60dd75745f | ||
|
|
fe7cdcefb4 | ||
|
|
13829329bd | ||
|
|
51ee382517 | ||
|
|
77fab79d83 | ||
|
|
2e9e6c82f9 | ||
|
|
7e839c5c9e | ||
|
|
bf50d25ea1 | ||
|
|
83e61bf99e | ||
|
|
e68e9659ab | ||
|
|
cb5171914e | ||
|
|
25c4fbd0cb | ||
|
|
4fb6153eed | ||
|
|
a2216c12a0 | ||
|
|
0a0951ba12 | ||
|
|
42e1fd8fff | ||
|
|
309fb90a5d | ||
|
|
7f2628acd7 | ||
|
|
ee4096d23e | ||
|
|
7b3fd92015 | ||
|
|
ce5930c365 | ||
|
|
f91ce704f3 | ||
|
|
8c7b18daed | ||
|
|
d1969b4c03 | ||
|
|
1dd96b6cdc | ||
|
|
7491413de5 | ||
|
|
7114d6681a | ||
|
|
34e01642ca | ||
|
|
b8bc85b534 | ||
|
|
4db3dfee7d | ||
|
|
ae31bc21bc | ||
|
|
b2f98db74e | ||
|
|
bde25d6694 | ||
|
|
e837b339cc | ||
|
|
01053f8f2f | ||
|
|
8fc5693ef6 | ||
|
|
3d36fa8f4e | ||
|
|
b59018aa05 | ||
|
|
282a64c252 | ||
|
|
5268c19b6b | ||
|
|
f5659e17d5 | ||
|
|
af047e9f8c | ||
|
|
d25efb6468 | ||
|
|
ebbde5c343 | ||
|
|
e74628f5d4 | ||
|
|
7cb34e3ad6 | ||
|
|
996645dc17 | ||
|
|
77ae180d3d | ||
|
|
0052b193cf | ||
|
|
635645c650 | ||
|
|
231a6e7aea | ||
|
|
562fe8078b | ||
|
|
a3a4439dec | ||
|
|
95cc900b1f | ||
|
|
190e58a8c6 | ||
|
|
5f0f8749d9 | ||
|
|
8bf6525394 | ||
|
|
117f26f865 | ||
|
|
b0f38e9352 | ||
|
|
f9e1b2b7b7 | ||
|
|
96f221e0d0 | ||
|
|
e436c94419 | ||
|
|
deb802b2be | ||
|
|
8e1adddc2b | ||
|
|
b894f7c9d6 | ||
|
|
a71ccd8372 | ||
|
|
7d297b418f | ||
|
|
166e878830 | ||
|
|
430be8d4bd | ||
|
|
8676a1bf56 | ||
|
|
4fe2f2fb09 | ||
|
|
7f559235be | ||
|
|
79813097b5 | ||
|
|
e49d06c6bd | ||
|
|
739b3f2c5f | ||
|
|
9e1690defe | ||
|
|
610b70b79e | ||
|
|
15a0d27eed | ||
|
|
888edba03f | ||
|
|
c817efbd8a | ||
|
|
c11d6d5929 | ||
|
|
243fd46df9 | ||
|
|
a0c9ecd289 | ||
|
|
e23f4ec3db | ||
|
|
9cdcc8303b | ||
|
|
c16a6222f3 | ||
|
|
3e648fd1e9 | ||
|
|
b9a9cd9db8 | ||
|
|
5b9e071c18 | ||
|
|
99157ae56a | ||
|
|
6024480400 | ||
|
|
6d35bd2421 | ||
|
|
8bae715994 | ||
|
|
1dcedb23ec | ||
|
|
d7fce99564 | ||
|
|
ce9d7045f9 | ||
|
|
1924e16f45 | ||
|
|
b3bb54da73 | ||
|
|
88b4c64c0d | ||
|
|
89eafa1b97 | ||
|
|
8ddb7b0152 | ||
|
|
111b04e18e | ||
|
|
2e31e97e54 | ||
|
|
56da375165 | ||
|
|
3534147905 | ||
|
|
738e420128 | ||
|
|
b80d5d6b33 | ||
|
|
422febd18e | ||
|
|
68c9252ff7 | ||
|
|
a1ba608641 | ||
|
|
224f574420 | ||
|
|
06f502a1aa | ||
|
|
d60ee84137 | ||
|
|
139feaf97a | ||
|
|
537b34dc6f | ||
|
|
3abbd7b4c7 | ||
|
|
1f19b78287 | ||
|
|
36927632c5 | ||
|
|
607599f2a1 | ||
|
|
b587dd2704 | ||
|
|
4b4ade8342 | ||
|
|
d4d36eed45 | ||
|
|
cb7f331ebc | ||
|
|
c4181e5f2e | ||
|
|
ec2cdafec5 | ||
|
|
755072e378 | ||
|
|
652ff07668 | ||
|
|
24a92808db | ||
|
|
6f046327ac | ||
|
|
eee3046624 | ||
|
|
a16289b204 | ||
|
|
a4ac750eb1 | ||
|
|
981f06b9d1 | ||
|
|
49c1cb6990 | ||
|
|
c0853967d5 | ||
|
|
fd8439ffbc | ||
|
|
7c79c9ac3a | ||
|
|
8ad58139cd | ||
|
|
7b25834667 | ||
|
|
66b9a72d5a | ||
|
|
9bbc3901ee | ||
|
|
f116722e68 | ||
|
|
8e4dc43368 | ||
|
|
00387cb645 | ||
|
|
0f8f8e05b2 | ||
|
|
82c2ba4c44 | ||
|
|
edf4595bc1 | ||
|
|
f1e1cc28ff | ||
|
|
122ec48a89 | ||
|
|
6e2bdcbbbc | ||
|
|
67f3c687b8 | ||
|
|
9c8420a4dc | ||
|
|
e960a09ff4 | ||
|
|
e339cdec52 | ||
|
|
40566cdbba | ||
|
|
30d0d5fb96 | ||
|
|
b758a13813 | ||
|
|
541580d157 | ||
|
|
8a484e990e | ||
|
|
1ca737ed55 | ||
|
|
e9edb03eff | ||
|
|
d5a34339e5 | ||
|
|
32ca060094 | ||
|
|
81d4d4d2c1 | ||
|
|
7a94bdb60c | ||
|
|
3453b6e715 | ||
|
|
1080dc256a | ||
|
|
fc5036a630 | ||
|
|
9d627e2567 | ||
|
|
5dd23a2195 | ||
|
|
956e50686e | ||
|
|
412310ed04 | ||
|
|
d20bfb12e4 | ||
|
|
3dbd4af263 | ||
|
|
7b9b4f821b | ||
|
|
1411d3f37f | ||
|
|
dfb89e3442 | ||
|
|
0c360fe55f | ||
|
|
3109069019 | ||
|
|
dbcb4c8729 | ||
|
|
2859c190cd | ||
|
|
9c39f69559 | ||
|
|
b958c55ac6 | ||
|
|
b943becc61 | ||
|
|
db490d1c75 | ||
|
|
f6f3473d17 | ||
|
|
db692a30e5 | ||
|
|
b0591c8042 | ||
|
|
f5920f8cbd | ||
|
|
05b242d542 | ||
|
|
6c3e4d7d0d | ||
|
|
f28459497d | ||
|
|
e558d45208 | ||
|
|
788741bbcb | ||
|
|
0bca4c8c3b | ||
|
|
5ff0fcc693 | ||
|
|
c49c6565e5 | ||
|
|
a92d21ce24 | ||
|
|
808c0a6dff | ||
|
|
f7d434aec2 | ||
|
|
6af98bec16 | ||
|
|
cf2ec238a4 | ||
|
|
bb6b7ded55 | ||
|
|
bad4a27b9f | ||
|
|
f5eb345c8a | ||
|
|
db0c9e1c2d | ||
|
|
0b143e6d22 | ||
|
|
7f3bc03990 | ||
|
|
1f624a8005 | ||
|
|
030a4e4e25 | ||
|
|
16781ac8f9 | ||
|
|
ae43fd7c7a | ||
|
|
6063d243eb | ||
|
|
bda3282f6d | ||
|
|
48ac946d9f | ||
|
|
0406c64a5d | ||
|
|
b1c94c7d86 | ||
|
|
529b80406c | ||
|
|
13c8d2ba74 | ||
|
|
cbb52b1d5d | ||
|
|
6506a1c490 | ||
|
|
dd3126735b | ||
|
|
424bcc05fa | ||
|
|
62e95dcc60 | ||
|
|
0fe182d3c3 | ||
|
|
0c0e26effa | ||
|
|
2a8c1c677e | ||
|
|
4380641714 | ||
|
|
9ead44531e | ||
|
|
d3bb466026 | ||
|
|
8196d5d680 | ||
|
|
82a43f448e | ||
|
|
eb1b185d70 | ||
|
|
67f40b2629 | ||
|
|
33f1ab3ae1 | ||
|
|
fbf2a5feed | ||
|
|
cb3afeec53 | ||
|
|
c50cf6d7ff | ||
|
|
3a49e1bdb1 | ||
|
|
886955148d | ||
|
|
408c3a62a8 | ||
|
|
d833038ba1 | ||
|
|
78afd6c772 | ||
|
|
f025488294 | ||
|
|
35944a13b4 | ||
|
|
6109a70a16 | ||
|
|
339a53d9d4 | ||
|
|
b3a3228a02 | ||
|
|
92b996513e | ||
|
|
cfcb1fc491 | ||
|
|
a9f884bd47 | ||
|
|
dbc5c9b82d | ||
|
|
3d6c831e8a | ||
|
|
baa3145817 | ||
|
|
632fdc3e19 | ||
|
|
57a43e9da7 | ||
|
|
5773d4d3c4 | ||
|
|
4554da0537 | ||
|
|
635c39c4c3 | ||
|
|
b0be833c75 | ||
|
|
34f0b313af | ||
|
|
c4fa2f6110 | ||
|
|
f305cdbf75 | ||
|
|
6bcf35f2e1 | ||
|
|
3c114262aa | ||
|
|
b8330fc58a | ||
|
|
483a7d05e9 | ||
|
|
8c4c754a72 | ||
|
|
f4a5a8b6cd | ||
|
|
bc6e2af374 | ||
|
|
6231e153e6 | ||
|
|
2dcf263536 | ||
|
|
f258a68029 | ||
|
|
7294ac4fc9 | ||
|
|
cc3c98d9b7 | ||
|
|
30c30d3696 | ||
|
|
5196458305 | ||
|
|
d5d48560a7 | ||
|
|
32009942fd | ||
|
|
00702dc39b | ||
|
|
8e06726f6b | ||
|
|
10273a0288 | ||
|
|
19eef1d0da | ||
|
|
07182444d2 | ||
|
|
5e81a210ce | ||
|
|
db444c4a08 | ||
|
|
70e230815b | ||
|
|
4af680c3b6 | ||
|
|
d24b36adf9 | ||
|
|
a13a3d1552 | ||
|
|
7a3676851d | ||
|
|
a7202ee804 | ||
|
|
3dd40b9f37 | ||
|
|
18e1ddec3c | ||
|
|
b3bffcef34 | ||
|
|
740db8ff02 | ||
|
|
752cf4c95d | ||
|
|
b30aa96a88 | ||
|
|
0f6ad749f5 | ||
|
|
f42e4932fa | ||
|
|
3d38ebbef5 | ||
|
|
889887c2f1 | ||
|
|
7fe8b95833 | ||
|
|
bd1eaa25f2 | ||
|
|
81b1befd10 | ||
|
|
64dd1973b9 | ||
|
|
bf94add992 | ||
|
|
f7bb8fc10f | ||
|
|
014fa02c6a | ||
|
|
e8de5da3a5 | ||
|
|
c43fee541d | ||
|
|
8083c30e7b | ||
|
|
3a091fa302 | ||
|
|
2a01c5c865 | ||
|
|
362fe4e4fa | ||
|
|
60217a2c02 | ||
|
|
c2fec29bfa | ||
|
|
f6fed76e7e | ||
|
|
7560518eec | ||
|
|
53107995bf | ||
|
|
264c636adf | ||
|
|
f9c02aa40f | ||
|
|
11f27beccd | ||
|
|
ebdcd94bf5 | ||
|
|
4a6f4eaac9 | ||
|
|
ebefb78fd4 | ||
|
|
73ec467dd3 | ||
|
|
0a9c8acd6d | ||
|
|
6f01fa50ce | ||
|
|
67d332e0f5 | ||
|
|
5dab410537 | ||
|
|
259dea0777 | ||
|
|
e30c724bd4 | ||
|
|
6f4148faab | ||
|
|
7e16606618 | ||
|
|
c2c5ad2d47 | ||
|
|
1a91b15a6e | ||
|
|
bb13c2cd15 | ||
|
|
033a0c139e | ||
|
|
0d5741bc74 | ||
|
|
899bfbfbae | ||
|
|
2bf0eeb82d | ||
|
|
c870c08b7e | ||
|
|
fa41fe3f13 | ||
|
|
8f6e5e197b | ||
|
|
15286523cf | ||
|
|
d9599f816f | ||
|
|
6062f4dd58 | ||
|
|
24a188588a | ||
|
|
2ab6907fe2 | ||
|
|
f44511e94d | ||
|
|
26675e6dcd | ||
|
|
75c8bdf962 | ||
|
|
efde0eb171 | ||
|
|
f4a47fa78e | ||
|
|
5f9f42292c | ||
|
|
c261b3d1f5 | ||
|
|
cca955fc94 | ||
|
|
0c8c231949 | ||
|
|
d485d1849f | ||
|
|
74055cc15e | ||
|
|
195f90159d | ||
|
|
fc27e2f32d | ||
|
|
f2eb55683c | ||
|
|
9a936721d8 | ||
|
|
eee0d5b065 | ||
|
|
b1dec917c7 | ||
|
|
0dbac3d11e | ||
|
|
f6c82d52ec | ||
|
|
af042f6a24 | ||
|
|
cbdcbfc49c | ||
|
|
e353a2e51c | ||
|
|
a1c7104d7f | ||
|
|
198c5bb55e | ||
|
|
141f9ebf4b | ||
|
|
f29c2f8796 | ||
|
|
5e07367979 | ||
|
|
0ea5b14bd8 | ||
|
|
9eca9bccf4 | ||
|
|
951ba267cf | ||
|
|
1fb5c127b5 | ||
|
|
4a71b0ec19 | ||
|
|
ba63b2886f | ||
|
|
d120167725 | ||
|
|
031b34b121 | ||
|
|
d8fc16538e | ||
|
|
80b6ec4478 | ||
|
|
9203d26a2f | ||
|
|
4cf116ceb6 | ||
|
|
41f30c288e | ||
|
|
b18c7f9466 | ||
|
|
d18492e751 | ||
|
|
86f9f707d8 | ||
|
|
0dfc443252 | ||
|
|
71cd9b9000 | ||
|
|
be95c80aa2 | ||
|
|
b7f355fdd2 | ||
|
|
4a746be43a | ||
|
|
44f839b896 | ||
|
|
35638f6146 | ||
|
|
e402d20876 | ||
|
|
dabb36c006 | ||
|
|
b76db01c66 | ||
|
|
4a37b852a0 | ||
|
|
b0f7ddaa2e | ||
|
|
113285e1dc | ||
|
|
46e9520a28 | ||
|
|
cf89ae64e2 | ||
|
|
3952b525b8 | ||
|
|
0f5f9c0385 | ||
|
|
167544d792 | ||
|
|
1fee7da16f | ||
|
|
048d6929f4 | ||
|
|
57e4f4d426 | ||
|
|
969ea57159 | ||
|
|
c489ce62b2 | ||
|
|
fc75885e9e | ||
|
|
28f8267563 | ||
|
|
9ec4c43dd2 | ||
|
|
46342d4633 | ||
|
|
fd26f45208 | ||
|
|
13aff0d8cd | ||
|
|
af76bbb3f3 | ||
|
|
0fc47f5abb | ||
|
|
4d382a8cc1 | ||
|
|
364abdd6d1 | ||
|
|
761ab7c834 | ||
|
|
b1bcb7183b | ||
|
|
e99ab0d1dd | ||
|
|
f73bcd427d | ||
|
|
7755c00721 | ||
|
|
a735f8cb76 | ||
|
|
cc767add88 | ||
|
|
4d436a3cb0 | ||
|
|
53a18635ee | ||
|
|
f0421e9455 | ||
|
|
93319841ed | ||
|
|
ccf21ec061 | ||
|
|
39913d6ee8 | ||
|
|
fe3464b763 | ||
|
|
af0a451dc4 | ||
|
|
59b91cf205 | ||
|
|
57ec922214 | ||
|
|
1123253f79 | ||
|
|
aba41d07cd | ||
|
|
1581de08da | ||
|
|
0162bb7034 | ||
|
|
c70a73f38d | ||
|
|
2ed40523ab | ||
|
|
009f692f49 | ||
|
|
48e19c1964 | ||
|
|
704d9e0a13 | ||
|
|
6b254ec495 | ||
|
|
561e51871e | ||
|
|
777c5ce992 | ||
|
|
70c5c12067 | ||
|
|
1595d36721 | ||
|
|
37714eb331 | ||
|
|
ad2e93f6c5 | ||
|
|
936190c17c | ||
|
|
9987fb24f8 | ||
|
|
67f0b69a4c | ||
|
|
5568f83a6c | ||
|
|
b08c3c5baa | ||
|
|
7d9ac3f97d | ||
|
|
0bbb4a07b2 | ||
|
|
7a92d4008e | ||
|
|
c51d71b033 | ||
|
|
7cb449c4a7 | ||
|
|
61142f203b | ||
|
|
fbaa3821a4 | ||
|
|
4e8a1c6516 | ||
|
|
8c5d3ac130 | ||
|
|
c110111f52 | ||
|
|
1e03be4e08 | ||
|
|
f91a098770 | ||
|
|
fcca359774 | ||
|
|
00a8076deb | ||
|
|
a6abdccf01 | ||
|
|
ab219d3331 | ||
|
|
2937f5eebc | ||
|
|
e5dd894960 | ||
|
|
bc7f6b37b0 | ||
|
|
36031d9a36 | ||
|
|
27e4cbb215 | ||
|
|
f9ae83e951 | ||
|
|
a55f4d3416 | ||
|
|
733d23aef8 | ||
|
|
8d3a7e1688 | ||
|
|
19b24cf978 | ||
|
|
458585b5fd | ||
|
|
1d57cfb7bd | ||
|
|
bc7241b2a4 | ||
|
|
7d132aefa9 | ||
|
|
a31aaa410c | ||
|
|
da5e62773d | ||
|
|
b1c79323af | ||
|
|
c82101ef16 | ||
|
|
978216d350 | ||
|
|
0c6bfa74b5 | ||
|
|
01175a415a | ||
|
|
a17cb2339e | ||
|
|
0a0a80ec72 | ||
|
|
91a5390929 | ||
|
|
1ea7f6f033 | ||
|
|
947afd7eac | ||
|
|
e6b8b23a2c | ||
|
|
39f1da08d2 | ||
|
|
09a841f810 | ||
|
|
792cff5abc | ||
|
|
f49525ee95 | ||
|
|
4e080928a8 | ||
|
|
9c52fc8e22 | ||
|
|
019ab50994 | ||
|
|
b63868327f | ||
|
|
e080c663a8 | ||
|
|
3a7808dc7d | ||
|
|
49ad633530 | ||
|
|
e03ef41829 | ||
|
|
a4341f22a2 | ||
|
|
b8b0243d95 | ||
|
|
62801f5343 |
43
.gitignore
vendored
43
.gitignore
vendored
@@ -20,12 +20,12 @@
|
||||
*buffer
|
||||
*model
|
||||
*pyc
|
||||
*train
|
||||
*test
|
||||
*.train
|
||||
*.test
|
||||
*.tar
|
||||
*group
|
||||
*rar
|
||||
*vali
|
||||
*data
|
||||
*sdf
|
||||
Release
|
||||
*exe*
|
||||
@@ -36,7 +36,6 @@ ipch
|
||||
*log
|
||||
Debug
|
||||
*suo
|
||||
*test*
|
||||
.Rhistory
|
||||
*.dll
|
||||
*i386
|
||||
@@ -48,13 +47,35 @@ Debug
|
||||
*.cpage.col
|
||||
*.cpage
|
||||
*.Rproj
|
||||
xgboost
|
||||
xgboost.mpi
|
||||
xgboost.mock
|
||||
train*
|
||||
rabit
|
||||
./xgboost
|
||||
./xgboost.mpi
|
||||
./xgboost.mock
|
||||
#.Rbuildignore
|
||||
R-package.Rproj
|
||||
*.cache*
|
||||
R-package/inst
|
||||
R-package/src
|
||||
#java
|
||||
java/xgboost4j/target
|
||||
java/xgboost4j/tmp
|
||||
java/xgboost4j-demo/target
|
||||
java/xgboost4j-demo/data/
|
||||
java/xgboost4j-demo/tmp/
|
||||
java/xgboost4j-demo/model/
|
||||
nb-configuration*
|
||||
# Eclipse
|
||||
.project
|
||||
.cproject
|
||||
.pydevproject
|
||||
.settings/
|
||||
build
|
||||
config.mk
|
||||
xgboost
|
||||
*.data
|
||||
build_plugin
|
||||
dmlc-core
|
||||
.idea
|
||||
recommonmark/
|
||||
tags
|
||||
*.iml
|
||||
*.class
|
||||
target
|
||||
*.swp
|
||||
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "dmlc-core"]
|
||||
path = dmlc-core
|
||||
url = https://github.com/dmlc/dmlc-core
|
||||
[submodule "rabit"]
|
||||
path = rabit
|
||||
url = https://github.com/dmlc/rabit
|
||||
74
.travis.yml
Normal file
74
.travis.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
# disable sudo for container build.
|
||||
sudo: false
|
||||
|
||||
# Enabling test on Linux and OS X
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
# Use Build Matrix to do lint and build seperately
|
||||
env:
|
||||
matrix:
|
||||
# code lint
|
||||
- TASK=lint
|
||||
# r package test
|
||||
- TASK=r_test
|
||||
# python package test
|
||||
- TASK=python_test
|
||||
- TASK=python_lightweight_test
|
||||
# java package test
|
||||
- TASK=java_test
|
||||
# cmake test
|
||||
- TASK=cmake_test
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: TASK=lint
|
||||
- os: linux
|
||||
env: TASK=r_test
|
||||
- os: osx
|
||||
env: TASK=java_test
|
||||
- os: osx
|
||||
env: TASK=python_lightweight_test
|
||||
|
||||
# dependent apt packages
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- doxygen
|
||||
- wget
|
||||
- libcurl4-openssl-dev
|
||||
- unzip
|
||||
- graphviz
|
||||
|
||||
before_install:
|
||||
- source dmlc-core/scripts/travis/travis_setup_env.sh
|
||||
- export PYTHONPATH=${PYTHONPATH}:${PWD}/python-package
|
||||
- echo "MAVEN_OPTS='-Xmx2048m -XX:MaxPermSize=1024m -XX:ReservedCodeCacheSize=512m'" > ~/.mavenrc
|
||||
|
||||
install:
|
||||
- source tests/travis/setup.sh
|
||||
|
||||
script:
|
||||
- tests/travis/run_test.sh
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ${HOME}/.cache/usr
|
||||
- ${HOME}/.cache/pip
|
||||
|
||||
before_cache:
|
||||
- dmlc-core/scripts/travis/travis_before_cache.sh
|
||||
|
||||
after_failure:
|
||||
- tests/travis/travis_after_failure.sh
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
36
CHANGES.md
36
CHANGES.md
@@ -1,36 +0,0 @@
|
||||
Change Log
|
||||
=====
|
||||
|
||||
xgboost-0.1
|
||||
=====
|
||||
* Initial release
|
||||
|
||||
xgboost-0.2x
|
||||
=====
|
||||
* Python module
|
||||
* Weighted samples instances
|
||||
* Initial version of pairwise rank
|
||||
|
||||
xgboost-0.3
|
||||
=====
|
||||
* Faster tree construction module
|
||||
- Allows subsample columns during tree construction via ```bst:col_samplebytree=ratio```
|
||||
* Support for boosting from initial predictions
|
||||
* Experimental version of LambdaRank
|
||||
* Linear booster is now parallelized, using parallel coordinated descent.
|
||||
* Add [Code Guide](src/README.md) for customizing objective function and evaluation
|
||||
* Add R module
|
||||
|
||||
xgboost-0.4
|
||||
=====
|
||||
* Distributed version of xgboost that runs on YARN, scales to billions of examples
|
||||
* Direct save/load data and model from/to S3 and HDFS
|
||||
* Feature importance visualization in R module, by Michael Benesty
|
||||
* Predict leaf index
|
||||
* Poisson regression for counts data
|
||||
* Early stopping option in training
|
||||
* Native save load support in R and python
|
||||
- xgboost models now can be saved using save/load in R
|
||||
- xgboost python model is now pickable
|
||||
* sklearn wrapper is supported in python module
|
||||
* Experimental External memory version
|
||||
79
CMakeLists.txt
Normal file
79
CMakeLists.txt
Normal file
@@ -0,0 +1,79 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (xgboost)
|
||||
find_package(OpenMP)
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -fPIC")
|
||||
|
||||
# Make sure we are using C++11
|
||||
# Visual Studio 12.0 and newer supports enough c++11 to make this work
|
||||
if(MSVC AND MSVC_VERSION LESS 1800)
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
else()
|
||||
# GCC 4.6 with c++0x supports enough to make this work
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
|
||||
if(COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
#Make sure we are using the static runtime
|
||||
if(MSVC)
|
||||
set(variables
|
||||
CMAKE_C_FLAGS_DEBUG
|
||||
CMAKE_C_FLAGS_MINSIZEREL
|
||||
CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
)
|
||||
foreach(variable ${variables})
|
||||
if(${variable} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
include_directories (
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
||||
${PROJECT_SOURCE_DIR}/rabit/include
|
||||
)
|
||||
|
||||
file(GLOB SOURCES
|
||||
src/c_api/*.cc
|
||||
src/common/*.cc
|
||||
src/data/*.cc
|
||||
src/gbm/*.cc
|
||||
src/metric/*.cc
|
||||
src/objective/*.cc
|
||||
src/tree/*.cc
|
||||
src/*.cc
|
||||
)
|
||||
|
||||
set(RABIT_SOURCES
|
||||
rabit/src/allreduce_base.cc
|
||||
rabit/src/allreduce_robust.cc
|
||||
rabit/src/engine.cc
|
||||
rabit/src/c_api.cc
|
||||
)
|
||||
|
||||
|
||||
add_subdirectory(dmlc-core)
|
||||
|
||||
add_library(rabit STATIC ${RABIT_SOURCES})
|
||||
|
||||
add_executable(xgboost ${SOURCES})
|
||||
add_library(libxgboost SHARED ${SOURCES})
|
||||
|
||||
target_link_libraries(xgboost dmlccore rabit)
|
||||
target_link_libraries(libxgboost dmlccore rabit)
|
||||
62
CONTRIBUTORS.md
Normal file
62
CONTRIBUTORS.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Contributors of DMLC/XGBoost
|
||||
============================
|
||||
XGBoost has been developed and used by a group of active community. Everyone is more than welcomed to is a great way to make the project better and more accessible to more users.
|
||||
|
||||
Comitters
|
||||
---------
|
||||
Committers are people who have made substantial contribution to the project and granted write access to the project.
|
||||
* [Tianqi Chen](https://github.com/tqchen), University of Washington
|
||||
- Tianqi is a PhD working on large-scale machine learning, he is the creator of the project.
|
||||
* [Tong He](https://github.com/hetong007), Simon Fraser University
|
||||
- Tong is a master student working on data mining, he is the maintainer of xgboost R package.
|
||||
* [Bing Xu](https://github.com/antinucleon)
|
||||
- Bing is the original creator of xgboost python package and currently the maintainer of [XGBoost.jl](https://github.com/antinucleon/XGBoost.jl).
|
||||
* [Michael Benesty](https://github.com/pommedeterresautee)
|
||||
- Micheal is a lawyer, data scientist in France, he is the creator of xgboost interactive analysis module in R.
|
||||
* [Yuan Tang](https://github.com/terrytangyuan)
|
||||
- Yuan is a data scientist in Chicago, US. He contributed mostly in R and Python packages.
|
||||
|
||||
Become a Comitter
|
||||
-----------------
|
||||
XGBoost is a opensource project and we are actively looking for new comitters who are willing to help maintaining and lead the project.
|
||||
Committers comes from contributors who:
|
||||
* Made substantial contribution to the project.
|
||||
* Willing to spent time on maintaining and lead the project.
|
||||
|
||||
New committers will be proposed by current comitter memembers, with support from more than two of current comitters.
|
||||
|
||||
List of Contributors
|
||||
--------------------
|
||||
* [Full List of Contributors](https://github.com/dmlc/xgboost/graphs/contributors)
|
||||
- To contributors: please add your name to the list when you submit a patch to the project:)
|
||||
* [Kailong Chen](https://github.com/kalenhaha)
|
||||
- Kailong is an early contributor of xgboost, he is creator of ranking objectives in xgboost.
|
||||
* [Skipper Seabold](https://github.com/jseabold)
|
||||
- Skipper is the major contributor to the scikit-learn module of xgboost.
|
||||
* [Zygmunt Zając](https://github.com/zygmuntz)
|
||||
- Zygmunt is the master behind the early stopping feature frequently used by kagglers.
|
||||
* [Ajinkya Kale](https://github.com/ajkl)
|
||||
* [Boliang Chen](https://github.com/cblsjtu)
|
||||
* [Vadim Khotilovich](https://github.com/khotilov)
|
||||
* [Yangqing Men](https://github.com/yanqingmen)
|
||||
- Yangqing is the creator of xgboost java package.
|
||||
* [Engpeng Yao](https://github.com/yepyao)
|
||||
* [Giulio](https://github.com/giuliohome)
|
||||
- Giulio is the creator of windows project of xgboost
|
||||
* [Jamie Hall](https://github.com/nerdcha)
|
||||
- Jamie is the initial creator of xgboost sklearn modue.
|
||||
* [Yen-Ying Lee](https://github.com/white1033)
|
||||
* [Masaaki Horikoshi](https://github.com/sinhrks)
|
||||
- Masaaki is the initial creator of xgboost python plotting module.
|
||||
* [Hongliang Liu](https://github.com/phunterlau)
|
||||
- Hongliang is the maintainer of xgboost python PyPI package for pip installation.
|
||||
* [daiyl0320](https://github.com/daiyl0320)
|
||||
- daiyl0320 contributed patch to xgboost distributed version more robust, and scales stably on TB scale datasets.
|
||||
* [Huayi Zhang](https://github.com/irachex)
|
||||
* [Johan Manders](https://github.com/johanmanders)
|
||||
* [yoori](https://github.com/yoori)
|
||||
* [Mathias Müller](https://github.com/far0n)
|
||||
* [Sam Thomson](https://github.com/sammthomson)
|
||||
* [ganesh-krishnan](https://github.com/ganesh-krishnan)
|
||||
* [Damien Carol](https://github.com/damiencarol)
|
||||
* [Alex Bain](https://github.com/convexquad)
|
||||
4
LICENSE
4
LICENSE
@@ -1,9 +1,9 @@
|
||||
Copyright (c) 2014 by Tianqi Chen and Contributors
|
||||
Copyright (c) 2016 by Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
257
Makefile
257
Makefile
@@ -1,131 +1,188 @@
|
||||
export CC = gcc
|
||||
export CXX = g++
|
||||
export MPICXX = mpicxx
|
||||
export LDFLAGS= -pthread -lm
|
||||
export CFLAGS = -Wall -O3 -msse2 -Wno-unknown-pragmas -fPIC
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
export CXX = g++ -m64
|
||||
export CC = gcc -m64
|
||||
ifndef config
|
||||
ifneq ("$(wildcard ./config.mk)","")
|
||||
config = config.mk
|
||||
else
|
||||
config = make/config.mk
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(no_omp),1)
|
||||
CFLAGS += -DDISABLE_OPENMP
|
||||
else
|
||||
ifndef DMLC_CORE
|
||||
DMLC_CORE = dmlc-core
|
||||
endif
|
||||
|
||||
ifndef RABIT
|
||||
RABIT = rabit
|
||||
endif
|
||||
|
||||
ROOTDIR = $(CURDIR)
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
UNAME="Windows"
|
||||
else
|
||||
UNAME=$(shell uname)
|
||||
endif
|
||||
|
||||
include $(config)
|
||||
ifeq ($(USE_OPENMP), 0)
|
||||
export NO_OPENMP = 1
|
||||
endif
|
||||
include $(DMLC_CORE)/make/dmlc.mk
|
||||
|
||||
# include the plugins
|
||||
include $(XGB_PLUGINS)
|
||||
|
||||
# use customized config file
|
||||
ifndef CC
|
||||
export CC = $(if $(shell which gcc-5),gcc-5,gcc)
|
||||
endif
|
||||
ifndef CXX
|
||||
export CXX = $(if $(shell which g++-5),g++-5,g++)
|
||||
endif
|
||||
|
||||
export LDFLAGS= -pthread -lm $(ADD_LDFLAGS) $(DMLC_LDFLAGS) $(PLUGIN_LDFLAGS)
|
||||
export CFLAGS= -std=c++0x -Wall -O3 -msse2 -Wno-unknown-pragmas -funroll-loops -Iinclude $(ADD_CFLAGS) $(PLUGIN_CFLAGS)
|
||||
CFLAGS += -I$(DMLC_CORE)/include -I$(RABIT)/include
|
||||
#java include path
|
||||
export JAVAINCFLAGS = -I${JAVA_HOME}/include -I./java
|
||||
|
||||
ifndef LINT_LANG
|
||||
LINT_LANG= "all"
|
||||
endif
|
||||
|
||||
ifneq ($(UNAME), Windows)
|
||||
CFLAGS += -fPIC
|
||||
XGBOOST_DYLIB = lib/libxgboost.so
|
||||
else
|
||||
XGBOOST_DYLIB = lib/libxgboost.dll
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), Linux)
|
||||
LDFLAGS += -lrt
|
||||
JAVAINCFLAGS += -I${JAVA_HOME}/include/linux
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), Darwin)
|
||||
JAVAINCFLAGS += -I${JAVA_HOME}/include/darwin
|
||||
endif
|
||||
|
||||
ifeq ($(USE_OPENMP), 1)
|
||||
CFLAGS += -fopenmp
|
||||
endif
|
||||
|
||||
# by default use c++11
|
||||
ifeq ($(cxx11),1)
|
||||
CFLAGS += -std=c++11
|
||||
else
|
||||
endif
|
||||
|
||||
# handling dmlc
|
||||
ifdef dmlc
|
||||
ifndef config
|
||||
ifneq ("$(wildcard $(dmlc)/config.mk)","")
|
||||
config = $(dmlc)/config.mk
|
||||
else
|
||||
config = $(dmlc)/make/config.mk
|
||||
endif
|
||||
endif
|
||||
include $(config)
|
||||
include $(dmlc)/make/dmlc.mk
|
||||
LDFLAGS+= $(DMLC_LDFLAGS)
|
||||
LIBDMLC=$(dmlc)/libdmlc.a
|
||||
else
|
||||
LIBDMLC=dmlc_simple.o
|
||||
CFLAGS += -DDISABLE_OPENMP
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
LIBRABIT = subtree/rabit/lib/librabit_empty.a
|
||||
SLIB = wrapper/xgboost_wrapper.dll
|
||||
else
|
||||
LIBRABIT = subtree/rabit/lib/librabit.a
|
||||
SLIB = wrapper/libxgboostwrapper.so
|
||||
endif
|
||||
|
||||
# specify tensor path
|
||||
BIN = xgboost
|
||||
MOCKBIN = xgboost.mock
|
||||
OBJ = updater.o gbm.o io.o main.o dmlc_simple.o
|
||||
MPIBIN =
|
||||
TARGET = $(BIN) $(OBJ) $(SLIB)
|
||||
.PHONY: clean all lint clean_all doxygen rcpplint pypack Rpack Rbuild Rcheck java pylint
|
||||
|
||||
.PHONY: clean all mpi python Rpack
|
||||
|
||||
all: $(BIN) $(OBJ) $(SLIB)
|
||||
mpi: $(MPIBIN)
|
||||
all: lib/libxgboost.a $(XGBOOST_DYLIB) xgboost
|
||||
|
||||
python: wrapper/libxgboostwrapper.so
|
||||
# now the wrapper takes in two files. io and wrapper part
|
||||
updater.o: src/tree/updater.cpp src/tree/*.hpp src/*.h src/tree/*.h src/utils/*.h
|
||||
dmlc_simple.o: src/io/dmlc_simple.cpp src/utils/*.h
|
||||
gbm.o: src/gbm/gbm.cpp src/gbm/*.hpp src/gbm/*.h
|
||||
io.o: src/io/io.cpp src/io/*.hpp src/utils/*.h src/learner/dmatrix.h src/*.h
|
||||
main.o: src/xgboost_main.cpp src/utils/*.h src/*.h src/learner/*.hpp src/learner/*.h
|
||||
xgboost: updater.o gbm.o io.o main.o $(LIBRABIT) $(LIBDMLC)
|
||||
wrapper/xgboost_wrapper.dll wrapper/libxgboostwrapper.so: wrapper/xgboost_wrapper.cpp src/utils/*.h src/*.h src/learner/*.hpp src/learner/*.h updater.o gbm.o io.o $(LIBRABIT) $(LIBDMLC)
|
||||
$(DMLC_CORE)/libdmlc.a: $(wildcard $(DMLC_CORE)/src/*.cc $(DMLC_CORE)/src/*/*.cc)
|
||||
+ cd $(DMLC_CORE); $(MAKE) libdmlc.a config=$(ROOTDIR)/$(config); cd $(ROOTDIR)
|
||||
|
||||
# dependency on rabit
|
||||
subtree/rabit/lib/librabit.a: subtree/rabit/src/engine.cc
|
||||
+ cd subtree/rabit;make lib/librabit.a; cd ../..
|
||||
subtree/rabit/lib/librabit_empty.a: subtree/rabit/src/engine_empty.cc
|
||||
+ cd subtree/rabit;make lib/librabit_empty.a; cd ../..
|
||||
subtree/rabit/lib/librabit_mock.a: subtree/rabit/src/engine_mock.cc
|
||||
+ cd subtree/rabit;make lib/librabit_mock.a; cd ../..
|
||||
subtree/rabit/lib/librabit_mpi.a: subtree/rabit/src/engine_mpi.cc
|
||||
+ cd subtree/rabit;make lib/librabit_mpi.a; cd ../..
|
||||
$(RABIT)/lib/$(LIB_RABIT): $(wildcard $(RABIT)/src/*.cc)
|
||||
+ cd $(RABIT); $(MAKE) lib/$(LIB_RABIT); cd $(ROOTDIR)
|
||||
|
||||
$(BIN) :
|
||||
$(CXX) $(CFLAGS) -o $@ $(filter %.cpp %.o %.c %.cc %.a, $^) $(LDFLAGS)
|
||||
jvm: jvm-packages/lib/libxgboost4j.so
|
||||
|
||||
$(MOCKBIN) :
|
||||
$(CXX) $(CFLAGS) -o $@ $(filter %.cpp %.o %.c %.cc %.a, $^) $(LDFLAGS)
|
||||
SRC = $(wildcard src/*.cc src/*/*.cc)
|
||||
ALL_OBJ = $(patsubst src/%.cc, build/%.o, $(SRC)) $(PLUGIN_OBJS)
|
||||
AMALGA_OBJ = amalgamation/xgboost-all0.o
|
||||
LIB_DEP = $(DMLC_CORE)/libdmlc.a $(RABIT)/lib/$(LIB_RABIT)
|
||||
ALL_DEP = $(filter-out build/cli_main.o, $(ALL_OBJ)) $(LIB_DEP)
|
||||
CLI_OBJ = build/cli_main.o
|
||||
|
||||
$(SLIB) :
|
||||
$(CXX) $(CFLAGS) -fPIC -shared -o $@ $(filter %.cpp %.o %.c %.a %.cc, $^) $(LDFLAGS) $(DLLFLAGS)
|
||||
build/%.o: src/%.cc
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) -MM -MT build/$*.o $< >build/$*.d
|
||||
$(CXX) -c $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJ) :
|
||||
$(CXX) -c $(CFLAGS) -o $@ $(firstword $(filter %.cpp %.c %.cc, $^) )
|
||||
build_plugin/%.o: plugin/%.cc
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) -MM -MT build_plugin/$*.o $< >build_plugin/$*.d
|
||||
$(CXX) -c $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(MPIOBJ) :
|
||||
$(MPICXX) -c $(CFLAGS) -o $@ $(firstword $(filter %.cpp %.c, $^) )
|
||||
# The should be equivalent to $(ALL_OBJ) except for build/cli_main.o
|
||||
amalgamation/xgboost-all0.o: amalgamation/xgboost-all0.cc
|
||||
$(CXX) -c $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(MPIBIN) :
|
||||
$(MPICXX) $(CFLAGS) -o $@ $(filter %.cpp %.o %.c %.cc %.a, $^) $(LDFLAGS)
|
||||
# Equivalent to lib/libxgboost_all.so
|
||||
lib/libxgboost_all.so: $(AMALGA_OBJ) $(LIB_DEP)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) -shared -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
|
||||
|
||||
install:
|
||||
cp -f -r $(BIN) $(INSTALL_PATH)
|
||||
lib/libxgboost.a: $(ALL_DEP)
|
||||
@mkdir -p $(@D)
|
||||
ar crv $@ $(filter %.o, $?)
|
||||
|
||||
lib/libxgboost.dll lib/libxgboost.so: $(ALL_DEP)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) -shared -o $@ $(filter %.o %a, $^) $(LDFLAGS)
|
||||
|
||||
jvm-packages/lib/libxgboost4j.so: jvm-packages/xgboost4j/src/native/xgboost4j.cpp $(ALL_DEP)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) $(JAVAINCFLAGS) -shared -o $@ $(filter %.cpp %.o %.a, $^) $(LDFLAGS)
|
||||
|
||||
xgboost: $(CLI_OBJ) $(ALL_DEP)
|
||||
$(CXX) $(CFLAGS) -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
|
||||
|
||||
rcpplint:
|
||||
python2 dmlc-core/scripts/lint.py xgboost ${LINT_LANG} R-package/src
|
||||
|
||||
lint: rcpplint
|
||||
python2 dmlc-core/scripts/lint.py xgboost ${LINT_LANG} include src plugin python-package
|
||||
|
||||
pylint:
|
||||
flake8 --ignore E501 python-package
|
||||
flake8 --ignore E501 tests/python
|
||||
clean:
|
||||
$(RM) -rf build build_plugin lib bin *~ */*~ */*/*~ */*/*/*~ */*.o */*/*.o */*/*/*.o xgboost
|
||||
|
||||
clean_all: clean
|
||||
cd $(DMLC_CORE); $(MAKE) clean; cd $(ROODIR)
|
||||
cd $(RABIT); $(MAKE) clean; cd $(ROODIR)
|
||||
|
||||
doxygen:
|
||||
doxygen doc/Doxyfile
|
||||
|
||||
# create standalone python tar file.
|
||||
pypack: ${XGBOOST_DYLIB}
|
||||
cp ${XGBOOST_DYLIB} python-package/xgboost
|
||||
cd python-package; tar cf xgboost.tar xgboost; cd ..
|
||||
|
||||
# Script to make a clean installable R package.
|
||||
Rpack:
|
||||
make clean
|
||||
cd subtree/rabit;make clean;cd ..
|
||||
$(MAKE) clean_all
|
||||
rm -rf xgboost xgboost*.tar.gz
|
||||
cp -r R-package xgboost
|
||||
rm -rf xgboost/src/*.o xgboost/src/*.so xgboost/src/*.dll
|
||||
rm -rf xgboost/src/*/*.o
|
||||
rm -rf subtree/rabit/src/*.o
|
||||
rm -rf xgboost/demo/*.model xgboost/demo/*.buffer xgboost/demo/*.txt
|
||||
rm -rf xgboost/demo/runall.R
|
||||
cp -r src xgboost/src/src
|
||||
mkdir xgboost/src/subtree
|
||||
mkdir xgboost/src/subtree/rabit
|
||||
cp -r subtree/rabit/include xgboost/src/subtree/rabit/include
|
||||
cp -r subtree/rabit/src xgboost/src/subtree/rabit/src
|
||||
rm -rf xgboost/src/subtree/rabit/src/*.o
|
||||
mkdir xgboost/src/wrapper
|
||||
cp wrapper/xgboost_wrapper.h xgboost/src/wrapper
|
||||
cp wrapper/xgboost_wrapper.cpp xgboost/src/wrapper
|
||||
cp -r include xgboost/src/include
|
||||
cp -r amalgamation xgboost/src/amalgamation
|
||||
mkdir -p xgboost/src/rabit
|
||||
cp -r rabit/include xgboost/src/rabit/include
|
||||
cp -r rabit/src xgboost/src/rabit/src
|
||||
rm -rf xgboost/src/rabit/src/*.o
|
||||
mkdir -p xgboost/src/dmlc-core
|
||||
cp -r dmlc-core/include xgboost/src/dmlc-core/include
|
||||
cp -r dmlc-core/src xgboost/src/dmlc-core/src
|
||||
cp ./LICENSE xgboost
|
||||
cat R-package/src/Makevars|sed '2s/.*/PKGROOT=./' > xgboost/src/Makevars
|
||||
cat R-package/src/Makevars|sed '2s/.*/PKGROOT=./' | sed '3s/.*/ENABLE_STD_THREAD=0/' > xgboost/src/Makevars
|
||||
cp xgboost/src/Makevars xgboost/src/Makevars.win
|
||||
# R CMD build --no-build-vignettes xgboost
|
||||
R CMD build xgboost
|
||||
rm -rf xgboost
|
||||
R CMD check --as-cran xgboost*.tar.gz
|
||||
|
||||
clean:
|
||||
$(RM) -rf $(OBJ) $(BIN) $(MPIBIN) $(MPIOBJ) $(SLIB) *.o */*.o */*/*.o *~ */*~ */*/*~
|
||||
cd subtree/rabit; make clean; cd ..
|
||||
Rbuild:
|
||||
$(MAKE) Rpack
|
||||
R CMD build --no-build-vignettes xgboost
|
||||
rm -rf xgboost
|
||||
|
||||
Rcheck:
|
||||
$(MAKE) Rbuild
|
||||
R CMD check xgboost*.tar.gz
|
||||
|
||||
-include build/*.d
|
||||
-include build/*/*.d
|
||||
-include build_plugin/*/*.d
|
||||
|
||||
104
NEWS.md
Normal file
104
NEWS.md
Normal file
@@ -0,0 +1,104 @@
|
||||
XGBoost Change Log
|
||||
==================
|
||||
|
||||
This file records the changes in xgboost library in reverse chronological order.
|
||||
|
||||
## v0.6 (2016.07.29)
|
||||
* Version 0.5 is skipped due to major improvements in the core
|
||||
* Major refactor of core library.
|
||||
- Goal: more flexible and modular code as a portable library.
|
||||
- Switch to use of c++11 standard code.
|
||||
- Random number generator defaults to ```std::mt19937```.
|
||||
- Share the data loading pipeline and logging module from dmlc-core.
|
||||
- Enable registry pattern to allow optionally plugin of objective, metric, tree constructor, data loader.
|
||||
- Future plugin modules can be put into xgboost/plugin and register back to the library.
|
||||
- Remove most of the raw pointers to smart ptrs, for RAII safety.
|
||||
* Add official option to approximate algorithm `tree_method` to parameter.
|
||||
- Change default behavior to switch to prefer faster algorithm.
|
||||
- User will get a message when approximate algorithm is chosen.
|
||||
* Change library name to libxgboost.so
|
||||
* Backward compatiblity
|
||||
- The binary buffer file is not backward compatible with previous version.
|
||||
- The model file is backward compatible on 64 bit platforms.
|
||||
* The model file is compatible between 64/32 bit platforms(not yet tested).
|
||||
* External memory version and other advanced features will be exposed to R library as well on linux.
|
||||
- Previously some of the features are blocked due to C++11 and threading limits.
|
||||
- The windows version is still blocked due to Rtools do not support ```std::thread```.
|
||||
* rabit and dmlc-core are maintained through git submodule
|
||||
- Anyone can open PR to update these dependencies now.
|
||||
* Improvements
|
||||
- Rabit and xgboost libs are not thread-safe and use thread local PRNGs
|
||||
- This could fix some of the previous problem which runs xgboost on multiple threads.
|
||||
* JVM Package
|
||||
- Enable xgboost4j for java and scala
|
||||
- XGBoost distributed now runs on Flink and Spark.
|
||||
* Support model attributes listing for meta data.
|
||||
- https://github.com/dmlc/xgboost/pull/1198
|
||||
- https://github.com/dmlc/xgboost/pull/1166
|
||||
* Support callback API
|
||||
- https://github.com/dmlc/xgboost/issues/892
|
||||
- https://github.com/dmlc/xgboost/pull/1211
|
||||
- https://github.com/dmlc/xgboost/pull/1264
|
||||
* Support new booster DART(dropout in tree boosting)
|
||||
- https://github.com/dmlc/xgboost/pull/1220
|
||||
* Add CMake build system
|
||||
- https://github.com/dmlc/xgboost/pull/1314
|
||||
|
||||
## v0.47 (2016.01.14)
|
||||
|
||||
* Changes in R library
|
||||
- fixed possible problem of poisson regression.
|
||||
- switched from 0 to NA for missing values.
|
||||
- exposed access to additional model parameters.
|
||||
* Changes in Python library
|
||||
- throws exception instead of crash terminal when a parameter error happens.
|
||||
- has importance plot and tree plot functions.
|
||||
- accepts different learning rates for each boosting round.
|
||||
- allows model training continuation from previously saved model.
|
||||
- allows early stopping in CV.
|
||||
- allows feval to return a list of tuples.
|
||||
- allows eval_metric to handle additional format.
|
||||
- improved compatibility in sklearn module.
|
||||
- additional parameters added for sklearn wrapper.
|
||||
- added pip installation functionality.
|
||||
- supports more Pandas DataFrame dtypes.
|
||||
- added best_ntree_limit attribute, in addition to best_score and best_iteration.
|
||||
* Java api is ready for use
|
||||
* Added more test cases and continuous integration to make each build more robust.
|
||||
|
||||
## v0.4 (2015.05.11)
|
||||
|
||||
* Distributed version of xgboost that runs on YARN, scales to billions of examples
|
||||
* Direct save/load data and model from/to S3 and HDFS
|
||||
* Feature importance visualization in R module, by Michael Benesty
|
||||
* Predict leaf index
|
||||
* Poisson regression for counts data
|
||||
* Early stopping option in training
|
||||
* Native save load support in R and python
|
||||
- xgboost models now can be saved using save/load in R
|
||||
- xgboost python model is now pickable
|
||||
* sklearn wrapper is supported in python module
|
||||
* Experimental External memory version
|
||||
|
||||
|
||||
## v0.3 (2014.09.07)
|
||||
|
||||
* Faster tree construction module
|
||||
- Allows subsample columns during tree construction via ```bst:col_samplebytree=ratio```
|
||||
* Support for boosting from initial predictions
|
||||
* Experimental version of LambdaRank
|
||||
* Linear booster is now parallelized, using parallel coordinated descent.
|
||||
* Add [Code Guide](src/README.md) for customizing objective function and evaluation
|
||||
* Add R module
|
||||
|
||||
|
||||
## v0.2x (2014.05.20)
|
||||
|
||||
* Python module
|
||||
* Weighted samples instances
|
||||
* Initial version of pairwise rank
|
||||
|
||||
|
||||
## v0.1 (2014.03.26)
|
||||
|
||||
* Initial release
|
||||
@@ -3,3 +3,4 @@
|
||||
\.dll$
|
||||
^.*\.Rproj$
|
||||
^\.Rproj\.user$
|
||||
README.md
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
Package: xgboost
|
||||
Type: Package
|
||||
Title: eXtreme Gradient Boosting
|
||||
Version: 0.4-0
|
||||
Date: 2015-05-11
|
||||
Author: Tianqi Chen <tianqi.tchen@gmail.com>, Tong He <hetong007@gmail.com>, Michael Benesty <michael@benesty.fr>
|
||||
Title: Extreme Gradient Boosting
|
||||
Version: 0.6-0
|
||||
Date: 2015-08-01
|
||||
Author: Tianqi Chen <tianqi.tchen@gmail.com>, Tong He <hetong007@gmail.com>,
|
||||
Michael Benesty <michael@benesty.fr>, Vadim Khotilovich <khotilovich@gmail.com>,
|
||||
Yuan Tang <terrytangyuan@gmail.com>
|
||||
Maintainer: Tong He <hetong007@gmail.com>
|
||||
Description: Xgboost is short for eXtreme Gradient Boosting, which is an
|
||||
efficient and scalable implementation of gradient boosting framework.
|
||||
This package is an R wrapper of xgboost. The package includes efficient
|
||||
linear model solver and tree learning algorithms. The package can automatically
|
||||
do parallel computation with OpenMP, and it can be more than 10 times faster
|
||||
than existing gradient boosting packages such as gbm. It supports various
|
||||
objective functions, including regression, classification and ranking. The
|
||||
package is made to be extensible, so that users are also allowed to define
|
||||
Description: Extreme Gradient Boosting, which is an efficient implementation
|
||||
of gradient boosting framework. This package is its R interface. The package
|
||||
includes efficient linear model solver and tree learning algorithms. The package
|
||||
can automatically do parallel computation on a single machine which could be
|
||||
more than 10 times faster than existing gradient boosting packages. It supports
|
||||
various objective functions, including regression, classification and ranking.
|
||||
The package is made to be extensible, so that users are also allowed to define
|
||||
their own objectives easily.
|
||||
License: Apache License (== 2.0) | file LICENSE
|
||||
URL: https://github.com/dmlc/xgboost
|
||||
@@ -20,15 +21,19 @@ BugReports: https://github.com/dmlc/xgboost/issues
|
||||
VignetteBuilder: knitr
|
||||
Suggests:
|
||||
knitr,
|
||||
ggplot2 (>= 1.0.0),
|
||||
DiagrammeR (>= 0.6),
|
||||
rmarkdown,
|
||||
ggplot2 (>= 1.0.1),
|
||||
DiagrammeR (>= 0.8.1),
|
||||
Ckmeans.1d.dp (>= 3.3.1),
|
||||
vcd (>= 1.3)
|
||||
vcd (>= 1.3),
|
||||
testthat,
|
||||
igraph (>= 1.0.1)
|
||||
Depends:
|
||||
R (>= 2.10)
|
||||
Imports:
|
||||
Matrix (>= 1.1-0),
|
||||
methods,
|
||||
data.table (>= 1.9.4),
|
||||
data.table (>= 1.9.6),
|
||||
magrittr (>= 1.5),
|
||||
stringr (>= 0.6.2)
|
||||
stringi (>= 0.5.2)
|
||||
RoxygenNote: 5.0.1
|
||||
|
||||
@@ -1,43 +1,71 @@
|
||||
# Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
# Generated by roxygen2: do not edit by hand
|
||||
|
||||
S3method("[",xgb.DMatrix)
|
||||
S3method("dimnames<-",xgb.DMatrix)
|
||||
S3method(dim,xgb.DMatrix)
|
||||
S3method(dimnames,xgb.DMatrix)
|
||||
S3method(getinfo,xgb.DMatrix)
|
||||
S3method(predict,xgb.Booster)
|
||||
S3method(predict,xgb.Booster.handle)
|
||||
S3method(print,xgb.Booster)
|
||||
S3method(print,xgb.DMatrix)
|
||||
S3method(print,xgb.cv.synchronous)
|
||||
S3method(setinfo,xgb.DMatrix)
|
||||
S3method(slice,xgb.DMatrix)
|
||||
export("xgb.attr<-")
|
||||
export("xgb.attributes<-")
|
||||
export("xgb.parameters<-")
|
||||
export(cb.cv.predict)
|
||||
export(cb.early.stop)
|
||||
export(cb.evaluation.log)
|
||||
export(cb.print.evaluation)
|
||||
export(cb.reset.parameters)
|
||||
export(cb.save.model)
|
||||
export(getinfo)
|
||||
export(setinfo)
|
||||
export(slice)
|
||||
export(xgb.DMatrix)
|
||||
export(xgb.DMatrix.save)
|
||||
export(xgb.attr)
|
||||
export(xgb.attributes)
|
||||
export(xgb.create.features)
|
||||
export(xgb.cv)
|
||||
export(xgb.dump)
|
||||
export(xgb.ggplot.deepness)
|
||||
export(xgb.ggplot.importance)
|
||||
export(xgb.importance)
|
||||
export(xgb.load)
|
||||
export(xgb.model.dt.tree)
|
||||
export(xgb.plot.deepness)
|
||||
export(xgb.plot.importance)
|
||||
export(xgb.plot.multi.trees)
|
||||
export(xgb.plot.tree)
|
||||
export(xgb.save)
|
||||
export(xgb.save.raw)
|
||||
export(xgb.train)
|
||||
export(xgboost)
|
||||
exportMethods(nrow)
|
||||
exportMethods(predict)
|
||||
import(methods)
|
||||
importClassesFrom(Matrix,dgCMatrix)
|
||||
importClassesFrom(Matrix,dgeMatrix)
|
||||
importFrom(Matrix,cBind)
|
||||
importFrom(Matrix,colSums)
|
||||
importFrom(Matrix,sparse.model.matrix)
|
||||
importFrom(Matrix,sparseVector)
|
||||
importFrom(data.table,":=")
|
||||
importFrom(data.table,as.data.table)
|
||||
importFrom(data.table,copy)
|
||||
importFrom(data.table,data.table)
|
||||
importFrom(data.table,fread)
|
||||
importFrom(data.table,rbindlist)
|
||||
importFrom(data.table,set)
|
||||
importFrom(data.table,setkey)
|
||||
importFrom(data.table,setkeyv)
|
||||
importFrom(data.table,setnames)
|
||||
importFrom(magrittr,"%>%")
|
||||
importFrom(magrittr,add)
|
||||
importFrom(magrittr,not)
|
||||
importFrom(stringr,str_extract)
|
||||
importFrom(stringr,str_extract_all)
|
||||
importFrom(stringr,str_match)
|
||||
importFrom(stringr,str_replace)
|
||||
importFrom(stringr,str_split)
|
||||
importFrom(stringr,str_trim)
|
||||
importFrom(stats,predict)
|
||||
importFrom(stringi,stri_detect_regex)
|
||||
importFrom(stringi,stri_match_first_regex)
|
||||
importFrom(stringi,stri_replace_all_regex)
|
||||
importFrom(stringi,stri_replace_first_regex)
|
||||
importFrom(stringi,stri_split_regex)
|
||||
importFrom(utils,object.size)
|
||||
importFrom(utils,str)
|
||||
importFrom(utils,tail)
|
||||
useDynLib(xgboost)
|
||||
|
||||
608
R-package/R/callbacks.R
Normal file
608
R-package/R/callbacks.R
Normal file
@@ -0,0 +1,608 @@
|
||||
#' Callback closures for booster training.
|
||||
#'
|
||||
#' These are used to perform various service tasks either during boosting iterations or at the end.
|
||||
#' This approach helps to modularize many of such tasks without bloating the main training methods,
|
||||
#' and it offers .
|
||||
#'
|
||||
#' @details
|
||||
#' By default, a callback function is run after each boosting iteration.
|
||||
#' An R-attribute \code{is_pre_iteration} could be set for a callback to define a pre-iteration function.
|
||||
#'
|
||||
#' When a callback function has \code{finalize} parameter, its finalizer part will also be run after
|
||||
#' the boosting is completed.
|
||||
#'
|
||||
#' WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
||||
#' the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
||||
#'
|
||||
#' To write a custom callback closure, make sure you first understand the main concepts about R envoronments.
|
||||
#' Check either R documentation on \code{\link[base]{environment}} or the
|
||||
#' \href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
||||
#' book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
||||
#' choose ones that do something similar to what you want to achieve. Also, you would need to get familiar
|
||||
#' with the objects available inside of the \code{xgb.train} and \code{xgb.cv} internal environments.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{cb.print.evaluation}},
|
||||
#' \code{\link{cb.evaluation.log}},
|
||||
#' \code{\link{cb.reset.parameters}},
|
||||
#' \code{\link{cb.early.stop}},
|
||||
#' \code{\link{cb.save.model}},
|
||||
#' \code{\link{cb.cv.predict}},
|
||||
#' \code{\link{xgb.train}},
|
||||
#' \code{\link{xgb.cv}}
|
||||
#'
|
||||
#' @name callbacks
|
||||
NULL
|
||||
|
||||
#
|
||||
# Callbacks -------------------------------------------------------------------
|
||||
#
|
||||
|
||||
#' Callback closure for printing the result of evaluation
|
||||
#'
|
||||
#' @param period results would be printed every number of periods
|
||||
#'
|
||||
#' @details
|
||||
#' The callback function prints the result of evaluation at every \code{period} iterations.
|
||||
#' The initial and the last iteration's evaluations are always printed.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{bst_evaluation} (also \code{bst_evaluation_err} when available),
|
||||
#' \code{iteration},
|
||||
#' \code{begin_iteration},
|
||||
#' \code{end_iteration}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}}
|
||||
#'
|
||||
#' @export
|
||||
cb.print.evaluation <- function(period=1) {
|
||||
|
||||
callback <- function(env = parent.frame()) {
|
||||
if (length(env$bst_evaluation) == 0 ||
|
||||
period == 0 ||
|
||||
NVL(env$rank, 0) != 0 )
|
||||
return()
|
||||
|
||||
i <- env$iteration
|
||||
if ((i-1) %% period == 0 ||
|
||||
i == env$begin_iteration ||
|
||||
i == env$end_iteration) {
|
||||
msg <- format.eval.string(i, env$bst_evaluation, env$bst_evaluation_err)
|
||||
cat(msg, '\n')
|
||||
}
|
||||
}
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.print.evaluation'
|
||||
callback
|
||||
}
|
||||
|
||||
|
||||
#' Callback closure for logging the evaluation history
|
||||
#'
|
||||
#' @details
|
||||
#' This callback function appends the current iteration evaluation results \code{bst_evaluation}
|
||||
#' available in the calling parent frame to the \code{evaluation_log} list in a calling frame.
|
||||
#'
|
||||
#' The finalizer callback (called with \code{finalize = TURE} in the end) converts
|
||||
#' the \code{evaluation_log} list into a final data.table.
|
||||
#'
|
||||
#' The iteration evaluation result \code{bst_evaluation} must be a named numeric vector.
|
||||
#'
|
||||
#' Note: in the column names of the final data.table, the dash '-' character is replaced with
|
||||
#' the underscore '_' in order to make the column names more like regular R identifiers.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{evaluation_log},
|
||||
#' \code{bst_evaluation},
|
||||
#' \code{iteration}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}}
|
||||
#'
|
||||
#' @export
|
||||
cb.evaluation.log <- function() {
|
||||
|
||||
mnames <- NULL
|
||||
|
||||
init <- function(env) {
|
||||
if (!is.list(env$evaluation_log))
|
||||
stop("'evaluation_log' has to be a list")
|
||||
mnames <<- names(env$bst_evaluation)
|
||||
if (is.null(mnames) || any(mnames == ""))
|
||||
stop("bst_evaluation must have non-empty names")
|
||||
|
||||
mnames <<- gsub('-', '_', names(env$bst_evaluation))
|
||||
if(!is.null(env$bst_evaluation_err))
|
||||
mnames <<- c(paste0(mnames, '_mean'), paste0(mnames, '_std'))
|
||||
}
|
||||
|
||||
finalizer <- function(env) {
|
||||
env$evaluation_log <- as.data.table(t(simplify2array(env$evaluation_log)))
|
||||
setnames(env$evaluation_log, c('iter', mnames))
|
||||
|
||||
if(!is.null(env$bst_evaluation_err)) {
|
||||
# rearrange col order from _mean,_mean,...,_std,_std,...
|
||||
# to be _mean,_std,_mean,_std,...
|
||||
len <- length(mnames)
|
||||
means <- mnames[1:(len/2)]
|
||||
stds <- mnames[(len/2 + 1):len]
|
||||
cnames <- numeric(len)
|
||||
cnames[c(TRUE, FALSE)] <- means
|
||||
cnames[c(FALSE, TRUE)] <- stds
|
||||
env$evaluation_log <- env$evaluation_log[, c('iter', cnames), with=FALSE]
|
||||
}
|
||||
}
|
||||
|
||||
callback <- function(env = parent.frame(), finalize = FALSE) {
|
||||
if (is.null(mnames))
|
||||
init(env)
|
||||
|
||||
if (finalize)
|
||||
return(finalizer(env))
|
||||
|
||||
ev <- env$bst_evaluation
|
||||
if(!is.null(env$bst_evaluation_err))
|
||||
ev <- c(ev, env$bst_evaluation_err)
|
||||
env$evaluation_log <- c(env$evaluation_log,
|
||||
list(c(iter = env$iteration, ev)))
|
||||
}
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.evaluation.log'
|
||||
callback
|
||||
}
|
||||
|
||||
#' Callback closure for restetting the booster's parameters at each iteration.
|
||||
#'
|
||||
#' @param new_params a list where each element corresponds to a parameter that needs to be reset.
|
||||
#' Each element's value must be either a vector of values of length \code{nrounds}
|
||||
#' to be set at each iteration,
|
||||
#' or a function of two parameters \code{learning_rates(iteration, nrounds)}
|
||||
#' which returns a new parameter value by using the current iteration number
|
||||
#' and the total number of boosting rounds.
|
||||
#'
|
||||
#' @details
|
||||
#' This is a "pre-iteration" callback function used to reset booster's parameters
|
||||
#' at the beginning of each iteration.
|
||||
#'
|
||||
#' Note that when training is resumed from some previous model, and a function is used to
|
||||
#' reset a parameter value, the \code{nround} argument in this function would be the
|
||||
#' the number of boosting rounds in the current training.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{bst} or \code{bst_folds},
|
||||
#' \code{iteration},
|
||||
#' \code{begin_iteration},
|
||||
#' \code{end_iteration}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}}
|
||||
#'
|
||||
#' @export
|
||||
cb.reset.parameters <- function(new_params) {
|
||||
|
||||
if (typeof(new_params) != "list")
|
||||
stop("'new_params' must be a list")
|
||||
pnames <- gsub("\\.", "_", names(new_params))
|
||||
nrounds <- NULL
|
||||
|
||||
# run some checks in the begining
|
||||
init <- function(env) {
|
||||
nrounds <<- env$end_iteration - env$begin_iteration + 1
|
||||
|
||||
if (is.null(env$bst) && is.null(env$bst_folds))
|
||||
stop("Parent frame has neither 'bst' nor 'bst_folds'")
|
||||
|
||||
# Some parameters are not allowed to be changed,
|
||||
# since changing them would simply wreck some chaos
|
||||
not_allowed <- pnames %in%
|
||||
c('num_class', 'num_output_group', 'size_leaf_vector', 'updater_seq')
|
||||
if (any(not_allowed))
|
||||
stop('Parameters ', paste(pnames[not_allowed]), " cannot be changed during boosting.")
|
||||
|
||||
for (n in pnames) {
|
||||
p <- new_params[[n]]
|
||||
if (is.function(p)) {
|
||||
if (length(formals(p)) != 2)
|
||||
stop("Parameter '", n, "' is a function but not of two arguments")
|
||||
} else if (is.numeric(p) || is.character(p)) {
|
||||
if (length(p) != nrounds)
|
||||
stop("Length of '", n, "' has to be equal to 'nrounds'")
|
||||
} else {
|
||||
stop("Parameter '", n, "' is not a function or a vector")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback <- function(env = parent.frame()) {
|
||||
if (is.null(nrounds))
|
||||
init(env)
|
||||
|
||||
i <- env$iteration
|
||||
pars <- lapply(new_params, function(p) {
|
||||
if (is.function(p))
|
||||
return(p(i, nrounds))
|
||||
p[i]
|
||||
})
|
||||
|
||||
if (!is.null(env$bst)) {
|
||||
xgb.parameters(env$bst$handle) <- pars
|
||||
} else {
|
||||
for (fd in env$bst_folds)
|
||||
xgb.parameters(fd$bst$handle) <- pars
|
||||
}
|
||||
}
|
||||
attr(callback, 'is_pre_iteration') <- TRUE
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.reset.parameters'
|
||||
callback
|
||||
}
|
||||
|
||||
|
||||
#' Callback closure to activate the early stopping.
|
||||
#'
|
||||
#' @param stopping_rounds The number of rounds with no improvement in
|
||||
#' the evaluation metric in order to stop the training.
|
||||
#' @param maximize whether to maximize the evaluation metric
|
||||
#' @param metric_name the name of an evaluation column to use as a criteria for early
|
||||
#' stopping. If not set, the last column would be used.
|
||||
#' Let's say the test data in \code{watchlist} was labelled as \code{dtest},
|
||||
#' and one wants to use the AUC in test data for early stopping regardless of where
|
||||
#' it is in the \code{watchlist}, then one of the following would need to be set:
|
||||
#' \code{metric_name='dtest-auc'} or \code{metric_name='dtest_auc'}.
|
||||
#' All dash '-' characters in metric names are considered equivalent to '_'.
|
||||
#' @param verbose whether to print the early stopping information.
|
||||
#'
|
||||
#' @details
|
||||
#' This callback function determines the condition for early stopping
|
||||
#' by setting the \code{stop_condition = TRUE} flag in its calling frame.
|
||||
#'
|
||||
#' The following additional fields are assigned to the model's R object:
|
||||
#' \itemize{
|
||||
#' \item \code{best_score} the evaluation score at the best iteration
|
||||
#' \item \code{best_iteration} at which boosting iteration the best score has occurred (1-based index)
|
||||
#' \item \code{best_ntreelimit} to use with the \code{ntreelimit} parameter in \code{predict}.
|
||||
#' It differs from \code{best_iteration} in multiclass or random forest settings.
|
||||
#' }
|
||||
#'
|
||||
#' The Same values are also stored as xgb-attributes:
|
||||
#' \itemize{
|
||||
#' \item \code{best_iteration} is stored as a 0-based iteration index (for interoperability of binary models)
|
||||
#' \item \code{best_msg} message string is also stored.
|
||||
#' }
|
||||
#'
|
||||
#' At least one data element is required in the evaluation watchlist for early stopping to work.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{stop_condition},
|
||||
#' \code{bst_evaluation},
|
||||
#' \code{rank},
|
||||
#' \code{bst} (or \code{bst_folds} and \code{basket}),
|
||||
#' \code{iteration},
|
||||
#' \code{begin_iteration},
|
||||
#' \code{end_iteration},
|
||||
#' \code{num_parallel_tree}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}},
|
||||
#' \code{\link{xgb.attr}}
|
||||
#'
|
||||
#' @export
|
||||
cb.early.stop <- function(stopping_rounds, maximize=FALSE,
|
||||
metric_name=NULL, verbose=TRUE) {
|
||||
# state variables
|
||||
best_iteration <- -1
|
||||
best_ntreelimit <- -1
|
||||
best_score <- Inf
|
||||
best_msg <- NULL
|
||||
metric_idx <- 1
|
||||
|
||||
init <- function(env) {
|
||||
if (length(env$bst_evaluation) == 0)
|
||||
stop("For early stopping, watchlist must have at least one element")
|
||||
|
||||
eval_names <- gsub('-', '_', names(env$bst_evaluation))
|
||||
if (!is.null(metric_name)) {
|
||||
metric_idx <<- which(gsub('-', '_', metric_name) == eval_names)
|
||||
if (length(metric_idx) == 0)
|
||||
stop("'metric_name' for early stopping is not one of the following:\n",
|
||||
paste(eval_names, collapse=' '), '\n')
|
||||
}
|
||||
if (is.null(metric_name) &&
|
||||
length(env$bst_evaluation) > 1) {
|
||||
metric_idx <<- length(eval_names)
|
||||
if (verbose)
|
||||
cat('Multiple eval metrics are present. Will use ',
|
||||
eval_names[metric_idx], ' for early stopping.\n', sep = '')
|
||||
}
|
||||
|
||||
metric_name <<- eval_names[metric_idx]
|
||||
|
||||
# maximixe is usually NULL when not set in xgb.train and built-in metrics
|
||||
if (is.null(maximize))
|
||||
maximize <<- ifelse(grepl('(_auc|_map|_ndcg)', metric_name), TRUE, FALSE)
|
||||
|
||||
if (verbose && NVL(env$rank, 0) == 0)
|
||||
cat("Will train until ", metric_name, " hasn't improved in ",
|
||||
stopping_rounds, " rounds.\n\n", sep = '')
|
||||
|
||||
best_iteration <<- 1
|
||||
if (maximize) best_score <<- -Inf
|
||||
|
||||
env$stop_condition <- FALSE
|
||||
|
||||
if (!is.null(env$bst)) {
|
||||
if (class(env$bst) != 'xgb.Booster')
|
||||
stop("'bst' in the parent frame must be an 'xgb.Booster'")
|
||||
if (!is.null(best_score <- xgb.attr(env$bst$handle, 'best_score'))) {
|
||||
best_score <<- as.numeric(best_score)
|
||||
best_iteration <<- as.numeric(xgb.attr(env$bst$handle, 'best_iteration')) + 1
|
||||
best_msg <<- as.numeric(xgb.attr(env$bst$handle, 'best_msg'))
|
||||
} else {
|
||||
xgb.attributes(env$bst$handle) <- list(best_iteration = best_iteration - 1,
|
||||
best_score = best_score)
|
||||
}
|
||||
} else if (is.null(env$bst_folds) || is.null(env$basket)) {
|
||||
stop("Parent frame has neither 'bst' nor ('bst_folds' and 'basket')")
|
||||
}
|
||||
}
|
||||
|
||||
finalizer <- function(env) {
|
||||
if (!is.null(env$bst)) {
|
||||
attr_best_score = as.numeric(xgb.attr(env$bst$handle, 'best_score'))
|
||||
if (best_score != attr_best_score)
|
||||
stop("Inconsistent 'best_score' values between the closure state: ", best_score,
|
||||
" and the xgb.attr: ", attr_best_score)
|
||||
env$bst$best_iteration = best_iteration
|
||||
env$bst$best_ntreelimit = best_ntreelimit
|
||||
env$bst$best_score = best_score
|
||||
} else {
|
||||
env$basket$best_iteration <- best_iteration
|
||||
env$basket$best_ntreelimit <- best_ntreelimit
|
||||
}
|
||||
}
|
||||
|
||||
callback <- function(env = parent.frame(), finalize = FALSE) {
|
||||
if (best_iteration < 0)
|
||||
init(env)
|
||||
|
||||
if (finalize)
|
||||
return(finalizer(env))
|
||||
|
||||
i <- env$iteration
|
||||
score = env$bst_evaluation[metric_idx]
|
||||
|
||||
if (( maximize && score > best_score) ||
|
||||
(!maximize && score < best_score)) {
|
||||
|
||||
best_msg <<- format.eval.string(i, env$bst_evaluation, env$bst_evaluation_err)
|
||||
best_score <<- score
|
||||
best_iteration <<- i
|
||||
best_ntreelimit <<- best_iteration * env$num_parallel_tree
|
||||
# save the property to attributes, so they will occur in checkpoint
|
||||
if (!is.null(env$bst)) {
|
||||
xgb.attributes(env$bst) <- list(
|
||||
best_iteration = best_iteration - 1, # convert to 0-based index
|
||||
best_score = best_score,
|
||||
best_msg = best_msg,
|
||||
best_ntreelimit = best_ntreelimit)
|
||||
}
|
||||
} else if (i - best_iteration >= stopping_rounds) {
|
||||
env$stop_condition <- TRUE
|
||||
env$end_iteration <- i
|
||||
if (verbose && NVL(env$rank, 0) == 0)
|
||||
cat("Stopping. Best iteration:\n", best_msg, "\n\n", sep = '')
|
||||
}
|
||||
}
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.early.stop'
|
||||
callback
|
||||
}
|
||||
|
||||
|
||||
#' Callback closure for saving a model file.
|
||||
#'
|
||||
#' @param save_period save the model to disk after every
|
||||
#' \code{save_period} iterations; 0 means save the model at the end.
|
||||
#' @param save_name the name or path for the saved model file.
|
||||
#' It can contain a \code{\link[base]{sprintf}} formatting specifier
|
||||
#' to include the integer iteration number in the file name.
|
||||
#' E.g., with \code{save_name} = 'xgboost_%04d.model',
|
||||
#' the file saved at iteration 50 would be named "xgboost_0050.model".
|
||||
#'
|
||||
#' @details
|
||||
#' This callback function allows to save an xgb-model file, either periodically after each \code{save_period}'s or at the end.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{bst},
|
||||
#' \code{iteration},
|
||||
#' \code{begin_iteration},
|
||||
#' \code{end_iteration}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}}
|
||||
#'
|
||||
#' @export
|
||||
cb.save.model <- function(save_period = 0, save_name = "xgboost.model") {
|
||||
|
||||
if (save_period < 0)
|
||||
stop("'save_period' cannot be negative")
|
||||
|
||||
callback <- function(env = parent.frame()) {
|
||||
if (is.null(env$bst))
|
||||
stop("'save_model' callback requires the 'bst' booster object in its calling frame")
|
||||
|
||||
if ((save_period > 0 && (env$iteration - env$begin_iteration) %% save_period == 0) ||
|
||||
(save_period == 0 && env$iteration == env$end_iteration))
|
||||
xgb.save(env$bst, sprintf(save_name, env$iteration))
|
||||
}
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.save.model'
|
||||
callback
|
||||
}
|
||||
|
||||
|
||||
#' Callback closure for returning cross-validation based predictions.
|
||||
#'
|
||||
#' @param save_models a flag for whether to save the folds' models.
|
||||
#'
|
||||
#' @details
|
||||
#' This callback function saves predictions for all of the test folds,
|
||||
#' and also allows to save the folds' models.
|
||||
#'
|
||||
#' It is a "finalizer" callback and it uses early stopping information whenever it is available,
|
||||
#' thus it must be run after the early stopping callback if the early stopping is used.
|
||||
#'
|
||||
#' Callback function expects the following values to be set in its calling frame:
|
||||
#' \code{bst_folds},
|
||||
#' \code{basket},
|
||||
#' \code{data},
|
||||
#' \code{end_iteration},
|
||||
#' \code{num_parallel_tree},
|
||||
#' \code{num_class}.
|
||||
#'
|
||||
#' @return
|
||||
#' Predictions are returned inside of the \code{pred} element, which is either a vector or a matrix,
|
||||
#' depending on the number of prediction outputs per data row. The order of predictions corresponds
|
||||
#' to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
||||
#' provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
||||
#' non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
||||
#' meaningful when user-profided folds have overlapping indices as in, e.g., random sampling splits.
|
||||
#' When some of the indices in the training dataset are not included into user-provided \code{folds},
|
||||
#' their prediction value would be \code{NA}.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}}
|
||||
#'
|
||||
#' @export
|
||||
cb.cv.predict <- function(save_models = FALSE) {
|
||||
|
||||
finalizer <- function(env) {
|
||||
if (is.null(env$basket) || is.null(env$bst_folds))
|
||||
stop("'cb.cv.predict' callback requires 'basket' and 'bst_folds' lists in its calling frame")
|
||||
|
||||
N <- nrow(env$data)
|
||||
pred <-
|
||||
if (env$num_class > 1) {
|
||||
matrix(NA_real_, N, env$num_class)
|
||||
} else {
|
||||
rep(NA_real_, N)
|
||||
}
|
||||
|
||||
ntreelimit <- NVL(env$basket$best_ntreelimit,
|
||||
env$end_iteration * env$num_parallel_tree)
|
||||
for (fd in env$bst_folds) {
|
||||
pr <- predict(fd$bst, fd$watchlist[[2]], ntreelimit = ntreelimit, reshape = TRUE)
|
||||
if (is.matrix(pred)) {
|
||||
pred[fd$index,] <- pr
|
||||
} else {
|
||||
pred[fd$index] <- pr
|
||||
}
|
||||
}
|
||||
env$basket$pred <- pred
|
||||
if (save_models) {
|
||||
env$basket$models <- lapply(env$bst_folds, function(fd) {
|
||||
xgb.attr(fd$bst, 'niter') <- env$end_iteration - 1
|
||||
xgb.Booster.check(xgb.handleToBooster(fd$bst), saveraw = TRUE)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
callback <- function(env = parent.frame(), finalize = FALSE) {
|
||||
if (finalize)
|
||||
return(finalizer(env))
|
||||
}
|
||||
attr(callback, 'call') <- match.call()
|
||||
attr(callback, 'name') <- 'cb.cv.predict'
|
||||
callback
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Internal utility functions for callbacks ------------------------------------
|
||||
#
|
||||
|
||||
# Format the evaluation metric string
|
||||
format.eval.string <- function(iter, eval_res, eval_err=NULL) {
|
||||
if (length(eval_res) == 0)
|
||||
stop('no evaluation results')
|
||||
enames <- names(eval_res)
|
||||
if (is.null(enames))
|
||||
stop('evaluation results must have names')
|
||||
iter <- sprintf('[%d]\t', iter)
|
||||
if (!is.null(eval_err)) {
|
||||
if (length(eval_res) != length(eval_err))
|
||||
stop('eval_res & eval_err lengths mismatch')
|
||||
res <- paste0(sprintf("%s:%f+%f", enames, eval_res, eval_err), collapse='\t')
|
||||
} else {
|
||||
res <- paste0(sprintf("%s:%f", enames, eval_res), collapse='\t')
|
||||
}
|
||||
return(paste0(iter, res))
|
||||
}
|
||||
|
||||
# Extract callback names from the list of callbacks
|
||||
callback.names <- function(cb_list) {
|
||||
unlist(lapply(cb_list, function(x) attr(x, 'name')))
|
||||
}
|
||||
|
||||
# Extract callback calls from the list of callbacks
|
||||
callback.calls <- function(cb_list) {
|
||||
unlist(lapply(cb_list, function(x) attr(x, 'call')))
|
||||
}
|
||||
|
||||
# Add a callback cb to the list and make sure that
|
||||
# cb.early.stop and cb.cv.predict are at the end of the list
|
||||
# with cb.cv.predict being the last (when present)
|
||||
add.cb <- function(cb_list, cb) {
|
||||
cb_list <- c(cb_list, cb)
|
||||
names(cb_list) <- callback.names(cb_list)
|
||||
if ('cb.early.stop' %in% names(cb_list)) {
|
||||
cb_list <- c(cb_list, cb_list['cb.early.stop'])
|
||||
# this removes only the first one
|
||||
cb_list['cb.early.stop'] <- NULL
|
||||
}
|
||||
if ('cb.cv.predict' %in% names(cb_list)) {
|
||||
cb_list <- c(cb_list, cb_list['cb.cv.predict'])
|
||||
cb_list['cb.cv.predict'] <- NULL
|
||||
}
|
||||
cb_list
|
||||
}
|
||||
|
||||
# Sort callbacks list into categories
|
||||
categorize.callbacks <- function(cb_list) {
|
||||
list(
|
||||
pre_iter = Filter(function(x) {
|
||||
pre <- attr(x, 'is_pre_iteration')
|
||||
!is.null(pre) && pre
|
||||
}, cb_list),
|
||||
post_iter = Filter(function(x) {
|
||||
pre <- attr(x, 'is_pre_iteration')
|
||||
is.null(pre) || !pre
|
||||
}, cb_list),
|
||||
finalize = Filter(function(x) {
|
||||
'finalize' %in% names(formals(x))
|
||||
}, cb_list)
|
||||
)
|
||||
}
|
||||
|
||||
# Check whether all callback functions with names given by 'query_names' are present in the 'cb_list'.
|
||||
has.callbacks <- function(cb_list, query_names) {
|
||||
if (length(cb_list) < length(query_names))
|
||||
return(FALSE)
|
||||
if (!is.list(cb_list) ||
|
||||
any(sapply(cb_list, class) != 'function')) {
|
||||
stop('`cb_list`` must be a list of callback functions')
|
||||
}
|
||||
cb_names <- callback.names(cb_list)
|
||||
if (!is.character(cb_names) ||
|
||||
length(cb_names) != length(cb_list) ||
|
||||
any(cb_names == "")) {
|
||||
stop('All callbacks in the `cb_list` must have a non-empty `name` attribute')
|
||||
}
|
||||
if (!is.character(query_names) ||
|
||||
length(query_names) == 0 ||
|
||||
any(query_names == "")) {
|
||||
stop('query_names must be a non-empty vector of non-empty character names')
|
||||
}
|
||||
return(all(query_names %in% cb_names))
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
setClass('xgb.DMatrix')
|
||||
|
||||
#' Get information of an xgb.DMatrix object
|
||||
#'
|
||||
#' Get information of an xgb.DMatrix object
|
||||
#'
|
||||
#' The information can be one of the following:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{label}: label Xgboost learn from ;
|
||||
#' \item \code{weight}: to do a weight rescale ;
|
||||
#' \item \code{base_margin}: base margin is the base prediction Xgboost will boost from ;
|
||||
#' \item \code{nrow}: number of rows of the \code{xgb.DMatrix}.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#' labels <- getinfo(dtrain, 'label')
|
||||
#' setinfo(dtrain, 'label', 1-labels)
|
||||
#' labels2 <- getinfo(dtrain, 'label')
|
||||
#' stopifnot(all(labels2 == 1-labels))
|
||||
#' @rdname getinfo
|
||||
#' @export
|
||||
#'
|
||||
getinfo <- function(object, ...){
|
||||
UseMethod("getinfo")
|
||||
}
|
||||
|
||||
|
||||
|
||||
#' @param object Object of class \code{xgb.DMatrix}
|
||||
#' @param name the name of the field to get
|
||||
#' @param ... other parameters
|
||||
#' @rdname getinfo
|
||||
#' @method getinfo xgb.DMatrix
|
||||
setMethod("getinfo", signature = "xgb.DMatrix",
|
||||
definition = function(object, name) {
|
||||
if (typeof(name) != "character") {
|
||||
stop("xgb.getinfo: name must be character")
|
||||
}
|
||||
if (class(object) != "xgb.DMatrix") {
|
||||
stop("xgb.setinfo: first argument dtrain must be xgb.DMatrix")
|
||||
}
|
||||
if (name != "label" && name != "weight" &&
|
||||
name != "base_margin" && name != "nrow") {
|
||||
stop(paste("xgb.getinfo: unknown info name", name))
|
||||
}
|
||||
if (name != "nrow"){
|
||||
ret <- .Call("XGDMatrixGetInfo_R", object, name, PACKAGE = "xgboost")
|
||||
} else {
|
||||
ret <- xgb.numrow(object)
|
||||
}
|
||||
return(ret)
|
||||
})
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
setGeneric("nrow")
|
||||
|
||||
#' @title Number of xgb.DMatrix rows
|
||||
#' @description \code{nrow} return the number of rows present in the \code{xgb.DMatrix}.
|
||||
#' @param x Object of class \code{xgb.DMatrix}
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#' stopifnot(nrow(dtrain) == nrow(train$data))
|
||||
#'
|
||||
#' @export
|
||||
setMethod("nrow",
|
||||
signature = "xgb.DMatrix",
|
||||
definition = function(x) {
|
||||
xgb.numrow(x)
|
||||
}
|
||||
)
|
||||
@@ -1,75 +0,0 @@
|
||||
setClass("xgb.Booster.handle")
|
||||
setClass("xgb.Booster",
|
||||
slots = c(handle = "xgb.Booster.handle",
|
||||
raw = "raw"))
|
||||
|
||||
#' Predict method for eXtreme Gradient Boosting model
|
||||
#'
|
||||
#' Predicted values based on xgboost model object.
|
||||
#'
|
||||
#' @param object Object of class "xgb.Boost"
|
||||
#' @param newdata takes \code{matrix}, \code{dgCMatrix}, local data file or
|
||||
#' \code{xgb.DMatrix}.
|
||||
#' @param missing Missing is only used when input is dense matrix, pick a float
|
||||
#' value that represents missing value. Sometime a data use 0 or other extreme value to represents missing values.
|
||||
#' @param outputmargin whether the prediction should be shown in the original
|
||||
#' value of sum of functions, when outputmargin=TRUE, the prediction is
|
||||
#' untransformed margin value. In logistic regression, outputmargin=T will
|
||||
#' output value before logistic transformation.
|
||||
#' @param ntreelimit limit number of trees used in prediction, this parameter is
|
||||
#' only valid for gbtree, but not for gblinear. set it to be value bigger
|
||||
#' than 0. It will use all trees by default.
|
||||
#' @param predleaf whether predict leaf index instead. If set to TRUE, the output will be a matrix object.
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' pred <- predict(bst, test$data)
|
||||
#' @export
|
||||
#'
|
||||
setMethod("predict", signature = "xgb.Booster",
|
||||
definition = function(object, newdata, missing = NULL,
|
||||
outputmargin = FALSE, ntreelimit = NULL, predleaf = FALSE) {
|
||||
if (class(object) != "xgb.Booster"){
|
||||
stop("predict: model in prediction must be of class xgb.Booster")
|
||||
} else {
|
||||
object <- xgb.Booster.check(object, saveraw = FALSE)
|
||||
}
|
||||
if (class(newdata) != "xgb.DMatrix") {
|
||||
if (is.null(missing)) {
|
||||
newdata <- xgb.DMatrix(newdata)
|
||||
} else {
|
||||
newdata <- xgb.DMatrix(newdata, missing = missing)
|
||||
}
|
||||
}
|
||||
if (is.null(ntreelimit)) {
|
||||
ntreelimit <- 0
|
||||
} else {
|
||||
if (ntreelimit < 1){
|
||||
stop("predict: ntreelimit must be equal to or greater than 1")
|
||||
}
|
||||
}
|
||||
option = 0
|
||||
if (outputmargin) {
|
||||
option <- option + 1
|
||||
}
|
||||
if (predleaf) {
|
||||
option <- option + 2
|
||||
}
|
||||
ret <- .Call("XGBoosterPredict_R", object$handle, newdata, as.integer(option),
|
||||
as.integer(ntreelimit), PACKAGE = "xgboost")
|
||||
if (predleaf){
|
||||
len <- getinfo(newdata, "nrow")
|
||||
if (length(ret) == len){
|
||||
ret <- matrix(ret,ncol = 1)
|
||||
} else {
|
||||
ret <- matrix(ret, ncol = len)
|
||||
ret <- t(ret)
|
||||
}
|
||||
}
|
||||
return(ret)
|
||||
})
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#' Predict method for eXtreme Gradient Boosting model handle
|
||||
#'
|
||||
#' Predicted values based on xgb.Booster.handle object.
|
||||
#'
|
||||
#' @param object Object of class "xgb.Boost.handle"
|
||||
#' @param ... Parameters pass to \code{predict.xgb.Booster}
|
||||
#'
|
||||
setMethod("predict", signature = "xgb.Booster.handle",
|
||||
definition = function(object, ...) {
|
||||
if (class(object) != "xgb.Booster.handle"){
|
||||
stop("predict: model in prediction must be of class xgb.Booster.handle")
|
||||
}
|
||||
|
||||
bst <- xgb.handleToBooster(object)
|
||||
|
||||
ret = predict(bst, ...)
|
||||
return(ret)
|
||||
})
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#' Set information of an xgb.DMatrix object
|
||||
#'
|
||||
#' Set information of an xgb.DMatrix object
|
||||
#'
|
||||
#' It can be one of the following:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{label}: label Xgboost learn from ;
|
||||
#' \item \code{weight}: to do a weight rescale ;
|
||||
#' \item \code{base_margin}: base margin is the base prediction Xgboost will boost from ;
|
||||
#' \item \code{group}.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#' labels <- getinfo(dtrain, 'label')
|
||||
#' setinfo(dtrain, 'label', 1-labels)
|
||||
#' labels2 <- getinfo(dtrain, 'label')
|
||||
#' stopifnot(all(labels2 == 1-labels))
|
||||
#' @rdname setinfo
|
||||
#' @export
|
||||
#'
|
||||
setinfo <- function(object, ...){
|
||||
UseMethod("setinfo")
|
||||
}
|
||||
|
||||
#' @param object Object of class "xgb.DMatrix"
|
||||
#' @param name the name of the field to get
|
||||
#' @param info the specific field of information to set
|
||||
#' @param ... other parameters
|
||||
#' @rdname setinfo
|
||||
#' @method setinfo xgb.DMatrix
|
||||
setMethod("setinfo", signature = "xgb.DMatrix",
|
||||
definition = function(object, name, info) {
|
||||
xgb.setinfo(object, name, info)
|
||||
})
|
||||
@@ -1,45 +0,0 @@
|
||||
setClass('xgb.DMatrix')
|
||||
|
||||
#' Get a new DMatrix containing the specified rows of
|
||||
#' orginal xgb.DMatrix object
|
||||
#'
|
||||
#' Get a new DMatrix containing the specified rows of
|
||||
#' orginal xgb.DMatrix object
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#' dsub <- slice(dtrain, 1:3)
|
||||
#' @rdname slice
|
||||
#' @export
|
||||
#'
|
||||
slice <- function(object, ...){
|
||||
UseMethod("slice")
|
||||
}
|
||||
|
||||
#' @param object Object of class "xgb.DMatrix"
|
||||
#' @param idxset a integer vector of indices of rows needed
|
||||
#' @param ... other parameters
|
||||
#' @rdname slice
|
||||
#' @method slice xgb.DMatrix
|
||||
setMethod("slice", signature = "xgb.DMatrix",
|
||||
definition = function(object, idxset, ...) {
|
||||
if (class(object) != "xgb.DMatrix") {
|
||||
stop("slice: first argument dtrain must be xgb.DMatrix")
|
||||
}
|
||||
ret <- .Call("XGDMatrixSliceDMatrix_R", object, idxset,
|
||||
PACKAGE = "xgboost")
|
||||
|
||||
attr_list <- attributes(object)
|
||||
nr <- xgb.numrow(object)
|
||||
len <- sapply(attr_list,length)
|
||||
ind <- which(len==nr)
|
||||
if (length(ind)>0) {
|
||||
nms <- names(attr_list)[ind]
|
||||
for (i in 1:length(ind)) {
|
||||
attr(ret,nms[i]) <- attr(object,nms[i])[idxset]
|
||||
}
|
||||
}
|
||||
return(structure(ret, class = "xgb.DMatrix"))
|
||||
})
|
||||
@@ -1,303 +1,224 @@
|
||||
#' @importClassesFrom Matrix dgCMatrix dgeMatrix
|
||||
#' @import methods
|
||||
#
|
||||
# This file is for the low level reuseable utility functions
|
||||
# that are not supposed to be visibe to a user.
|
||||
#
|
||||
|
||||
# depends on matrix
|
||||
.onLoad <- function(libname, pkgname) {
|
||||
library.dynam("xgboost", pkgname, libname)
|
||||
}
|
||||
.onUnload <- function(libpath) {
|
||||
library.dynam.unload("xgboost", libpath)
|
||||
#
|
||||
# General helper utilities ----------------------------------------------------
|
||||
#
|
||||
|
||||
# SQL-style NVL shortcut.
|
||||
NVL <- function(x, val) {
|
||||
if (is.null(x))
|
||||
return(val)
|
||||
if (is.vector(x)) {
|
||||
x[is.na(x)] <- val
|
||||
return(x)
|
||||
}
|
||||
if (typeof(x) == 'closure')
|
||||
return(x)
|
||||
stop('x of unsupported for NVL type')
|
||||
}
|
||||
|
||||
# set information into dmatrix, this mutate dmatrix
|
||||
xgb.setinfo <- function(dmat, name, info) {
|
||||
if (class(dmat) != "xgb.DMatrix") {
|
||||
stop("xgb.setinfo: first argument dtrain must be xgb.DMatrix")
|
||||
|
||||
#
|
||||
# Low-level functions for boosting --------------------------------------------
|
||||
#
|
||||
|
||||
# Merges booster params with whatever is provided in ...
|
||||
# plus runs some checks
|
||||
check.booster.params <- function(params, ...) {
|
||||
if (typeof(params) != "list")
|
||||
stop("params must be a list")
|
||||
|
||||
# in R interface, allow for '.' instead of '_' in parameter names
|
||||
names(params) <- gsub("\\.", "_", names(params))
|
||||
|
||||
# merge parameters from the params and the dots-expansion
|
||||
dot_params <- list(...)
|
||||
names(dot_params) <- gsub("\\.", "_", names(dot_params))
|
||||
if (length(intersect(names(params),
|
||||
names(dot_params))) > 0)
|
||||
stop("Same parameters in 'params' and in the call are not allowed. Please check your 'params' list.")
|
||||
params <- c(params, dot_params)
|
||||
|
||||
# providing a parameter multiple times only makes sense for 'eval_metric'
|
||||
name_freqs <- table(names(params))
|
||||
multi_names <- setdiff(names(name_freqs[name_freqs > 1]), 'eval_metric')
|
||||
if (length(multi_names) > 0) {
|
||||
warning("The following parameters were provided multiple times:\n\t",
|
||||
paste(multi_names, collapse=', '), "\n Only the last value for each of them will be used.\n")
|
||||
# While xgboost itself would choose the last value for a multi-parameter,
|
||||
# will do some clean-up here b/c multi-parameters could be used further in R code, and R would
|
||||
# pick the 1st (not the last) value when multiple elements with the same name are present in a list.
|
||||
for (n in multi_names) {
|
||||
del_idx <- which(n == names(params))
|
||||
del_idx <- del_idx[-length(del_idx)]
|
||||
params[[del_idx]] <- NULL
|
||||
}
|
||||
}
|
||||
if (name == "label") {
|
||||
if (length(info)!=xgb.numrow(dmat))
|
||||
stop("The length of labels must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", dmat, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
|
||||
# for multiclass, expect num_class to be set
|
||||
if (typeof(params[['objective']]) == "character" &&
|
||||
substr(NVL(params[['objective']], 'x'), 1, 6) == 'multi:') {
|
||||
if (as.numeric(NVL(params[['num_class']], 0)) < 2)
|
||||
stop("'num_class' > 1 parameter must be set for multiclass classification")
|
||||
}
|
||||
if (name == "weight") {
|
||||
if (length(info)!=xgb.numrow(dmat))
|
||||
stop("The length of weights must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", dmat, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
if (name == "base_margin") {
|
||||
# if (length(info)!=xgb.numrow(dmat))
|
||||
# stop("The length of base margin must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", dmat, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
if (name == "group") {
|
||||
if (sum(info)!=xgb.numrow(dmat))
|
||||
stop("The sum of groups must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", dmat, name, as.integer(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
stop(paste("xgb.setinfo: unknown info name", name))
|
||||
return(FALSE)
|
||||
|
||||
return(params)
|
||||
}
|
||||
|
||||
# construct a Booster from cachelist
|
||||
xgb.Booster <- function(params = list(), cachelist = list(), modelfile = NULL) {
|
||||
if (typeof(cachelist) != "list") {
|
||||
stop("xgb.Booster: only accepts list of DMatrix as cachelist")
|
||||
|
||||
# Performs some checks related to custom objective function.
|
||||
# WARNING: has side-effects and can modify 'params' and 'obj' in its calling frame
|
||||
check.custom.obj <- function(env = parent.frame()) {
|
||||
if (!is.null(env$params[['objective']]) && !is.null(env$obj))
|
||||
stop("Setting objectives in 'params' and 'obj' at the same time is not allowed")
|
||||
|
||||
if (!is.null(env$obj) && typeof(env$obj) != 'closure')
|
||||
stop("'obj' must be a function")
|
||||
|
||||
# handle the case when custom objective function was provided through params
|
||||
if (!is.null(env$params[['objective']]) &&
|
||||
typeof(env$params$objective) == 'closure') {
|
||||
env$obj <- env$params$objective
|
||||
p <- env$params
|
||||
p$objective <- NULL
|
||||
env$params <- p
|
||||
}
|
||||
for (dm in cachelist) {
|
||||
if (class(dm) != "xgb.DMatrix") {
|
||||
stop("xgb.Booster: only accepts list of DMatrix as cachelist")
|
||||
}
|
||||
}
|
||||
handle <- .Call("XGBoosterCreate_R", cachelist, PACKAGE = "xgboost")
|
||||
if (length(params) != 0) {
|
||||
for (i in 1:length(params)) {
|
||||
p <- params[i]
|
||||
.Call("XGBoosterSetParam_R", handle, gsub("\\.", "_", names(p)), as.character(p),
|
||||
PACKAGE = "xgboost")
|
||||
}
|
||||
}
|
||||
if (!is.null(modelfile)) {
|
||||
if (typeof(modelfile) == "character") {
|
||||
.Call("XGBoosterLoadModel_R", handle, modelfile, PACKAGE = "xgboost")
|
||||
} else if (typeof(modelfile) == "raw") {
|
||||
.Call("XGBoosterLoadModelFromRaw_R", handle, modelfile, PACKAGE = "xgboost")
|
||||
} else {
|
||||
stop("xgb.Booster: modelfile must be character or raw vector")
|
||||
}
|
||||
}
|
||||
return(structure(handle, class = "xgb.Booster.handle"))
|
||||
}
|
||||
|
||||
# convert xgb.Booster.handle to xgb.Booster
|
||||
xgb.handleToBooster <- function(handle, raw = NULL)
|
||||
{
|
||||
bst <- list(handle = handle, raw = raw)
|
||||
class(bst) <- "xgb.Booster"
|
||||
return(bst)
|
||||
# Performs some checks related to custom evaluation function.
|
||||
# WARNING: has side-effects and can modify 'params' and 'feval' in its calling frame
|
||||
check.custom.eval <- function(env = parent.frame()) {
|
||||
if (!is.null(env$params[['eval_metric']]) && !is.null(env$feval))
|
||||
stop("Setting evaluation metrics in 'params' and 'feval' at the same time is not allowed")
|
||||
|
||||
if (!is.null(env$feval) && typeof(env$feval) != 'closure')
|
||||
stop("'feval' must be a function")
|
||||
|
||||
if (!is.null(env$feval) && is.null(env$maximize))
|
||||
stop("Please set 'maximize' to indicate whether the metric needs to be maximized or not")
|
||||
|
||||
# handle a situation when custom eval function was provided through params
|
||||
if (!is.null(env$params[['eval_metric']]) &&
|
||||
typeof(env$params$eval_metric) == 'closure') {
|
||||
env$feval <- env$params$eval_metric
|
||||
p <- env$params
|
||||
p[ which(names(p) == 'eval_metric') ] <- NULL
|
||||
env$params <- p
|
||||
}
|
||||
}
|
||||
|
||||
# Check whether an xgb.Booster object is complete
|
||||
xgb.Booster.check <- function(bst, saveraw = TRUE)
|
||||
{
|
||||
isnull <- is.null(bst$handle)
|
||||
if (!isnull) {
|
||||
isnull <- .Call("XGCheckNullPtr_R", bst$handle, PACKAGE="xgboost")
|
||||
}
|
||||
if (isnull) {
|
||||
bst$handle <- xgb.Booster(modelfile = bst$raw)
|
||||
} else {
|
||||
if (is.null(bst$raw) && saveraw)
|
||||
bst$raw <- xgb.save.raw(bst$handle)
|
||||
}
|
||||
return(bst)
|
||||
}
|
||||
|
||||
## ----the following are low level iteratively function, not needed if
|
||||
## you do not want to use them ---------------------------------------
|
||||
# get dmatrix from data, label
|
||||
xgb.get.DMatrix <- function(data, label = NULL, missing = NULL) {
|
||||
inClass <- class(data)
|
||||
if (inClass == "dgCMatrix" || inClass == "matrix") {
|
||||
if (is.null(label)) {
|
||||
stop("xgboost: need label when data is a matrix")
|
||||
}
|
||||
if (is.null(missing)){
|
||||
dtrain <- xgb.DMatrix(data, label = label)
|
||||
} else {
|
||||
dtrain <- xgb.DMatrix(data, label = label, missing = missing)
|
||||
}
|
||||
} else {
|
||||
if (!is.null(label)) {
|
||||
warning("xgboost: label will be ignored.")
|
||||
}
|
||||
if (inClass == "character") {
|
||||
dtrain <- xgb.DMatrix(data)
|
||||
} else if (inClass == "xgb.DMatrix") {
|
||||
dtrain <- data
|
||||
} else {
|
||||
stop("xgboost: Invalid input of data")
|
||||
}
|
||||
}
|
||||
return (dtrain)
|
||||
}
|
||||
xgb.numrow <- function(dmat) {
|
||||
nrow <- .Call("XGDMatrixNumRow_R", dmat, PACKAGE="xgboost")
|
||||
return(nrow)
|
||||
}
|
||||
# iteratively update booster with customized statistics
|
||||
xgb.iter.boost <- function(booster, dtrain, gpair) {
|
||||
if (class(booster) != "xgb.Booster.handle") {
|
||||
stop("xgb.iter.update: first argument must be type xgb.Booster.handle")
|
||||
}
|
||||
if (class(dtrain) != "xgb.DMatrix") {
|
||||
stop("xgb.iter.update: second argument must be type xgb.DMatrix")
|
||||
}
|
||||
.Call("XGBoosterBoostOneIter_R", booster, dtrain, gpair$grad, gpair$hess,
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
|
||||
# iteratively update booster with dtrain
|
||||
# Update booster with dtrain for an iteration
|
||||
xgb.iter.update <- function(booster, dtrain, iter, obj = NULL) {
|
||||
if (class(booster) != "xgb.Booster.handle") {
|
||||
stop("xgb.iter.update: first argument must be type xgb.Booster.handle")
|
||||
stop("first argument type must be xgb.Booster.handle")
|
||||
}
|
||||
if (class(dtrain) != "xgb.DMatrix") {
|
||||
stop("xgb.iter.update: second argument must be type xgb.DMatrix")
|
||||
stop("second argument type must be xgb.DMatrix")
|
||||
}
|
||||
|
||||
if (is.null(obj)) {
|
||||
.Call("XGBoosterUpdateOneIter_R", booster, as.integer(iter), dtrain,
|
||||
.Call("XGBoosterUpdateOneIter_R", booster, as.integer(iter), dtrain,
|
||||
PACKAGE = "xgboost")
|
||||
} else {
|
||||
pred <- predict(booster, dtrain)
|
||||
gpair <- obj(pred, dtrain)
|
||||
succ <- xgb.iter.boost(booster, dtrain, gpair)
|
||||
.Call("XGBoosterBoostOneIter_R", booster, dtrain, gpair$grad, gpair$hess, PACKAGE = "xgboost")
|
||||
}
|
||||
return(TRUE)
|
||||
}
|
||||
|
||||
# iteratively evaluate one iteration
|
||||
xgb.iter.eval <- function(booster, watchlist, iter, feval = NULL, prediction = FALSE) {
|
||||
if (class(booster) != "xgb.Booster.handle") {
|
||||
stop("xgb.eval: first argument must be type xgb.Booster")
|
||||
}
|
||||
if (typeof(watchlist) != "list") {
|
||||
stop("xgb.eval: only accepts list of DMatrix as watchlist")
|
||||
}
|
||||
for (w in watchlist) {
|
||||
if (class(w) != "xgb.DMatrix") {
|
||||
stop("xgb.eval: watch list can only contain xgb.DMatrix")
|
||||
}
|
||||
}
|
||||
if (length(watchlist) != 0) {
|
||||
if (is.null(feval)) {
|
||||
evnames <- list()
|
||||
for (i in 1:length(watchlist)) {
|
||||
w <- watchlist[i]
|
||||
if (length(names(w)) == 0) {
|
||||
stop("xgb.eval: name tag must be presented for every elements in watchlist")
|
||||
}
|
||||
evnames <- append(evnames, names(w))
|
||||
}
|
||||
msg <- .Call("XGBoosterEvalOneIter_R", booster, as.integer(iter), watchlist,
|
||||
evnames, PACKAGE = "xgboost")
|
||||
} else {
|
||||
msg <- paste("[", iter, "]", sep="")
|
||||
for (j in 1:length(watchlist)) {
|
||||
w <- watchlist[j]
|
||||
if (length(names(w)) == 0) {
|
||||
stop("xgb.eval: name tag must be presented for every elements in watchlist")
|
||||
}
|
||||
preds <- predict(booster, w[[1]])
|
||||
ret <- feval(preds, w[[1]])
|
||||
msg <- paste(msg, "\t", names(w), "-", ret$metric, ":", ret$value, sep="")
|
||||
}
|
||||
}
|
||||
|
||||
# Evaluate one iteration.
|
||||
# Returns a named vector of evaluation metrics
|
||||
# with the names in a 'datasetname-metricname' format.
|
||||
xgb.iter.eval <- function(booster, watchlist, iter, feval = NULL) {
|
||||
if (class(booster) != "xgb.Booster.handle")
|
||||
stop("first argument type must be xgb.Booster.handle")
|
||||
|
||||
if (length(watchlist) == 0)
|
||||
return(NULL)
|
||||
|
||||
evnames <- names(watchlist)
|
||||
if (is.null(feval)) {
|
||||
msg <- .Call("XGBoosterEvalOneIter_R", booster, as.integer(iter), watchlist,
|
||||
as.list(evnames), PACKAGE = "xgboost")
|
||||
msg <- stri_split_regex(msg, '(\\s+|:|\\s+)')[[1]][-1]
|
||||
res <- as.numeric(msg[c(FALSE,TRUE)]) # even indices are the values
|
||||
names(res) <- msg[c(TRUE,FALSE)] # odds are the names
|
||||
} else {
|
||||
msg <- ""
|
||||
res <- sapply(seq_along(watchlist), function(j) {
|
||||
w <- watchlist[[j]]
|
||||
preds <- predict(booster, w) # predict using all trees
|
||||
eval_res <- feval(preds, w)
|
||||
out <- eval_res$value
|
||||
names(out) <- paste0(evnames[j], "-", eval_res$metric)
|
||||
out
|
||||
})
|
||||
}
|
||||
if (prediction){
|
||||
preds <- predict(booster,watchlist[[2]])
|
||||
return(list(msg,preds))
|
||||
}
|
||||
return(msg)
|
||||
return(res)
|
||||
}
|
||||
|
||||
#------------------------------------------
|
||||
# helper functions for cross validation
|
||||
|
||||
#
|
||||
xgb.cv.mknfold <- function(dall, nfold, param, stratified, folds) {
|
||||
if (nfold <= 1) {
|
||||
stop("nfold must be bigger than 1")
|
||||
# Helper functions for cross validation ---------------------------------------
|
||||
#
|
||||
|
||||
# Generates random (stratified if needed) CV folds
|
||||
generate.cv.folds <- function(nfold, nrows, stratified, label, params) {
|
||||
|
||||
# cannot do it for rank
|
||||
if (exists('objective', where=params) &&
|
||||
is.character(params$objective) &&
|
||||
strtrim(params$objective, 5) == 'rank:') {
|
||||
stop("\n\tAutomatic generation of CV-folds is not implemented for ranking!\n",
|
||||
"\tConsider providing pre-computed CV-folds through the 'folds=' parameter.\n")
|
||||
}
|
||||
if(is.null(folds)) {
|
||||
if (exists('objective', where=param) && strtrim(param[['objective']], 5) == 'rank:') {
|
||||
stop("\tAutomatic creation of CV-folds is not implemented for ranking!\n",
|
||||
"\tConsider providing pre-computed CV-folds through the folds parameter.")
|
||||
# shuffle
|
||||
rnd_idx <- sample(1:nrows)
|
||||
if (stratified &&
|
||||
length(label) == length(rnd_idx)) {
|
||||
y <- label[rnd_idx]
|
||||
# WARNING: some heuristic logic is employed to identify classification setting!
|
||||
# - For classification, need to convert y labels to factor before making the folds,
|
||||
# and then do stratification by factor levels.
|
||||
# - For regression, leave y numeric and do stratification by quantiles.
|
||||
if (exists('objective', where=params) &&
|
||||
is.character(params$objective)) {
|
||||
# If 'objective' provided in params, assume that y is a classification label
|
||||
# unless objective is reg:linear
|
||||
if (params$objective != 'reg:linear')
|
||||
y <- factor(y)
|
||||
} else {
|
||||
# If no 'objective' given in params, it means that user either wants to use
|
||||
# the default 'reg:linear' objective or has provided a custom obj function.
|
||||
# Here, assume classification setting when y has 5 or less unique values:
|
||||
if (length(unique(y)) <= 5)
|
||||
y <- factor(y)
|
||||
}
|
||||
y <- getinfo(dall, 'label')
|
||||
randidx <- sample(1 : xgb.numrow(dall))
|
||||
if (stratified & length(y) == length(randidx)) {
|
||||
y <- y[randidx]
|
||||
#
|
||||
# WARNING: some heuristic logic is employed to identify classification setting!
|
||||
#
|
||||
# For classification, need to convert y labels to factor before making the folds,
|
||||
# and then do stratification by factor levels.
|
||||
# For regression, leave y numeric and do stratification by quantiles.
|
||||
if (exists('objective', where=param)) {
|
||||
# If 'objective' provided in params, assume that y is a classification label
|
||||
# unless objective is reg:linear
|
||||
if (param[['objective']] != 'reg:linear') y <- factor(y)
|
||||
} else {
|
||||
# If no 'objective' given in params, it means that user either wants to use
|
||||
# the default 'reg:linear' objective or has provided a custom obj function.
|
||||
# Here, assume classification setting when y has 5 or less unique values:
|
||||
if (length(unique(y)) <= 5) y <- factor(y)
|
||||
}
|
||||
folds <- xgb.createFolds(y, nfold)
|
||||
} else {
|
||||
# make simple non-stratified folds
|
||||
kstep <- length(randidx) %/% nfold
|
||||
folds <- list()
|
||||
for (i in 1:(nfold-1)) {
|
||||
folds[[i]] = randidx[1:kstep]
|
||||
randidx = setdiff(randidx, folds[[i]])
|
||||
}
|
||||
folds[[nfold]] = randidx
|
||||
folds <- xgb.createFolds(y, nfold)
|
||||
} else {
|
||||
# make simple non-stratified folds
|
||||
kstep <- length(rnd_idx) %/% nfold
|
||||
folds <- list()
|
||||
for (i in 1:(nfold - 1)) {
|
||||
folds[[i]] <- rnd_idx[1:kstep]
|
||||
rnd_idx <- rnd_idx[-(1:kstep)]
|
||||
}
|
||||
folds[[nfold]] <- rnd_idx
|
||||
}
|
||||
ret <- list()
|
||||
for (k in 1:nfold) {
|
||||
dtest <- slice(dall, folds[[k]])
|
||||
didx = c()
|
||||
for (i in 1:nfold) {
|
||||
if (i != k) {
|
||||
didx <- append(didx, folds[[i]])
|
||||
}
|
||||
}
|
||||
dtrain <- slice(dall, didx)
|
||||
bst <- xgb.Booster(param, list(dtrain, dtest))
|
||||
watchlist = list(train=dtrain, test=dtest)
|
||||
ret[[k]] <- list(dtrain=dtrain, booster=bst, watchlist=watchlist, index=folds[[k]])
|
||||
}
|
||||
return (ret)
|
||||
return(folds)
|
||||
}
|
||||
|
||||
xgb.cv.aggcv <- function(res, showsd = TRUE) {
|
||||
header <- res[[1]]
|
||||
ret <- header[1]
|
||||
for (i in 2:length(header)) {
|
||||
kv <- strsplit(header[i], ":")[[1]]
|
||||
ret <- paste(ret, "\t", kv[1], ":", sep="")
|
||||
stats <- c()
|
||||
stats[1] <- as.numeric(kv[2])
|
||||
for (j in 2:length(res)) {
|
||||
tkv <- strsplit(res[[j]][i], ":")[[1]]
|
||||
stats[j] <- as.numeric(tkv[2])
|
||||
}
|
||||
ret <- paste(ret, sprintf("%f", mean(stats)), sep="")
|
||||
if (showsd) {
|
||||
ret <- paste(ret, sprintf("+%f", sd(stats)), sep="")
|
||||
}
|
||||
}
|
||||
return (ret)
|
||||
}
|
||||
|
||||
# Shamelessly copied from caret::createFolds
|
||||
# and simplified by always returning an unnamed list of test indices
|
||||
# Creates CV folds stratified by the values of y.
|
||||
# It was borrowed from caret::createFolds and simplified
|
||||
# by always returning an unnamed list of fold indices.
|
||||
xgb.createFolds <- function(y, k = 10)
|
||||
{
|
||||
if(is.numeric(y)) {
|
||||
if (is.numeric(y)) {
|
||||
## Group the numeric data based on their magnitudes
|
||||
## and sample within those groups.
|
||||
|
||||
@@ -308,37 +229,101 @@ xgb.createFolds <- function(y, k = 10)
|
||||
## At most, we will use quantiles. If the sample
|
||||
## is too small, we just do regular unstratified
|
||||
## CV
|
||||
cuts <- floor(length(y)/k)
|
||||
if(cuts < 2) cuts <- 2
|
||||
if(cuts > 5) cuts <- 5
|
||||
cuts <- floor(length(y) / k)
|
||||
if (cuts < 2) cuts <- 2
|
||||
if (cuts > 5) cuts <- 5
|
||||
y <- cut(y,
|
||||
unique(quantile(y, probs = seq(0, 1, length = cuts))),
|
||||
unique(stats::quantile(y, probs = seq(0, 1, length = cuts))),
|
||||
include.lowest = TRUE)
|
||||
}
|
||||
|
||||
if(k < length(y)) {
|
||||
if (k < length(y)) {
|
||||
## reset levels so that the possible levels and
|
||||
## the levels in the vector are the same
|
||||
y <- factor(as.character(y))
|
||||
numInClass <- table(y)
|
||||
foldVector <- vector(mode = "integer", length(y))
|
||||
|
||||
|
||||
## For each class, balance the fold allocation as far
|
||||
## as possible, then resample the remainder.
|
||||
## The final assignment of folds is also randomized.
|
||||
for(i in 1:length(numInClass)) {
|
||||
for (i in 1:length(numInClass)) {
|
||||
## create a vector of integers from 1:k as many times as possible without
|
||||
## going over the number of samples in the class. Note that if the number
|
||||
## of samples in a class is less than k, nothing is producd here.
|
||||
seqVector <- rep(1:k, numInClass[i] %/% k)
|
||||
## add enough random integers to get length(seqVector) == numInClass[i]
|
||||
if(numInClass[i] %% k > 0) seqVector <- c(seqVector, sample(1:k, numInClass[i] %% k))
|
||||
if (numInClass[i] %% k > 0) seqVector <- c(seqVector, sample(1:k, numInClass[i] %% k))
|
||||
## shuffle the integers for fold assignment and assign to this classes's data
|
||||
foldVector[which(y == dimnames(numInClass)$y[i])] <- sample(seqVector)
|
||||
}
|
||||
} else foldVector <- seq(along = y)
|
||||
} else {
|
||||
foldVector <- seq(along = y)
|
||||
}
|
||||
|
||||
out <- split(seq(along = y), foldVector)
|
||||
names(out) <- NULL
|
||||
out
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Deprectaion notice utilities ------------------------------------------------
|
||||
#
|
||||
|
||||
#' Deprecation notices.
|
||||
#'
|
||||
#' At this time, some of the parameter names were changed in order to make the code style more uniform.
|
||||
#' The deprecated parameters would be removed in the next release.
|
||||
#'
|
||||
#' To see all the current deprecated and new parameters, check the \code{xgboost:::depr_par_lut} table.
|
||||
#'
|
||||
#' A deprecation warning is shown when any of the deprecated parameters is used in a call.
|
||||
#' An additional warning is shown when there was a partial match to a deprecated parameter
|
||||
#' (as R is able to partially match parameter names).
|
||||
#'
|
||||
#' @name xgboost-deprecated
|
||||
NULL
|
||||
|
||||
# Lookup table for the deprecated parameters bookkeeping
|
||||
depr_par_lut <- matrix(c(
|
||||
'print.every.n', 'print_every_n',
|
||||
'early.stop.round', 'early_stopping_rounds',
|
||||
'training.data', 'data',
|
||||
'with.stats', 'with_stats',
|
||||
'numberOfClusters', 'n_clusters',
|
||||
'features.keep', 'features_keep',
|
||||
'plot.height','plot_height',
|
||||
'plot.width','plot_width',
|
||||
'dummy', 'DUMMY'
|
||||
), ncol=2, byrow = TRUE)
|
||||
colnames(depr_par_lut) <- c('old', 'new')
|
||||
|
||||
# Checks the dot-parameters for deprecated names
|
||||
# (including partial matching), gives a deprecation warning,
|
||||
# and sets new parameters to the old parameters' values within its parent frame.
|
||||
# WARNING: has side-effects
|
||||
check.deprecation <- function(..., env = parent.frame()) {
|
||||
pars <- list(...)
|
||||
# exact and partial matches
|
||||
all_match <- pmatch(names(pars), depr_par_lut[,1])
|
||||
# indices of matched pars' names
|
||||
idx_pars <- which(!is.na(all_match))
|
||||
if (length(idx_pars) == 0) return()
|
||||
# indices of matched LUT rows
|
||||
idx_lut <- all_match[idx_pars]
|
||||
# which of idx_lut were the exact matches?
|
||||
ex_match <- depr_par_lut[idx_lut,1] %in% names(pars)
|
||||
for (i in seq_along(idx_pars)) {
|
||||
pars_par <- names(pars)[idx_pars[i]]
|
||||
old_par <- depr_par_lut[idx_lut[i], 1]
|
||||
new_par <- depr_par_lut[idx_lut[i], 2]
|
||||
if (!ex_match[i]) {
|
||||
warning("'", pars_par, "' was partially matched to '", old_par,"'")
|
||||
}
|
||||
.Deprecated(new_par, old=old_par, package = 'xgboost')
|
||||
if (new_par != 'NULL') {
|
||||
eval(parse(text = paste(new_par, '<-', pars[[pars_par]])), envir = env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
486
R-package/R/xgb.Booster.R
Normal file
486
R-package/R/xgb.Booster.R
Normal file
@@ -0,0 +1,486 @@
|
||||
# Construct a Booster from cachelist
|
||||
# internal utility function
|
||||
xgb.Booster <- function(params = list(), cachelist = list(), modelfile = NULL) {
|
||||
if (typeof(cachelist) != "list" ||
|
||||
any(sapply(cachelist, class) != 'xgb.DMatrix')) {
|
||||
stop("xgb.Booster only accepts list of DMatrix as cachelist")
|
||||
}
|
||||
|
||||
handle <- .Call("XGBoosterCreate_R", cachelist, PACKAGE = "xgboost")
|
||||
if (!is.null(modelfile)) {
|
||||
if (typeof(modelfile) == "character") {
|
||||
.Call("XGBoosterLoadModel_R", handle, modelfile, PACKAGE = "xgboost")
|
||||
} else if (typeof(modelfile) == "raw") {
|
||||
.Call("XGBoosterLoadModelFromRaw_R", handle, modelfile, PACKAGE = "xgboost")
|
||||
} else if (class(modelfile) == "xgb.Booster") {
|
||||
modelfile <- xgb.Booster.check(modelfile, saveraw=TRUE)
|
||||
.Call("XGBoosterLoadModelFromRaw_R", handle, modelfile$raw, PACKAGE = "xgboost")
|
||||
} else {
|
||||
stop("modelfile must be either character filename, or raw booster dump, or xgb.Booster object")
|
||||
}
|
||||
}
|
||||
class(handle) <- "xgb.Booster.handle"
|
||||
if (length(params) > 0) {
|
||||
xgb.parameters(handle) <- params
|
||||
}
|
||||
return(handle)
|
||||
}
|
||||
|
||||
# Convert xgb.Booster.handle to xgb.Booster
|
||||
# internal utility function
|
||||
xgb.handleToBooster <- function(handle, raw = NULL) {
|
||||
bst <- list(handle = handle, raw = raw)
|
||||
class(bst) <- "xgb.Booster"
|
||||
return(bst)
|
||||
}
|
||||
|
||||
# Return a verified to be valid handle out of either xgb.Booster.handle or xgb.Booster
|
||||
# internal utility function
|
||||
xgb.get.handle <- function(object) {
|
||||
handle <- switch(class(object)[1],
|
||||
xgb.Booster = object$handle,
|
||||
xgb.Booster.handle = object,
|
||||
stop("argument must be of either xgb.Booster or xgb.Booster.handle class")
|
||||
)
|
||||
if (is.null(handle) || .Call("XGCheckNullPtr_R", handle, PACKAGE="xgboost")) {
|
||||
stop("invalid xgb.Booster.handle")
|
||||
}
|
||||
handle
|
||||
}
|
||||
|
||||
# Check whether an xgb.Booster object is complete
|
||||
# internal utility function
|
||||
xgb.Booster.check <- function(bst, saveraw = TRUE) {
|
||||
if (class(bst) != "xgb.Booster")
|
||||
stop("argument type must be xgb.Booster")
|
||||
|
||||
isnull <- is.null(bst$handle)
|
||||
if (!isnull) {
|
||||
isnull <- .Call("XGCheckNullPtr_R", bst$handle, PACKAGE="xgboost")
|
||||
}
|
||||
if (isnull) {
|
||||
bst$handle <- xgb.Booster(modelfile = bst$raw)
|
||||
} else {
|
||||
if (is.null(bst$raw) && saveraw)
|
||||
bst$raw <- xgb.save.raw(bst$handle)
|
||||
}
|
||||
return(bst)
|
||||
}
|
||||
|
||||
|
||||
#' Predict method for eXtreme Gradient Boosting model
|
||||
#'
|
||||
#' Predicted values based on either xgboost model or model handle object.
|
||||
#'
|
||||
#' @param object Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}
|
||||
#' @param newdata takes \code{matrix}, \code{dgCMatrix}, local data file or \code{xgb.DMatrix}.
|
||||
#' @param missing Missing is only used when input is dense matrix. Pick a float value that represents
|
||||
#' missing values in data (e.g., sometimes 0 or some other extreme value is used).
|
||||
#' @param outputmargin whether the prediction should be returned in the for of original untransformed
|
||||
#' sum of predictions from boosting iterations' results. E.g., setting \code{outputmargin=TRUE} for
|
||||
#' logistic regression would result in predictions for log-odds instead of probabilities.
|
||||
#' @param ntreelimit limit the number of model's trees or boosting iterations used in prediction (see Details).
|
||||
#' It will use all the trees by default (\code{NULL} value).
|
||||
#' @param predleaf whether predict leaf index instead.
|
||||
#' @param reshape whether to reshape the vector of predictions to a matrix form when there are several
|
||||
#' prediction outputs per case. This option has no effect when \code{predleaf = TRUE}.
|
||||
#' @param ... Parameters passed to \code{predict.xgb.Booster}
|
||||
#'
|
||||
#' @details
|
||||
#' Note that \code{ntreelimit} is not necesserily equal to the number of boosting iterations
|
||||
#' and it is not necesserily equal to the number of trees in a model.
|
||||
#' E.g., in a random forest-like model, \code{ntreelimit} would limit the number of trees.
|
||||
#' But for multiclass classification, there are multiple trees per iteration,
|
||||
#' but \code{ntreelimit} limits the number of boosting iterations.
|
||||
#'
|
||||
#' Also note that \code{ntreelimit} would currently do nothing for predictions from gblinear,
|
||||
#' since gblinear doesn't keep its boosting history.
|
||||
#'
|
||||
#' One possible practical applications of the \code{predleaf} option is to use the model
|
||||
#' as a generator of new features which capture non-linearity and interactions,
|
||||
#' e.g., as implemented in \code{\link{xgb.create.features}}.
|
||||
#'
|
||||
#' @return
|
||||
#' For regression or binary classification, it returns a vector of length \code{nrows(newdata)}.
|
||||
#' For multiclass classification, either a \code{num_class * nrows(newdata)} vector or
|
||||
#' a \code{(nrows(newdata), num_class)} dimension matrix is returned, depending on
|
||||
#' the \code{reshape} value.
|
||||
#'
|
||||
#' When \code{predleaf = TRUE}, the output is a matrix object with the
|
||||
#' number of columns corresponding to the number of trees.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{xgb.train}}.
|
||||
#'
|
||||
#' @examples
|
||||
#' ## binary classification:
|
||||
#'
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#' # use all trees by default
|
||||
#' pred <- predict(bst, test$data)
|
||||
#' # use only the 1st tree
|
||||
#' pred <- predict(bst, test$data, ntreelimit = 1)
|
||||
#'
|
||||
#'
|
||||
#' ## multiclass classification in iris dataset:
|
||||
#'
|
||||
#' lb <- as.numeric(iris$Species) - 1
|
||||
#' num_class <- 3
|
||||
#' set.seed(11)
|
||||
#' bst <- xgboost(data = as.matrix(iris[, -5]), label = lb,
|
||||
#' max_depth = 4, eta = 0.5, nthread = 2, nrounds = 10, subsample = 0.5,
|
||||
#' objective = "multi:softprob", num_class = num_class)
|
||||
#' # predict for softmax returns num_class probability numbers per case:
|
||||
#' pred <- predict(bst, as.matrix(iris[, -5]))
|
||||
#' str(pred)
|
||||
#' # reshape it to a num_class-columns matrix
|
||||
#' pred <- matrix(pred, ncol=num_class, byrow=TRUE)
|
||||
#' # convert the probabilities to softmax labels
|
||||
#' pred_labels <- max.col(pred) - 1
|
||||
#' # the following should result in the same error as seen in the last iteration
|
||||
#' sum(pred_labels != lb)/length(lb)
|
||||
#'
|
||||
#' # compare that to the predictions from softmax:
|
||||
#' set.seed(11)
|
||||
#' bst <- xgboost(data = as.matrix(iris[, -5]), label = lb,
|
||||
#' max_depth = 4, eta = 0.5, nthread = 2, nrounds = 10, subsample = 0.5,
|
||||
#' objective = "multi:softmax", num_class = num_class)
|
||||
#' pred <- predict(bst, as.matrix(iris[, -5]))
|
||||
#' str(pred)
|
||||
#' all.equal(pred, pred_labels)
|
||||
#' # prediction from using only 5 iterations should result
|
||||
#' # in the same error as seen in iteration 5:
|
||||
#' pred5 <- predict(bst, as.matrix(iris[, -5]), ntreelimit=5)
|
||||
#' sum(pred5 != lb)/length(lb)
|
||||
#'
|
||||
#'
|
||||
#' ## random forest-like model of 25 trees for binary classification:
|
||||
#'
|
||||
#' set.seed(11)
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 5,
|
||||
#' nthread = 2, nrounds = 1, objective = "binary:logistic",
|
||||
#' num_parallel_tree = 25, subsample = 0.6, colsample_bytree = 0.1)
|
||||
#' # Inspect the prediction error vs number of trees:
|
||||
#' lb <- test$label
|
||||
#' dtest <- xgb.DMatrix(test$data, label=lb)
|
||||
#' err <- sapply(1:25, function(n) {
|
||||
#' pred <- predict(bst, dtest, ntreelimit=n)
|
||||
#' sum((pred > 0.5) != lb)/length(lb)
|
||||
#' })
|
||||
#' plot(err, type='l', ylim=c(0,0.1), xlab='#trees')
|
||||
#'
|
||||
#' @rdname predict.xgb.Booster
|
||||
#' @export
|
||||
predict.xgb.Booster <- function(object, newdata, missing = NA,
|
||||
outputmargin = FALSE, ntreelimit = NULL, predleaf = FALSE, reshape = FALSE, ...) {
|
||||
|
||||
object <- xgb.Booster.check(object, saveraw = FALSE)
|
||||
if (class(newdata) != "xgb.DMatrix")
|
||||
newdata <- xgb.DMatrix(newdata, missing = missing)
|
||||
if (is.null(ntreelimit))
|
||||
ntreelimit <- NVL(object$best_ntreelimit, 0)
|
||||
if (ntreelimit < 0)
|
||||
stop("ntreelimit cannot be negative")
|
||||
|
||||
option <- 0L + 1L * as.logical(outputmargin) + 2L * as.logical(predleaf)
|
||||
|
||||
ret <- .Call("XGBoosterPredict_R", object$handle, newdata, option[1],
|
||||
as.integer(ntreelimit), PACKAGE = "xgboost")
|
||||
|
||||
if (length(ret) %% nrow(newdata) != 0)
|
||||
stop("prediction length ", length(ret)," is not multiple of nrows(newdata) ", nrow(newdata))
|
||||
npred_per_case <- length(ret) / nrow(newdata)
|
||||
|
||||
if (predleaf){
|
||||
len <- nrow(newdata)
|
||||
ret <- if (length(ret) == len) {
|
||||
matrix(ret, ncol = 1)
|
||||
} else {
|
||||
t(matrix(ret, ncol = len))
|
||||
}
|
||||
} else if (reshape && npred_per_case > 1) {
|
||||
ret <- matrix(ret, ncol = length(ret) / nrow(newdata), byrow = TRUE)
|
||||
}
|
||||
return(ret)
|
||||
}
|
||||
|
||||
#' @rdname predict.xgb.Booster
|
||||
#' @export
|
||||
predict.xgb.Booster.handle <- function(object, ...) {
|
||||
|
||||
bst <- xgb.handleToBooster(object)
|
||||
|
||||
ret <- predict(bst, ...)
|
||||
return(ret)
|
||||
}
|
||||
|
||||
|
||||
#' Accessors for serializable attributes of a model.
|
||||
#'
|
||||
#' These methods allow to manipulate the key-value attribute strings of an xgboost model.
|
||||
#'
|
||||
#' @param object Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}.
|
||||
#' @param name a non-empty character string specifying which attribute is to be accessed.
|
||||
#' @param value a value of an attribute for \code{xgb.attr<-}; for \code{xgb.attributes<-}
|
||||
#' it's a list (or an object coercible to a list) with the names of attributes to set
|
||||
#' and the elements corresponding to attribute values.
|
||||
#' Non-character values are converted to character.
|
||||
#' When attribute value is not a scalar, only the first index is used.
|
||||
#' Use \code{NULL} to remove an attribute.
|
||||
#'
|
||||
#' @details
|
||||
#' The primary purpose of xgboost model attributes is to store some meta-data about the model.
|
||||
#' Note that they are a separate concept from the object attributes in R.
|
||||
#' Specifically, they refer to key-value strings that can be attached to an xgboost model,
|
||||
#' stored together with the model's binary representation, and accessed later
|
||||
#' (from R or any other interface).
|
||||
#' In contrast, any R-attribute assigned to an R-object of \code{xgb.Booster} class
|
||||
#' would not be saved by \code{xgb.save} because an xgboost model is an external memory object
|
||||
#' and its serialization is handled extrnally.
|
||||
#' Also, setting an attribute that has the same name as one of xgboost's parameters wouldn't
|
||||
#' change the value of that parameter for a model.
|
||||
#' Use \code{\link{xgb.parameters<-}} to set or change model parameters.
|
||||
#'
|
||||
#' The attribute setters would usually work more efficiently for \code{xgb.Booster.handle}
|
||||
#' than for \code{xgb.Booster}, since only just a handle (pointer) would need to be copied.
|
||||
#' That would only matter if attributes need to be set many times.
|
||||
#' Note, however, that when feeding a handle of an \code{xgb.Booster} object to the attribute setters,
|
||||
#' the raw model cache of an \code{xgb.Booster} object would not be automatically updated,
|
||||
#' and it would be user's responsibility to call \code{xgb.save.raw} to update it.
|
||||
#'
|
||||
#' The \code{xgb.attributes<-} setter either updates the existing or adds one or several attributes,
|
||||
#' but it doesn't delete the other existing attributes.
|
||||
#'
|
||||
#' @return
|
||||
#' \code{xgb.attr} returns either a string value of an attribute
|
||||
#' or \code{NULL} if an attribute wasn't stored in a model.
|
||||
#'
|
||||
#' \code{xgb.attributes} returns a list of all attribute stored in a model
|
||||
#' or \code{NULL} if a model has no stored attributes.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#'
|
||||
#' xgb.attr(bst, "my_attribute") <- "my attribute value"
|
||||
#' print(xgb.attr(bst, "my_attribute"))
|
||||
#' xgb.attributes(bst) <- list(a = 123, b = "abc")
|
||||
#'
|
||||
#' xgb.save(bst, 'xgb.model')
|
||||
#' bst1 <- xgb.load('xgb.model')
|
||||
#' print(xgb.attr(bst1, "my_attribute"))
|
||||
#' print(xgb.attributes(bst1))
|
||||
#'
|
||||
#' # deletion:
|
||||
#' xgb.attr(bst1, "my_attribute") <- NULL
|
||||
#' print(xgb.attributes(bst1))
|
||||
#' xgb.attributes(bst1) <- list(a = NULL, b = NULL)
|
||||
#' print(xgb.attributes(bst1))
|
||||
#'
|
||||
#' @rdname xgb.attr
|
||||
#' @export
|
||||
xgb.attr <- function(object, name) {
|
||||
if (is.null(name) || nchar(as.character(name[1])) == 0) stop("invalid attribute name")
|
||||
handle <- xgb.get.handle(object)
|
||||
.Call("XGBoosterGetAttr_R", handle, as.character(name[1]), PACKAGE="xgboost")
|
||||
}
|
||||
|
||||
#' @rdname xgb.attr
|
||||
#' @export
|
||||
`xgb.attr<-` <- function(object, name, value) {
|
||||
if (is.null(name) || nchar(as.character(name[1])) == 0) stop("invalid attribute name")
|
||||
handle <- xgb.get.handle(object)
|
||||
if (!is.null(value)) {
|
||||
# Coerce the elements to be scalar strings.
|
||||
# Q: should we warn user about non-scalar elements?
|
||||
value <- as.character(value[1])
|
||||
}
|
||||
.Call("XGBoosterSetAttr_R", handle, as.character(name[1]), value, PACKAGE="xgboost")
|
||||
if (is(object, 'xgb.Booster') && !is.null(object$raw)) {
|
||||
object$raw <- xgb.save.raw(object$handle)
|
||||
}
|
||||
object
|
||||
}
|
||||
|
||||
#' @rdname xgb.attr
|
||||
#' @export
|
||||
xgb.attributes <- function(object) {
|
||||
handle <- xgb.get.handle(object)
|
||||
attr_names <- .Call("XGBoosterGetAttrNames_R", handle, PACKAGE="xgboost")
|
||||
if (is.null(attr_names)) return(NULL)
|
||||
res <- lapply(attr_names, function(x) {
|
||||
.Call("XGBoosterGetAttr_R", handle, x, PACKAGE="xgboost")
|
||||
})
|
||||
names(res) <- attr_names
|
||||
res
|
||||
}
|
||||
|
||||
#' @rdname xgb.attr
|
||||
#' @export
|
||||
`xgb.attributes<-` <- function(object, value) {
|
||||
a <- as.list(value)
|
||||
if (is.null(names(a)) || any(nchar(names(a)) == 0)) {
|
||||
stop("attribute names cannot be empty strings")
|
||||
}
|
||||
# Coerce the elements to be scalar strings.
|
||||
# Q: should we warn a user about non-scalar elements?
|
||||
a <- lapply(a, function(x) {
|
||||
if (is.null(x)) return(NULL)
|
||||
as.character(x[1])
|
||||
})
|
||||
handle <- xgb.get.handle(object)
|
||||
for (i in seq_along(a)) {
|
||||
.Call("XGBoosterSetAttr_R", handle, names(a[i]), a[[i]], PACKAGE="xgboost")
|
||||
}
|
||||
if (is(object, 'xgb.Booster') && !is.null(object$raw)) {
|
||||
object$raw <- xgb.save.raw(object$handle)
|
||||
}
|
||||
object
|
||||
}
|
||||
|
||||
#' Accessors for model parameters.
|
||||
#'
|
||||
#' Only the setter for xgboost parameters is currently implemented.
|
||||
#'
|
||||
#' @param object Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}.
|
||||
#' @param value a list (or an object coercible to a list) with the names of parameters to set
|
||||
#' and the elements corresponding to parameter values.
|
||||
#'
|
||||
#' @details
|
||||
#' Note that the setter would usually work more efficiently for \code{xgb.Booster.handle}
|
||||
#' than for \code{xgb.Booster}, since only just a handle would need to be copied.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#'
|
||||
#' xgb.parameters(bst) <- list(eta = 0.1)
|
||||
#'
|
||||
#' @rdname xgb.parameters
|
||||
#' @export
|
||||
`xgb.parameters<-` <- function(object, value) {
|
||||
if (length(value) == 0) return(object)
|
||||
p <- as.list(value)
|
||||
if (is.null(names(p)) || any(nchar(names(p)) == 0)) {
|
||||
stop("parameter names cannot be empty strings")
|
||||
}
|
||||
names(p) <- gsub("\\.", "_", names(p))
|
||||
p <- lapply(p, function(x) as.character(x)[1])
|
||||
handle <- xgb.get.handle(object)
|
||||
for (i in seq_along(p)) {
|
||||
.Call("XGBoosterSetParam_R", handle, names(p[i]), p[[i]], PACKAGE = "xgboost")
|
||||
}
|
||||
if (is(object, 'xgb.Booster') && !is.null(object$raw)) {
|
||||
object$raw <- xgb.save.raw(object$handle)
|
||||
}
|
||||
object
|
||||
}
|
||||
|
||||
# Extract # of trees in a model
|
||||
# TODO: either add a getter to C-interface, or simply set an 'ntree' attribute after each iteration
|
||||
# internal utility function
|
||||
xgb.ntree <- function(bst) {
|
||||
length(grep('^booster', xgb.dump(bst)))
|
||||
}
|
||||
|
||||
|
||||
#' Print xgb.Booster
|
||||
#'
|
||||
#' Print information about xgb.Booster.
|
||||
#'
|
||||
#' @param x an xgb.Booster object
|
||||
#' @param verbose whether to print detailed data (e.g., attribute values)
|
||||
#' @param ... not currently used
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#' attr(bst, 'myattr') <- 'memo'
|
||||
#'
|
||||
#' print(bst)
|
||||
#' print(bst, verbose=TRUE)
|
||||
#'
|
||||
#' @method print xgb.Booster
|
||||
#' @export
|
||||
print.xgb.Booster <- function(x, verbose=FALSE, ...) {
|
||||
cat('##### xgb.Booster\n')
|
||||
|
||||
if (is.null(x$handle) || .Call("XGCheckNullPtr_R", x$handle, PACKAGE="xgboost")) {
|
||||
cat("handle is invalid\n")
|
||||
return(x)
|
||||
}
|
||||
|
||||
cat('raw: ')
|
||||
if (!is.null(x$raw)) {
|
||||
cat(format(object.size(x$raw), units="auto"), '\n')
|
||||
} else {
|
||||
cat('NULL\n')
|
||||
}
|
||||
if (!is.null(x$call)) {
|
||||
cat('call:\n ')
|
||||
print(x$call)
|
||||
}
|
||||
|
||||
if (!is.null(x$params)) {
|
||||
cat('params (as set within xgb.train):\n')
|
||||
cat( ' ',
|
||||
paste(names(x$params),
|
||||
paste0('"', unlist(x$params), '"'),
|
||||
sep=' = ', collapse=', '), '\n', sep='')
|
||||
}
|
||||
# TODO: need an interface to access all the xgboosts parameters
|
||||
|
||||
attrs <- xgb.attributes(x)
|
||||
if (length(attrs) > 0) {
|
||||
cat('xgb.attributes:\n')
|
||||
if (verbose) {
|
||||
cat( paste(paste0(' ',names(attrs)),
|
||||
paste0('"', unlist(attrs), '"'),
|
||||
sep=' = ', collapse='\n'), '\n', sep='')
|
||||
} else {
|
||||
cat(' ', paste(names(attrs), collapse=', '), '\n', sep='')
|
||||
}
|
||||
}
|
||||
|
||||
if (!is.null(x$callbacks) && length(x$callbacks) > 0) {
|
||||
cat('callbacks:\n')
|
||||
lapply(callback.calls(x$callbacks), function(x) {
|
||||
cat(' ')
|
||||
print(x)
|
||||
})
|
||||
}
|
||||
|
||||
cat('niter: ', x$niter, '\n', sep='')
|
||||
# TODO: uncomment when faster xgb.ntree is implemented
|
||||
#cat('ntree: ', xgb.ntree(x), '\n', sep='')
|
||||
|
||||
for (n in setdiff(names(x), c('handle', 'raw', 'call', 'params', 'callbacks','evaluation_log','niter'))) {
|
||||
if (is.atomic(x[[n]])) {
|
||||
cat(n, ': ', x[[n]], '\n', sep='')
|
||||
} else {
|
||||
cat(n, ':\n\t', sep='')
|
||||
print(x[[n]])
|
||||
}
|
||||
}
|
||||
|
||||
if (!is.null(x$evaluation_log)) {
|
||||
cat('evaluation_log:\n')
|
||||
print(x$evaluation_log, row.names = FALSE, topn = 2)
|
||||
}
|
||||
|
||||
invisible(x)
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#' Contruct xgb.DMatrix object
|
||||
#'
|
||||
#' Contruct xgb.DMatrix object from dense matrix, sparse matrix or local file.
|
||||
#' Contruct xgb.DMatrix object from dense matrix, sparse matrix
|
||||
#' or local file (that was created previously by saving an \code{xgb.DMatrix}).
|
||||
#'
|
||||
#' @param data a \code{matrix} object, a \code{dgCMatrix} object or a character
|
||||
#' indicating the data file.
|
||||
#' @param data a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename
|
||||
#' @param info a list of information of the xgb.DMatrix object
|
||||
#' @param missing Missing is only used when input is dense matrix, pick a float
|
||||
#' value that represents missing value. Sometime a data use 0 or other extreme value to represents missing values.
|
||||
@@ -17,29 +17,351 @@
|
||||
#' xgb.DMatrix.save(dtrain, 'xgb.DMatrix.data')
|
||||
#' dtrain <- xgb.DMatrix('xgb.DMatrix.data')
|
||||
#' @export
|
||||
#'
|
||||
xgb.DMatrix <- function(data, info = list(), missing = 0, ...) {
|
||||
xgb.DMatrix <- function(data, info = list(), missing = NA, ...) {
|
||||
cnames <- NULL
|
||||
if (typeof(data) == "character") {
|
||||
handle <- .Call("XGDMatrixCreateFromFile_R", data, as.integer(FALSE),
|
||||
handle <- .Call("XGDMatrixCreateFromFile_R", data, as.integer(FALSE),
|
||||
PACKAGE = "xgboost")
|
||||
} else if (is.matrix(data)) {
|
||||
handle <- .Call("XGDMatrixCreateFromMat_R", data, missing,
|
||||
handle <- .Call("XGDMatrixCreateFromMat_R", data, missing,
|
||||
PACKAGE = "xgboost")
|
||||
cnames <- colnames(data)
|
||||
} else if (class(data) == "dgCMatrix") {
|
||||
handle <- .Call("XGDMatrixCreateFromCSC_R", data@p, data@i, data@x,
|
||||
handle <- .Call("XGDMatrixCreateFromCSC_R", data@p, data@i, data@x,
|
||||
PACKAGE = "xgboost")
|
||||
cnames <- colnames(data)
|
||||
} else {
|
||||
stop(paste("xgb.DMatrix: does not support to construct from ",
|
||||
stop(paste("xgb.DMatrix: does not support to construct from ",
|
||||
typeof(data)))
|
||||
}
|
||||
dmat <- structure(handle, class = "xgb.DMatrix")
|
||||
|
||||
dmat <- handle
|
||||
attributes(dmat) <- list(.Dimnames = list(NULL, cnames), class = "xgb.DMatrix")
|
||||
#dmat <- list(handle = handle, colnames = cnames)
|
||||
#attr(dmat, 'class') <- "xgb.DMatrix"
|
||||
|
||||
info <- append(info, list(...))
|
||||
if (length(info) == 0)
|
||||
if (length(info) == 0)
|
||||
return(dmat)
|
||||
for (i in 1:length(info)) {
|
||||
p <- info[i]
|
||||
xgb.setinfo(dmat, names(p), p[[1]])
|
||||
setinfo(dmat, names(p), p[[1]])
|
||||
}
|
||||
return(dmat)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# get dmatrix from data, label
|
||||
# internal helper method
|
||||
xgb.get.DMatrix <- function(data, label = NULL, missing = NA, weight = NULL) {
|
||||
inClass <- class(data)
|
||||
if ("dgCMatrix" %in% inClass || "matrix" %in% inClass ) {
|
||||
if (is.null(label)) {
|
||||
stop("xgboost: need label when data is a matrix")
|
||||
}
|
||||
dtrain <- xgb.DMatrix(data, label = label, missing = missing)
|
||||
if (!is.null(weight)){
|
||||
setinfo(dtrain, "weight", weight)
|
||||
}
|
||||
} else {
|
||||
if (!is.null(label)) {
|
||||
warning("xgboost: label will be ignored.")
|
||||
}
|
||||
if (inClass == "character") {
|
||||
dtrain <- xgb.DMatrix(data)
|
||||
} else if (inClass == "xgb.DMatrix") {
|
||||
dtrain <- data
|
||||
} else if (inClass == "data.frame") {
|
||||
stop("xgboost only support numerical matrix input,
|
||||
use 'data.matrix' to transform the data.")
|
||||
} else {
|
||||
stop("xgboost: Invalid input of data")
|
||||
}
|
||||
}
|
||||
return (dtrain)
|
||||
}
|
||||
|
||||
|
||||
#' Dimensions of xgb.DMatrix
|
||||
#'
|
||||
#' Returns a vector of numbers of rows and of columns in an \code{xgb.DMatrix}.
|
||||
#' @param x Object of class \code{xgb.DMatrix}
|
||||
#'
|
||||
#' @details
|
||||
#' Note: since \code{nrow} and \code{ncol} internally use \code{dim}, they can also
|
||||
#' be directly used with an \code{xgb.DMatrix} object.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#'
|
||||
#' stopifnot(nrow(dtrain) == nrow(train$data))
|
||||
#' stopifnot(ncol(dtrain) == ncol(train$data))
|
||||
#' stopifnot(all(dim(dtrain) == dim(train$data)))
|
||||
#'
|
||||
#' @export
|
||||
dim.xgb.DMatrix <- function(x) {
|
||||
c(.Call("XGDMatrixNumRow_R", x, PACKAGE="xgboost"),
|
||||
.Call("XGDMatrixNumCol_R", x, PACKAGE="xgboost"))
|
||||
}
|
||||
|
||||
|
||||
#' Handling of column names of \code{xgb.DMatrix}
|
||||
#'
|
||||
#' Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
||||
#' row names would have no effect and returnten row names would be NULL.
|
||||
#'
|
||||
#' @param x object of class \code{xgb.DMatrix}
|
||||
#' @param value a list of two elements: the first one is ignored
|
||||
#' and the second one is column names
|
||||
#'
|
||||
#' @details
|
||||
#' Generic \code{dimnames} methods are used by \code{colnames}.
|
||||
#' Since row names are irrelevant, it is recommended to use \code{colnames} directly.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#' dimnames(dtrain)
|
||||
#' colnames(dtrain)
|
||||
#' colnames(dtrain) <- make.names(1:ncol(train$data))
|
||||
#' print(dtrain, verbose=TRUE)
|
||||
#'
|
||||
#' @rdname dimnames.xgb.DMatrix
|
||||
#' @export
|
||||
dimnames.xgb.DMatrix <- function(x) {
|
||||
attr(x, '.Dimnames')
|
||||
}
|
||||
|
||||
#' @rdname dimnames.xgb.DMatrix
|
||||
#' @export
|
||||
`dimnames<-.xgb.DMatrix` <- function(x, value) {
|
||||
if (!is.list(value) || length(value) != 2L)
|
||||
stop("invalid 'dimnames' given: must be a list of two elements")
|
||||
if (!is.null(value[[1L]]))
|
||||
stop("xgb.DMatrix does not have rownames")
|
||||
if (is.null(value[[2]])) {
|
||||
attr(x, '.Dimnames') <- NULL
|
||||
return(x)
|
||||
}
|
||||
if (ncol(x) != length(value[[2]]))
|
||||
stop("can't assign ", length(value[[2]]), " colnames to a ",
|
||||
ncol(x), " column xgb.DMatrix")
|
||||
attr(x, '.Dimnames') <- value
|
||||
x
|
||||
}
|
||||
|
||||
|
||||
#' Get information of an xgb.DMatrix object
|
||||
#'
|
||||
#' Get information of an xgb.DMatrix object
|
||||
#' @param object Object of class \code{xgb.DMatrix}
|
||||
#' @param name the name of the information field to get (see details)
|
||||
#' @param ... other parameters
|
||||
#'
|
||||
#' @details
|
||||
#' The \code{name} field can be one of the following:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{label}: label Xgboost learn from ;
|
||||
#' \item \code{weight}: to do a weight rescale ;
|
||||
#' \item \code{base_margin}: base margin is the base prediction Xgboost will boost from ;
|
||||
#' \item \code{nrow}: number of rows of the \code{xgb.DMatrix}.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#'
|
||||
#' labels <- getinfo(dtrain, 'label')
|
||||
#' setinfo(dtrain, 'label', 1-labels)
|
||||
#'
|
||||
#' labels2 <- getinfo(dtrain, 'label')
|
||||
#' stopifnot(all(labels2 == 1-labels))
|
||||
#' @rdname getinfo
|
||||
#' @export
|
||||
getinfo <- function(object, ...) UseMethod("getinfo")
|
||||
|
||||
#' @rdname getinfo
|
||||
#' @export
|
||||
getinfo.xgb.DMatrix <- function(object, name, ...) {
|
||||
if (typeof(name) != "character" ||
|
||||
length(name) != 1 ||
|
||||
!name %in% c('label', 'weight', 'base_margin', 'nrow')) {
|
||||
stop("getinfo: name must one of the following\n",
|
||||
" 'label', 'weight', 'base_margin', 'nrow'")
|
||||
}
|
||||
if (name != "nrow"){
|
||||
ret <- .Call("XGDMatrixGetInfo_R", object, name, PACKAGE = "xgboost")
|
||||
} else {
|
||||
ret <- nrow(object)
|
||||
}
|
||||
if (length(ret) == 0) return(NULL)
|
||||
return(ret)
|
||||
}
|
||||
|
||||
|
||||
#' Set information of an xgb.DMatrix object
|
||||
#'
|
||||
#' Set information of an xgb.DMatrix object
|
||||
#'
|
||||
#' @param object Object of class "xgb.DMatrix"
|
||||
#' @param name the name of the field to get
|
||||
#' @param info the specific field of information to set
|
||||
#' @param ... other parameters
|
||||
#'
|
||||
#' @details
|
||||
#' The \code{name} field can be one of the following:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{label}: label Xgboost learn from ;
|
||||
#' \item \code{weight}: to do a weight rescale ;
|
||||
#' \item \code{base_margin}: base margin is the base prediction Xgboost will boost from ;
|
||||
#' \item \code{group}.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#'
|
||||
#' labels <- getinfo(dtrain, 'label')
|
||||
#' setinfo(dtrain, 'label', 1-labels)
|
||||
#' labels2 <- getinfo(dtrain, 'label')
|
||||
#' stopifnot(all.equal(labels2, 1-labels))
|
||||
#' @rdname setinfo
|
||||
#' @export
|
||||
setinfo <- function(object, ...) UseMethod("setinfo")
|
||||
|
||||
#' @rdname setinfo
|
||||
#' @export
|
||||
setinfo.xgb.DMatrix <- function(object, name, info, ...) {
|
||||
if (name == "label") {
|
||||
if (length(info) != nrow(object))
|
||||
stop("The length of labels must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", object, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
if (name == "weight") {
|
||||
if (length(info) != nrow(object))
|
||||
stop("The length of weights must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", object, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
if (name == "base_margin") {
|
||||
# if (length(info)!=nrow(object))
|
||||
# stop("The length of base margin must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", object, name, as.numeric(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
if (name == "group") {
|
||||
if (sum(info) != nrow(object))
|
||||
stop("The sum of groups must equal to the number of rows in the input data")
|
||||
.Call("XGDMatrixSetInfo_R", object, name, as.integer(info),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
stop(paste("setinfo: unknown info name", name))
|
||||
return(FALSE)
|
||||
}
|
||||
|
||||
|
||||
#' Get a new DMatrix containing the specified rows of
|
||||
#' orginal xgb.DMatrix object
|
||||
#'
|
||||
#' Get a new DMatrix containing the specified rows of
|
||||
#' orginal xgb.DMatrix object
|
||||
#'
|
||||
#' @param object Object of class "xgb.DMatrix"
|
||||
#' @param idxset a integer vector of indices of rows needed
|
||||
#' @param colset currently not used (columns subsetting is not available)
|
||||
#' @param ... other parameters (currently not used)
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#'
|
||||
#' dsub <- slice(dtrain, 1:42)
|
||||
#' labels1 <- getinfo(dsub, 'label')
|
||||
#' dsub <- dtrain[1:42, ]
|
||||
#' labels2 <- getinfo(dsub, 'label')
|
||||
#' all.equal(labels1, labels2)
|
||||
#'
|
||||
#' @rdname slice.xgb.DMatrix
|
||||
#' @export
|
||||
slice <- function(object, ...) UseMethod("slice")
|
||||
|
||||
#' @rdname slice.xgb.DMatrix
|
||||
#' @export
|
||||
slice.xgb.DMatrix <- function(object, idxset, ...) {
|
||||
if (class(object) != "xgb.DMatrix") {
|
||||
stop("slice: first argument dtrain must be xgb.DMatrix")
|
||||
}
|
||||
ret <- .Call("XGDMatrixSliceDMatrix_R", object, idxset, PACKAGE = "xgboost")
|
||||
|
||||
attr_list <- attributes(object)
|
||||
nr <- nrow(object)
|
||||
len <- sapply(attr_list, length)
|
||||
ind <- which(len == nr)
|
||||
if (length(ind) > 0) {
|
||||
nms <- names(attr_list)[ind]
|
||||
for (i in 1:length(ind)) {
|
||||
attr(ret, nms[i]) <- attr(object, nms[i])[idxset]
|
||||
}
|
||||
}
|
||||
return(structure(ret, class = "xgb.DMatrix"))
|
||||
}
|
||||
|
||||
#' @rdname slice.xgb.DMatrix
|
||||
#' @export
|
||||
`[.xgb.DMatrix` <- function(object, idxset, colset=NULL) {
|
||||
slice(object, idxset)
|
||||
}
|
||||
|
||||
|
||||
#' Print xgb.DMatrix
|
||||
#'
|
||||
#' Print information about xgb.DMatrix.
|
||||
#' Currently it displays dimensions and presence of info-fields and colnames.
|
||||
#'
|
||||
#' @param x an xgb.DMatrix object
|
||||
#' @param verbose whether to print colnames (when present)
|
||||
#' @param ... not currently used
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
#'
|
||||
#' dtrain
|
||||
#' print(dtrain, verbose=TRUE)
|
||||
#'
|
||||
#' @method print xgb.DMatrix
|
||||
#' @export
|
||||
print.xgb.DMatrix <- function(x, verbose=FALSE, ...) {
|
||||
cat('xgb.DMatrix dim:', nrow(x), 'x', ncol(x), ' info: ')
|
||||
infos <- c()
|
||||
if(length(getinfo(x, 'label')) > 0) infos <- 'label'
|
||||
if(length(getinfo(x, 'weight')) > 0) infos <- c(infos, 'weight')
|
||||
if(length(getinfo(x, 'base_margin')) > 0) infos <- c(infos, 'base_margin')
|
||||
if (length(infos) == 0) infos <- 'NA'
|
||||
cat(infos)
|
||||
cnames <- colnames(x)
|
||||
cat(' colnames:')
|
||||
if (verbose & !is.null(cnames)) {
|
||||
cat("\n'")
|
||||
cat(cnames, sep="','")
|
||||
cat("'")
|
||||
} else {
|
||||
if (is.null(cnames)) cat(' no')
|
||||
else cat(' yes')
|
||||
}
|
||||
cat("\n")
|
||||
invisible(x)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#'
|
||||
#' Save xgb.DMatrix object to binary file
|
||||
#'
|
||||
#' @param DMatrix the DMatrix object
|
||||
#' @param fname the name of the binary file.
|
||||
#' @param dmatrix the \code{xgb.DMatrix} object
|
||||
#' @param fname the name of the file to write.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
@@ -12,16 +12,12 @@
|
||||
#' xgb.DMatrix.save(dtrain, 'xgb.DMatrix.data')
|
||||
#' dtrain <- xgb.DMatrix('xgb.DMatrix.data')
|
||||
#' @export
|
||||
#'
|
||||
xgb.DMatrix.save <- function(DMatrix, fname) {
|
||||
if (typeof(fname) != "character") {
|
||||
stop("xgb.save: fname must be character")
|
||||
}
|
||||
if (class(DMatrix) == "xgb.DMatrix") {
|
||||
.Call("XGDMatrixSaveBinary_R", DMatrix, fname, as.integer(FALSE),
|
||||
PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
stop("xgb.DMatrix.save: the input must be xgb.DMatrix")
|
||||
return(FALSE)
|
||||
}
|
||||
xgb.DMatrix.save <- function(dmatrix, fname) {
|
||||
if (typeof(fname) != "character")
|
||||
stop("fname must be character")
|
||||
if (class(dmatrix) != "xgb.DMatrix")
|
||||
stop("the input data must be xgb.DMatrix")
|
||||
|
||||
.Call("XGDMatrixSaveBinary_R", dmatrix, fname, 0L, PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
|
||||
84
R-package/R/xgb.create.features.R
Normal file
84
R-package/R/xgb.create.features.R
Normal file
@@ -0,0 +1,84 @@
|
||||
#' Create new features from a previously learned model
|
||||
#'
|
||||
#' May improve the learning by adding new features to the training data based on the decision trees from a previously learned model.
|
||||
#'
|
||||
#' @param model decision tree boosting model learned on the original data
|
||||
#' @param data original data (usually provided as a \code{dgCMatrix} matrix)
|
||||
#' @param ... currently not used
|
||||
#'
|
||||
#' @return \code{dgCMatrix} matrix including both the original data and the new features.
|
||||
#'
|
||||
#' @details
|
||||
#' This is the function inspired from the paragraph 3.1 of the paper:
|
||||
#'
|
||||
#' \strong{Practical Lessons from Predicting Clicks on Ads at Facebook}
|
||||
#'
|
||||
#' \emph{(Xinran He, Junfeng Pan, Ou Jin, Tianbing Xu, Bo Liu, Tao Xu, Yan, xin Shi, Antoine Atallah, Ralf Herbrich, Stuart Bowers,
|
||||
#' Joaquin Quinonero Candela)}
|
||||
#'
|
||||
#' International Workshop on Data Mining for Online Advertising (ADKDD) - August 24, 2014
|
||||
#'
|
||||
#' \url{https://research.facebook.com/publications/758569837499391/practical-lessons-from-predicting-clicks-on-ads-at-facebook/}.
|
||||
#'
|
||||
#' Extract explaining the method:
|
||||
#'
|
||||
#' "We found that boosted decision trees are a powerful and very
|
||||
#' convenient way to implement non-linear and tuple transformations
|
||||
#' of the kind we just described. We treat each individual
|
||||
#' tree as a categorical feature that takes as value the
|
||||
#' index of the leaf an instance ends up falling in. We use
|
||||
#' 1-of-K coding of this type of features.
|
||||
#'
|
||||
#' For example, consider the boosted tree model in Figure 1 with 2 subtrees,
|
||||
#' where the first subtree has 3 leafs and the second 2 leafs. If an
|
||||
#' instance ends up in leaf 2 in the first subtree and leaf 1 in
|
||||
#' second subtree, the overall input to the linear classifier will
|
||||
#' be the binary vector \code{[0, 1, 0, 1, 0]}, where the first 3 entries
|
||||
#' correspond to the leaves of the first subtree and last 2 to
|
||||
#' those of the second subtree.
|
||||
#'
|
||||
#' [...]
|
||||
#'
|
||||
#' We can understand boosted decision tree
|
||||
#' based transformation as a supervised feature encoding that
|
||||
#' converts a real-valued vector into a compact binary-valued
|
||||
#' vector. A traversal from root node to a leaf node represents
|
||||
#' a rule on certain features."
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' dtrain <- xgb.DMatrix(data = agaricus.train$data, label = agaricus.train$label)
|
||||
#' dtest <- xgb.DMatrix(data = agaricus.test$data, label = agaricus.test$label)
|
||||
#'
|
||||
#' param <- list(max_depth=2, eta=1, silent=1, objective='binary:logistic')
|
||||
#' nround = 4
|
||||
#'
|
||||
#' bst = xgb.train(params = param, data = dtrain, nrounds = nround, nthread = 2)
|
||||
#'
|
||||
#' # Model accuracy without new features
|
||||
#' accuracy.before <- sum((predict(bst, agaricus.test$data) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
#'
|
||||
#' # Convert previous features to one hot encoding
|
||||
#' new.features.train <- xgb.create.features(model = bst, agaricus.train$data)
|
||||
#' new.features.test <- xgb.create.features(model = bst, agaricus.test$data)
|
||||
#'
|
||||
#' # learning with new features
|
||||
#' new.dtrain <- xgb.DMatrix(data = new.features.train, label = agaricus.train$label)
|
||||
#' new.dtest <- xgb.DMatrix(data = new.features.test, label = agaricus.test$label)
|
||||
#' watchlist <- list(train = new.dtrain)
|
||||
#' bst <- xgb.train(params = param, data = new.dtrain, nrounds = nround, nthread = 2)
|
||||
#'
|
||||
#' # Model accuracy with new features
|
||||
#' accuracy.after <- sum((predict(bst, new.dtest) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
#'
|
||||
#' # Here the accuracy was already good and is now perfect.
|
||||
#' cat(paste("The accuracy was", accuracy.before, "before adding leaf features and it is now", accuracy.after, "!\n"))
|
||||
#'
|
||||
#' @export
|
||||
xgb.create.features <- function(model, data, ...){
|
||||
check.deprecation(...)
|
||||
pred_with_leaf <- predict(model, data, predleaf = TRUE)
|
||||
cols <- lapply(as.data.frame(pred_with_leaf), factor)
|
||||
cBind(data, sparse.model.matrix( ~ . -1, cols))
|
||||
}
|
||||
@@ -2,17 +2,6 @@
|
||||
#'
|
||||
#' The cross valudation function of xgboost
|
||||
#'
|
||||
#' @importFrom data.table data.table
|
||||
#' @importFrom data.table as.data.table
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom data.table rbindlist
|
||||
#' @importFrom stringr str_extract_all
|
||||
#' @importFrom stringr str_extract
|
||||
#' @importFrom stringr str_split
|
||||
#' @importFrom stringr str_replace
|
||||
#' @importFrom stringr str_match
|
||||
#'
|
||||
#' @param params the list of parameters. Commonly used ones are:
|
||||
#' \itemize{
|
||||
#' \item \code{objective} objective function, common ones are
|
||||
@@ -21,21 +10,23 @@
|
||||
#' \item \code{binary:logistic} logistic regression for classification
|
||||
#' }
|
||||
#' \item \code{eta} step size of each boosting step
|
||||
#' \item \code{max.depth} maximum depth of the tree
|
||||
#' \item \code{max_depth} maximum depth of the tree
|
||||
#' \item \code{nthread} number of thread used in training, if not set, all threads are used
|
||||
#' }
|
||||
#'
|
||||
#' See \link{xgb.train} for further details.
|
||||
#' See \code{\link{xgb.train}} for further details.
|
||||
#' See also demo/ for walkthrough example in R.
|
||||
#' @param data takes an \code{xgb.DMatrix} or \code{Matrix} as the input.
|
||||
#' @param nrounds the max number of iterations
|
||||
#' @param nfold the original dataset is randomly partitioned into \code{nfold} equal size subsamples.
|
||||
#' @param label option field, when data is \code{Matrix}
|
||||
#' @param missing Missing is only used when input is dense matrix, pick a float
|
||||
#' value that represents missing value. Sometime a data use 0 or other extreme value to represents missing values.
|
||||
#' @param prediction A logical value indicating whether to return the prediction vector.
|
||||
#' @param showsd \code{boolean}, whether show standard deviation of cross validation
|
||||
#' @param metrics, list of evaluation metrics to be used in corss validation,
|
||||
#' @param label vector of response values. Should be provided only when data is \code{DMatrix}.
|
||||
#' @param missing is only used when input is a dense matrix. By default is set to NA, which means
|
||||
#' that NA values should be considered as 'missing' by the algorithm.
|
||||
#' Sometimes, 0 or other extreme value might be used to represent missing values.
|
||||
#' @param prediction A logical value indicating whether to return the test fold predictions
|
||||
#' from each CV model. This parameter engages the \code{\link{cb.cv.predict}} callback.
|
||||
#' @param showsd \code{boolean}, whether to show standard deviation of cross validation
|
||||
#' @param metrics, list of evaluation metrics to be used in cross validation,
|
||||
#' when it is not specified, the evaluation metric is chosen according to objective function.
|
||||
#' Possible options are:
|
||||
#' \itemize{
|
||||
@@ -46,32 +37,33 @@
|
||||
#' \item \code{merror} Exact matching error, used to evaluate multi-class classification
|
||||
#' }
|
||||
#' @param obj customized objective function. Returns gradient and second order
|
||||
#' gradient with given prediction and dtrain.
|
||||
#' gradient with given prediction and dtrain.
|
||||
#' @param feval custimized evaluation function. Returns
|
||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||
#' prediction and dtrain.
|
||||
#' @param stratified \code{boolean} whether sampling of folds should be stratified by the values of labels in \code{data}
|
||||
#' @param folds \code{list} provides a possibility of using a list of pre-defined CV folds (each element must be a vector of fold's indices).
|
||||
#' If folds are supplied, the nfold and stratified parameters would be ignored.
|
||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||
#' prediction and dtrain.
|
||||
#' @param stratified a \code{boolean} indicating whether sampling of folds should be stratified
|
||||
#' by the values of outcome labels.
|
||||
#' @param folds \code{list} provides a possibility to use a list of pre-defined CV folds
|
||||
#' (each element must be a vector of test fold's indices). When folds are supplied,
|
||||
#' the \code{nfold} and \code{stratified} parameters are ignored.
|
||||
#' @param verbose \code{boolean}, print the statistics during the process
|
||||
#' @param early_stop_round If \code{NULL}, the early stopping function is not triggered.
|
||||
#' If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
#' keeps getting worse consecutively for \code{k} rounds.
|
||||
#' @param early.stop.round An alternative of \code{early_stop_round}.
|
||||
#' @param maximize If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
#' \code{maximize=TRUE} means the larger the evaluation score the better.
|
||||
#'
|
||||
#' @param print_every_n Print each n-th iteration evaluation messages when \code{verbose>0}.
|
||||
#' Default is 1 which means all messages are printed. This parameter is passed to the
|
||||
#' \code{\link{cb.print.evaluation}} callback.
|
||||
#' @param early_stopping_rounds If \code{NULL}, the early stopping function is not triggered.
|
||||
#' If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
#' doesn't improve for \code{k} rounds.
|
||||
#' Setting this parameter engages the \code{\link{cb.early.stop}} callback.
|
||||
#' @param maximize If \code{feval} and \code{early_stopping_rounds} are set,
|
||||
#' then this parameter must be set as well.
|
||||
#' When it is \code{TRUE}, it means the larger the evaluation score the better.
|
||||
#' This parameter is passed to the \code{\link{cb.early.stop}} callback.
|
||||
#' @param callbacks a list of callback functions to perform various task during boosting.
|
||||
#' See \code{\link{callbacks}}. Some of the callbacks are automatically created depending on the
|
||||
#' parameters' values. User can provide either existing or their own callback methods in order
|
||||
#' to customize the training process.
|
||||
#' @param ... other parameters to pass to \code{params}.
|
||||
#'
|
||||
#' @return
|
||||
#' If \code{prediction = TRUE}, a list with the following elements is returned:
|
||||
#' \itemize{
|
||||
#' \item \code{dt} a \code{data.table} with each mean and standard deviation stat for training set and test set
|
||||
#' \item \code{pred} an array or matrix (for multiclass classification) with predictions for each CV-fold for the model having been trained on the data in all other folds.
|
||||
#' }
|
||||
#'
|
||||
#' If \code{prediction = FALSE}, just a \code{data.table} with each mean and standard deviation stat for training set and test set is returned.
|
||||
#'
|
||||
#' @details
|
||||
#' The original sample is randomly partitioned into \code{nfold} equal size subsamples.
|
||||
#'
|
||||
@@ -83,150 +75,228 @@
|
||||
#'
|
||||
#' Adapted from \url{http://en.wikipedia.org/wiki/Cross-validation_\%28statistics\%29#k-fold_cross-validation}
|
||||
#'
|
||||
#' @return
|
||||
#' An object of class \code{xgb.cv.synchronous} with the following elements:
|
||||
#' \itemize{
|
||||
#' \item \code{call} a function call.
|
||||
#' \item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
||||
#' explicitely passed.
|
||||
#' \item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
||||
#' first column corresponding to iteration number and the rest corresponding to the
|
||||
#' CV-based evaluation means and standard deviations for the training and test CV-sets.
|
||||
#' It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||
#' \item \code{niter} number of boosting iterations.
|
||||
#' \item \code{folds} the list of CV folds' indices - either those passed through the \code{folds}
|
||||
#' parameter or randomly generated.
|
||||
#' \item \code{best_iteration} iteration number with the best evaluation metric value
|
||||
#' (only available with early stopping).
|
||||
#' \item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||
#' which could further be used in \code{predict} method
|
||||
#' (only available with early stopping).
|
||||
#' \item \code{pred} CV prediction values available when \code{prediction} is set.
|
||||
#' It is either vector or matrix (see \code{\link{cb.cv.predict}}).
|
||||
#' \item \code{models} a liost of the CV folds' models. It is only available with the explicit
|
||||
#' setting of the \code{cb.cv.predict(save_models = TRUE)} callback.
|
||||
#' }
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
#' history <- xgb.cv(data = dtrain, nround=3, nthread = 2, nfold = 5, metrics=list("rmse","auc"),
|
||||
#' max.depth =3, eta = 1, objective = "binary:logistic")
|
||||
#' print(history)
|
||||
#' cv <- xgb.cv(data = dtrain, nrounds = 3, nthread = 2, nfold = 5, metrics = list("rmse","auc"),
|
||||
#' max_depth = 3, eta = 1, objective = "binary:logistic")
|
||||
#' print(cv)
|
||||
#' print(cv, verbose=TRUE)
|
||||
#'
|
||||
#' @export
|
||||
#'
|
||||
xgb.cv <- function(params=list(), data, nrounds, nfold, label = NULL, missing = NULL,
|
||||
prediction = FALSE, showsd = TRUE, metrics=list(),
|
||||
obj = NULL, feval = NULL, stratified = TRUE, folds = NULL, verbose = T,
|
||||
early_stop_round = NULL, early.stop.round = NULL, maximize = NULL, ...) {
|
||||
if (typeof(params) != "list") {
|
||||
stop("xgb.cv: first argument params must be list")
|
||||
}
|
||||
xgb.cv <- function(params=list(), data, nrounds, nfold, label = NULL, missing = NA,
|
||||
prediction = FALSE, showsd = TRUE, metrics=list(),
|
||||
obj = NULL, feval = NULL, stratified = TRUE, folds = NULL,
|
||||
verbose = TRUE, print_every_n=1L,
|
||||
early_stopping_rounds = NULL, maximize = NULL, callbacks = list(), ...) {
|
||||
|
||||
check.deprecation(...)
|
||||
|
||||
params <- check.booster.params(params, ...)
|
||||
# TODO: should we deprecate the redundant 'metrics' parameter?
|
||||
for (m in metrics)
|
||||
params <- c(params, list("eval_metric" = m))
|
||||
|
||||
check.custom.obj()
|
||||
check.custom.eval()
|
||||
|
||||
#if (is.null(params[['eval_metric']]) && is.null(feval))
|
||||
# stop("Either 'eval_metric' or 'feval' must be provided for CV")
|
||||
|
||||
# Labels
|
||||
if (class(data) == 'xgb.DMatrix')
|
||||
labels <- getinfo(data, 'label')
|
||||
if (is.null(labels))
|
||||
stop("Labels must be provided for CV either through xgb.DMatrix, or through 'label=' when 'data' is matrix")
|
||||
|
||||
# CV folds
|
||||
if(!is.null(folds)) {
|
||||
if(class(folds)!="list" | length(folds) < 2) {
|
||||
stop("folds must be a list with 2 or more elements that are vectors of indices for each CV-fold")
|
||||
}
|
||||
if(class(folds) != "list" || length(folds) < 2)
|
||||
stop("'folds' must be a list with 2 or more elements that are vectors of indices for each CV-fold")
|
||||
nfold <- length(folds)
|
||||
}
|
||||
if (nfold <= 1) {
|
||||
stop("nfold must be bigger than 1")
|
||||
}
|
||||
if (is.null(missing)) {
|
||||
dtrain <- xgb.get.DMatrix(data, label)
|
||||
} else {
|
||||
dtrain <- xgb.get.DMatrix(data, label, missing)
|
||||
}
|
||||
params <- append(params, list(...))
|
||||
params <- append(params, list(silent=1))
|
||||
for (mc in metrics) {
|
||||
params <- append(params, list("eval_metric"=mc))
|
||||
if (nfold <= 1)
|
||||
stop("'nfold' must be > 1")
|
||||
folds <- generate.cv.folds(nfold, nrow(data), stratified, label, params)
|
||||
}
|
||||
|
||||
# Early Stopping
|
||||
if (is.null(early_stop_round) && !is.null(early.stop.round))
|
||||
early_stop_round = early.stop.round
|
||||
if (!is.null(early_stop_round)){
|
||||
if (!is.null(feval) && is.null(maximize))
|
||||
stop('Please set maximize to note whether the model is maximizing the evaluation or not.')
|
||||
if (is.null(maximize) && is.null(params$eval_metric))
|
||||
stop('Please set maximize to note whether the model is maximizing the evaluation or not.')
|
||||
if (is.null(maximize))
|
||||
{
|
||||
if (params$eval_metric %in% c('rmse','logloss','error','merror','mlogloss')) {
|
||||
maximize = FALSE
|
||||
} else {
|
||||
maximize = TRUE
|
||||
}
|
||||
}
|
||||
# Potential TODO: sequential CV
|
||||
#if (strategy == 'sequential')
|
||||
# stop('Sequential CV strategy is not yet implemented')
|
||||
|
||||
# verbosity & evaluation printing callback:
|
||||
params <- c(params, list(silent = 1))
|
||||
print_every_n <- max( as.integer(print_every_n), 1L)
|
||||
if (!has.callbacks(callbacks, 'cb.print.evaluation') && verbose) {
|
||||
callbacks <- add.cb(callbacks, cb.print.evaluation(print_every_n))
|
||||
}
|
||||
# evaluation log callback: always is on in CV
|
||||
evaluation_log <- list()
|
||||
if (!has.callbacks(callbacks, 'cb.evaluation.log')) {
|
||||
callbacks <- add.cb(callbacks, cb.evaluation.log())
|
||||
}
|
||||
# Early stopping callback
|
||||
stop_condition <- FALSE
|
||||
if (!is.null(early_stopping_rounds) &&
|
||||
!has.callbacks(callbacks, 'cb.early.stop')) {
|
||||
callbacks <- add.cb(callbacks, cb.early.stop(early_stopping_rounds,
|
||||
maximize=maximize, verbose=verbose))
|
||||
}
|
||||
# CV-predictions callback
|
||||
if (prediction &&
|
||||
!has.callbacks(callbacks, 'cb.cv.predict')) {
|
||||
callbacks <- add.cb(callbacks, cb.cv.predict(save_models=FALSE))
|
||||
}
|
||||
# Sort the callbacks into categories
|
||||
cb <- categorize.callbacks(callbacks)
|
||||
|
||||
|
||||
# create the booster-folds
|
||||
dall <- xgb.get.DMatrix(data, label, missing)
|
||||
bst_folds <- lapply(1:length(folds), function(k) {
|
||||
dtest <- slice(dall, folds[[k]])
|
||||
dtrain <- slice(dall, unlist(folds[-k]))
|
||||
bst <- xgb.Booster(params, list(dtrain, dtest))
|
||||
list(dtrain=dtrain, bst=bst, watchlist=list(train=dtrain, test=dtest), index=folds[[k]])
|
||||
})
|
||||
# a "basket" to collect some results from callbacks
|
||||
basket <- list()
|
||||
|
||||
# extract parameters that can affect the relationship b/w #trees and #iterations
|
||||
num_class <- max(as.numeric(NVL(params[['num_class']], 1)), 1)
|
||||
num_parallel_tree <- max(as.numeric(NVL(params[['num_parallel_tree']], 1)), 1)
|
||||
|
||||
# those are fixed for CV (no training continuation)
|
||||
begin_iteration <- 1
|
||||
end_iteration <- nrounds
|
||||
|
||||
# synchronous CV boosting: run CV folds' models within each iteration
|
||||
for (iteration in begin_iteration:end_iteration) {
|
||||
|
||||
if (maximize) {
|
||||
bestScore = 0
|
||||
} else {
|
||||
bestScore = Inf
|
||||
}
|
||||
bestInd = 0
|
||||
earlyStopflag = FALSE
|
||||
for (f in cb$pre_iter) f()
|
||||
|
||||
if (length(metrics)>1)
|
||||
warning('Only the first metric is used for early stopping process.')
|
||||
}
|
||||
|
||||
xgb_folds <- xgb.cv.mknfold(dtrain, nfold, params, stratified, folds)
|
||||
obj_type = params[['objective']]
|
||||
mat_pred = FALSE
|
||||
if (!is.null(obj_type) && obj_type=='multi:softprob')
|
||||
{
|
||||
num_class = params[['num_class']]
|
||||
if (is.null(num_class))
|
||||
stop('must set num_class to use softmax')
|
||||
predictValues <- matrix(0,xgb.numrow(dtrain),num_class)
|
||||
mat_pred = TRUE
|
||||
}
|
||||
else
|
||||
predictValues <- rep(0,xgb.numrow(dtrain))
|
||||
history <- c()
|
||||
for (i in 1:nrounds) {
|
||||
msg <- list()
|
||||
for (k in 1:nfold) {
|
||||
fd <- xgb_folds[[k]]
|
||||
succ <- xgb.iter.update(fd$booster, fd$dtrain, i - 1, obj)
|
||||
if (i<nrounds) {
|
||||
msg[[k]] <- xgb.iter.eval(fd$booster, fd$watchlist, i - 1, feval) %>% str_split("\t") %>% .[[1]]
|
||||
} else {
|
||||
if (!prediction) {
|
||||
msg[[k]] <- xgb.iter.eval(fd$booster, fd$watchlist, i - 1, feval) %>% str_split("\t") %>% .[[1]]
|
||||
} else {
|
||||
res <- xgb.iter.eval(fd$booster, fd$watchlist, i - 1, feval, prediction)
|
||||
if (mat_pred) {
|
||||
pred_mat = matrix(res[[2]],num_class,length(fd$index))
|
||||
predictValues[fd$index,] <- t(pred_mat)
|
||||
} else {
|
||||
predictValues[fd$index] <- res[[2]]
|
||||
}
|
||||
msg[[k]] <- res[[1]] %>% str_split("\t") %>% .[[1]]
|
||||
}
|
||||
}
|
||||
}
|
||||
ret <- xgb.cv.aggcv(msg, showsd)
|
||||
history <- c(history, ret)
|
||||
if(verbose) paste(ret, "\n", sep="") %>% cat
|
||||
msg <- lapply(bst_folds, function(fd) {
|
||||
xgb.iter.update(fd$bst, fd$dtrain, iteration - 1, obj)
|
||||
xgb.iter.eval(fd$bst, fd$watchlist, iteration - 1, feval)
|
||||
})
|
||||
msg <- simplify2array(msg)
|
||||
bst_evaluation <- rowMeans(msg)
|
||||
bst_evaluation_err <- sqrt(rowMeans(msg^2) - bst_evaluation^2)
|
||||
|
||||
# early_Stopping
|
||||
if (!is.null(early_stop_round)){
|
||||
score = strsplit(ret,'\\s+')[[1]][1+length(metrics)+1]
|
||||
score = strsplit(score,'\\+|:')[[1]][[2]]
|
||||
score = as.numeric(score)
|
||||
if ((maximize && score>bestScore) || (!maximize && score<bestScore)) {
|
||||
bestScore = score
|
||||
bestInd = i
|
||||
} else {
|
||||
if (i-bestInd>=early_stop_round) {
|
||||
earlyStopflag = TRUE
|
||||
cat('Stopping. Best iteration:',bestInd)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for (f in cb$post_iter) f()
|
||||
|
||||
if (stop_condition) break
|
||||
}
|
||||
|
||||
colnames <- str_split(string = history[1], pattern = "\t")[[1]] %>% .[2:length(.)] %>% str_extract(".*:") %>% str_replace(":","") %>% str_replace("-", ".")
|
||||
colnamesMean <- paste(colnames, "mean")
|
||||
if(showsd) colnamesStd <- paste(colnames, "std")
|
||||
|
||||
colnames <- c()
|
||||
if(showsd) for(i in 1:length(colnamesMean)) colnames <- c(colnames, colnamesMean[i], colnamesStd[i])
|
||||
else colnames <- colnamesMean
|
||||
|
||||
type <- rep(x = "numeric", times = length(colnames))
|
||||
dt <- read.table(text = "", colClasses = type, col.names = colnames) %>% as.data.table
|
||||
split <- str_split(string = history, pattern = "\t")
|
||||
|
||||
for(line in split) dt <- line[2:length(line)] %>% str_extract_all(pattern = "\\d*\\.+\\d*") %>% unlist %>% as.numeric %>% as.list %>% {rbindlist(list(dt, .), use.names = F, fill = F)}
|
||||
|
||||
if (prediction) {
|
||||
return(list(dt = dt,pred = predictValues))
|
||||
}
|
||||
return(dt)
|
||||
for (f in cb$finalize) f(finalize=TRUE)
|
||||
|
||||
# the CV result
|
||||
ret <- list(
|
||||
call = match.call(),
|
||||
params = params,
|
||||
callbacks = callbacks,
|
||||
evaluation_log = evaluation_log,
|
||||
niter = end_iteration,
|
||||
folds = folds
|
||||
)
|
||||
ret <- c(ret, basket)
|
||||
|
||||
class(ret) <- 'xgb.cv.synchronous'
|
||||
invisible(ret)
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(".")
|
||||
|
||||
|
||||
#' Print xgb.cv result
|
||||
#'
|
||||
#' Prints formatted results of \code{xgb.cv}.
|
||||
#'
|
||||
#' @param x an \code{xgb.cv.synchronous} object
|
||||
#' @param verbose whether to print detailed data
|
||||
#' @param ... passed to \code{data.table.print}
|
||||
#'
|
||||
#' @details
|
||||
#' When not verbose, it would only print the evaluation results,
|
||||
#' including the best iteration (when available).
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' cv <- xgb.cv(data = train$data, label = train$label, nfold = 5, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#' print(cv)
|
||||
#' print(cv, verbose=TRUE)
|
||||
#'
|
||||
#' @rdname print.xgb.cv
|
||||
#' @method print xgb.cv.synchronous
|
||||
#' @export
|
||||
print.xgb.cv.synchronous <- function(x, verbose=FALSE, ...) {
|
||||
cat('##### xgb.cv ', length(x$folds), '-folds\n', sep='')
|
||||
|
||||
if (verbose) {
|
||||
if (!is.null(x$call)) {
|
||||
cat('call:\n ')
|
||||
print(x$call)
|
||||
}
|
||||
if (!is.null(x$params)) {
|
||||
cat('params (as set within xgb.cv):\n')
|
||||
cat( ' ',
|
||||
paste(names(x$params),
|
||||
paste0('"', unlist(x$params), '"'),
|
||||
sep=' = ', collapse=', '), '\n', sep='')
|
||||
}
|
||||
if (!is.null(x$callbacks) && length(x$callbacks) > 0) {
|
||||
cat('callbacks:\n')
|
||||
lapply(callback.calls(x$callbacks), function(x) {
|
||||
cat(' ')
|
||||
print(x)
|
||||
})
|
||||
}
|
||||
|
||||
for (n in c('niter', 'best_iteration', 'best_ntreelimit')) {
|
||||
if (is.null(x[[n]]))
|
||||
next
|
||||
cat(n, ': ', x[[n]], '\n', sep='')
|
||||
}
|
||||
|
||||
if (!is.null(x$pred)) {
|
||||
cat('pred:\n')
|
||||
str(x$pred)
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
cat('evaluation_log:\n')
|
||||
print(x$evaluation_log, row.names = FALSE, ...)
|
||||
|
||||
if (!is.null(x$best_iteration)) {
|
||||
cat('Best iteration:\n')
|
||||
print(x$evaluation_log[x$best_iteration], row.names = FALSE, ...)
|
||||
}
|
||||
invisible(x)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
#'
|
||||
#' Save a xgboost model to text file. Could be parsed later.
|
||||
#'
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom stringr str_replace
|
||||
#' @importFrom data.table fread
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom data.table setnames
|
||||
#' @param model the model object.
|
||||
#' @param fname the name of the text file where to save the model text dump. If not provided or set to \code{NULL} the function will return the model as a \code{character} vector.
|
||||
#' @param fmap feature map file representing the type of feature.
|
||||
@@ -15,10 +10,11 @@
|
||||
#' See demo/ for walkthrough example in R, and
|
||||
#' \url{https://github.com/dmlc/xgboost/blob/master/demo/data/featmap.txt}
|
||||
#' for example Format.
|
||||
#' @param with.stats whether dump statistics of splits
|
||||
#' @param with_stats whether dump statistics of splits
|
||||
#' When this option is on, the model dump comes with two additional statistics:
|
||||
#' gain is the approximate loss function gain we get in each split;
|
||||
#' cover is the sum of second order gradient in each node.
|
||||
#' @param ... currently not used
|
||||
#'
|
||||
#' @return
|
||||
#' if fname is not provided or set to \code{NULL} the function will return the model as a \code{character} vector. Otherwise it will return \code{TRUE}.
|
||||
@@ -28,44 +24,36 @@
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#' # save the model in file 'xgb.model.dump'
|
||||
#' xgb.dump(bst, 'xgb.model.dump', with.stats = TRUE)
|
||||
#' xgb.dump(bst, 'xgb.model.dump', with_stats = TRUE)
|
||||
#'
|
||||
#' # print the model without saving it to a file
|
||||
#' print(xgb.dump(bst))
|
||||
#' @export
|
||||
#'
|
||||
xgb.dump <- function(model = NULL, fname = NULL, fmap = "", with.stats=FALSE) {
|
||||
if (class(model) != "xgb.Booster") {
|
||||
stop("model: argument must be type xgb.Booster")
|
||||
} else {
|
||||
model <- xgb.Booster.check(model)
|
||||
}
|
||||
if (!(class(fname) %in% c("character", "NULL") && length(fname) <= 1)) {
|
||||
stop("fname: argument must be type character (when provided)")
|
||||
}
|
||||
if (!(class(fmap) %in% c("character", "NULL") && length(fname) <= 1)) {
|
||||
stop("fmap: argument must be type character (when provided)")
|
||||
}
|
||||
xgb.dump <- function(model = NULL, fname = NULL, fmap = "", with_stats=FALSE, ...) {
|
||||
check.deprecation(...)
|
||||
if (class(model) != "xgb.Booster")
|
||||
stop("model: argument must be of type xgb.Booster")
|
||||
if (!(class(fname) %in% c("character", "NULL") && length(fname) <= 1))
|
||||
stop("fname: argument must be of type character (when provided)")
|
||||
if (!(class(fmap) %in% c("character", "NULL") && length(fmap) <= 1))
|
||||
stop("fmap: argument must be of type character (when provided)")
|
||||
|
||||
longString <- .Call("XGBoosterDumpModel_R", model$handle, fmap, as.integer(with.stats), PACKAGE = "xgboost")
|
||||
|
||||
dt <- fread(paste(longString, collapse = ""), sep = "\n", header = F)
|
||||
model <- xgb.Booster.check(model)
|
||||
model_dump <- .Call("XGBoosterDumpModel_R", model$handle, fmap, as.integer(with_stats), PACKAGE = "xgboost")
|
||||
|
||||
setnames(dt, "Lines")
|
||||
if (is.null(fname))
|
||||
model_dump <- stri_replace_all_regex(model_dump, '\t', '')
|
||||
|
||||
if(is.null(fname)) {
|
||||
result <- dt[Lines != "0"][, Lines := str_replace(Lines, "^\t+", "")][Lines != ""][, paste(Lines)]
|
||||
return(result)
|
||||
model_dump <- unlist(stri_split_regex(model_dump, '\n'))
|
||||
model_dump <- grep('^\\s*$', model_dump, invert = TRUE, value = TRUE)
|
||||
|
||||
if (is.null(fname)) {
|
||||
return(model_dump)
|
||||
} else {
|
||||
result <- dt[Lines != "0"][Lines != ""][, paste(Lines)] %>% writeLines(fname)
|
||||
writeLines(model_dump, fname)
|
||||
return(TRUE)
|
||||
}
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(c("Lines", "."))
|
||||
|
||||
135
R-package/R/xgb.ggplot.R
Normal file
135
R-package/R/xgb.ggplot.R
Normal file
@@ -0,0 +1,135 @@
|
||||
# ggplot backend for the xgboost plotting facilities
|
||||
|
||||
|
||||
#' @rdname xgb.plot.importance
|
||||
#' @export
|
||||
xgb.ggplot.importance <- function(importance_matrix = NULL, top_n = NULL, measure = NULL,
|
||||
rel_to_first = FALSE, n_clusters = c(1:10), ...) {
|
||||
|
||||
importance_matrix <- xgb.plot.importance(importance_matrix, top_n = top_n, measure = measure,
|
||||
rel_to_first = rel_to_first, plot = FALSE, ...)
|
||||
if (!requireNamespace("ggplot2", quietly = TRUE)) {
|
||||
stop("ggplot2 package is required", call. = FALSE)
|
||||
}
|
||||
if (!requireNamespace("Ckmeans.1d.dp", quietly = TRUE)) {
|
||||
stop("Ckmeans.1d.dp package is required", call. = FALSE)
|
||||
}
|
||||
|
||||
clusters <- suppressWarnings(
|
||||
Ckmeans.1d.dp::Ckmeans.1d.dp(importance_matrix$Importance, n_clusters)
|
||||
)
|
||||
importance_matrix[, Cluster := as.character(clusters$cluster)]
|
||||
|
||||
plot <-
|
||||
ggplot2::ggplot(importance_matrix,
|
||||
ggplot2::aes(x = factor(Feature, levels = rev(Feature)), y = Importance, width = 0.05),
|
||||
environment = environment()) +
|
||||
ggplot2::geom_bar(ggplot2::aes(fill = Cluster), stat = "identity", position = "identity") +
|
||||
ggplot2::coord_flip() +
|
||||
ggplot2::xlab("Features") +
|
||||
ggplot2::ggtitle("Feature importance") +
|
||||
ggplot2::theme(plot.title = ggplot2::element_text(lineheight = .9, face = "bold"),
|
||||
panel.grid.major.y = ggplot2::element_blank())
|
||||
return(plot)
|
||||
}
|
||||
|
||||
|
||||
#' @rdname xgb.plot.deepness
|
||||
#' @export
|
||||
xgb.ggplot.deepness <- function(model = NULL, which = c("2x1", "max.depth", "med.depth", "med.weight")) {
|
||||
|
||||
if (!requireNamespace("ggplot2", quietly = TRUE))
|
||||
stop("ggplot2 package is required for plotting the graph deepness.", call. = FALSE)
|
||||
|
||||
which <- match.arg(which)
|
||||
|
||||
dt_depths <- xgb.plot.deepness(model = model, plot = FALSE)
|
||||
dt_summaries <- dt_depths[, .(.N, Cover = mean(Cover)), Depth]
|
||||
setkey(dt_summaries, 'Depth')
|
||||
|
||||
if (which == "2x1") {
|
||||
p1 <-
|
||||
ggplot2::ggplot(dt_summaries) +
|
||||
ggplot2::geom_bar(ggplot2::aes(x = Depth, y = N), stat = "Identity") +
|
||||
ggplot2::xlab("") +
|
||||
ggplot2::ylab("Number of leafs") +
|
||||
ggplot2::ggtitle("Model complexity") +
|
||||
ggplot2::theme(
|
||||
plot.title = ggplot2::element_text(lineheight = 0.9, face = "bold"),
|
||||
panel.grid.major.y = ggplot2::element_blank(),
|
||||
axis.ticks = ggplot2::element_blank(),
|
||||
axis.text.x = ggplot2::element_blank()
|
||||
)
|
||||
|
||||
p2 <-
|
||||
ggplot2::ggplot(dt_summaries) +
|
||||
ggplot2::geom_bar(ggplot2::aes(x = Depth, y = Cover), stat = "Identity") +
|
||||
ggplot2::xlab("Leaf depth") +
|
||||
ggplot2::ylab("Weighted cover")
|
||||
|
||||
multiplot(p1, p2, cols = 1)
|
||||
return(invisible(list(p1, p2)))
|
||||
|
||||
} else if (which == "max.depth") {
|
||||
p <-
|
||||
ggplot2::ggplot(dt_depths[, max(Depth), Tree]) +
|
||||
ggplot2::geom_jitter(ggplot2::aes(x = Tree, y = V1),
|
||||
height = 0.15, alpha=0.4, size=3, stroke=0) +
|
||||
ggplot2::xlab("tree #") +
|
||||
ggplot2::ylab("Max tree leaf depth")
|
||||
return(p)
|
||||
|
||||
} else if (which == "med.depth") {
|
||||
p <-
|
||||
ggplot2::ggplot(dt_depths[, median(as.numeric(Depth)), Tree]) +
|
||||
ggplot2::geom_jitter(ggplot2::aes(x = Tree, y = V1),
|
||||
height = 0.15, alpha=0.4, size=3, stroke=0) +
|
||||
ggplot2::xlab("tree #") +
|
||||
ggplot2::ylab("Median tree leaf depth")
|
||||
return(p)
|
||||
|
||||
} else if (which == "med.weight") {
|
||||
p <-
|
||||
ggplot2::ggplot(dt_depths[, median(abs(Weight)), Tree]) +
|
||||
ggplot2::geom_point(ggplot2::aes(x = Tree, y = V1),
|
||||
alpha=0.4, size=3, stroke=0) +
|
||||
ggplot2::xlab("tree #") +
|
||||
ggplot2::ylab("Median absolute leaf weight")
|
||||
return(p)
|
||||
}
|
||||
}
|
||||
|
||||
# Plot multiple ggplot graph aligned by rows and columns.
|
||||
# ... the plots
|
||||
# cols number of columns
|
||||
# internal utility function
|
||||
multiplot <- function(..., cols = 1) {
|
||||
plots <- list(...)
|
||||
num_plots = length(plots)
|
||||
|
||||
layout <- matrix(seq(1, cols * ceiling(num_plots / cols)),
|
||||
ncol = cols, nrow = ceiling(num_plots / cols))
|
||||
|
||||
if (num_plots == 1) {
|
||||
print(plots[[1]])
|
||||
} else {
|
||||
grid::grid.newpage()
|
||||
grid::pushViewport(grid::viewport(layout = grid::grid.layout(nrow(layout), ncol(layout))))
|
||||
for (i in 1:num_plots) {
|
||||
# Get the i,j matrix positions of the regions that contain this subplot
|
||||
matchidx <- as.data.table(which(layout == i, arr.ind = TRUE))
|
||||
|
||||
print(
|
||||
plots[[i]], vp = grid::viewport(
|
||||
layout.pos.row = matchidx$row,
|
||||
layout.pos.col = matchidx$col
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globalVariables(c(
|
||||
"Cluster", "ggplot", "aes", "geom_bar", "coord_flip", "xlab", "ylab", "ggtitle", "theme",
|
||||
"element_blank", "element_text"
|
||||
))
|
||||
@@ -1,44 +1,31 @@
|
||||
#' Show importance of features in a model
|
||||
#'
|
||||
#' Read a xgboost model text dump.
|
||||
#' Can be tree or linear model (text dump of linear model are only supported in dev version of \code{Xgboost} for now).
|
||||
#'
|
||||
#' @importFrom data.table data.table
|
||||
#' @importFrom data.table setnames
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom Matrix colSums
|
||||
#' @importFrom Matrix cBind
|
||||
#' @importFrom Matrix sparseVector
|
||||
#'
|
||||
#' @param feature_names names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#'
|
||||
#' @param filename_dump the path to the text file storing the model. Model dump must include the gain per feature and per tree (\code{with.stats = T} in function \code{xgb.dump}).
|
||||
#'
|
||||
#' @param model generated by the \code{xgb.train} function. Avoid the creation of a dump file.
|
||||
#' Create a \code{data.table} of the most important features of a model.
|
||||
#'
|
||||
#' @param feature_names names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#' @param model generated by the \code{xgb.train} function.
|
||||
#' @param data the dataset used for the training step. Will be used with \code{label} parameter for co-occurence computation. More information in \code{Detail} part. This parameter is optional.
|
||||
#'
|
||||
#' @param label the label vetor used for the training step. Will be used with \code{data} parameter for co-occurence computation. More information in \code{Detail} part. This parameter is optional.
|
||||
#'
|
||||
#' @param target a function which returns \code{TRUE} or \code{1} when an observation should be count as a co-occurence and \code{FALSE} or \code{0} otherwise. Default function is provided for computing co-occurences in a binary classification. The \code{target} function should have only one parameter. This parameter will be used to provide each important feature vector after having applied the split condition, therefore these vector will be only made of 0 and 1 only, whatever was the information before. More information in \code{Detail} part. This parameter is optional.
|
||||
#'
|
||||
#' @return A \code{data.table} of the features used in the model with their average gain (and their weight for boosted tree model) in the model.
|
||||
#'
|
||||
#' @details
|
||||
#' This is the function to understand the model trained (and through your model, your data).
|
||||
#'
|
||||
#' Results are returned for both linear and tree models.
|
||||
#' This function is for both linear and tree models.
|
||||
#'
|
||||
#' \code{data.table} is returned by the function.
|
||||
#' There are 3 columns :
|
||||
#' The columns are :
|
||||
#' \itemize{
|
||||
#' \item \code{Features} name of the features as provided in \code{feature_names} or already present in the model dump.
|
||||
#' \item \code{Gain} contribution of each feature to the model. For boosted tree model, each gain of each feature of each tree is taken into account, then average per feature to give a vision of the entire model. Highest percentage means important feature to predict the \code{label} used for the training ;
|
||||
#' \item \code{Cover} metric of the number of observation related to this feature (only available for tree models) ;
|
||||
#' \item \code{Weight} percentage representing the relative number of times a feature have been taken into trees. \code{Gain} should be prefered to search the most important feature. For boosted linear model, this column has no meaning.
|
||||
#' \item \code{Features} name of the features as provided in \code{feature_names} or already present in the model dump;
|
||||
#' \item \code{Gain} contribution of each feature to the model. For boosted tree model, each gain of each feature of each tree is taken into account, then average per feature to give a vision of the entire model. Highest percentage means important feature to predict the \code{label} used for the training (only available for tree models);
|
||||
#' \item \code{Cover} metric of the number of observation related to this feature (only available for tree models);
|
||||
#' \item \code{Weight} percentage representing the relative number of times a feature have been taken into trees.
|
||||
#' }
|
||||
#'
|
||||
#' If you don't provide \code{feature_names}, index of the features will be used instead.
|
||||
#'
|
||||
#' Because the index is extracted from the model dump (made on the C++ side), it starts at 0 (usual in C++) instead of 1 (usual in R).
|
||||
#'
|
||||
#' Co-occurence count
|
||||
#' ------------------
|
||||
#'
|
||||
@@ -51,57 +38,54 @@
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#'
|
||||
#' # Both dataset are list with two items, a sparse matrix and labels
|
||||
#' # (labels = outcome column which will be learned).
|
||||
#' # Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
#' train <- agaricus.train
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' # train$data@@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
#' xgb.importance(train$data@@Dimnames[[2]], model = bst)
|
||||
#' xgb.importance(colnames(agaricus.train$data), model = bst)
|
||||
#'
|
||||
#' # Same thing with co-occurence computation this time
|
||||
#' xgb.importance(train$data@@Dimnames[[2]], model = bst, data = train$data, label = train$label)
|
||||
#' xgb.importance(colnames(agaricus.train$data), model = bst, data = agaricus.train$data, label = agaricus.train$label)
|
||||
#'
|
||||
#' @export
|
||||
xgb.importance <- function(feature_names = NULL, filename_dump = NULL, model = NULL, data = NULL, label = NULL, target = function(x) ((x + label) == 2)){
|
||||
if (!class(feature_names) %in% c("character", "NULL")) {
|
||||
stop("feature_names: Has to be a vector of character or NULL if the model dump already contains feature name. Look at this function documentation to see where to get feature names.")
|
||||
xgb.importance <- function(feature_names = NULL, model = NULL, data = NULL, label = NULL, target = function(x) ( (x + label) == 2)){
|
||||
if (!class(feature_names) %in% c("character", "NULL")) {
|
||||
stop("feature_names: Has to be a vector of character or NULL if the model already contains feature name. Look at this function documentation to see where to get feature names.")
|
||||
}
|
||||
|
||||
if (!(class(filename_dump) %in% c("character", "NULL") && length(filename_dump) <= 1)) {
|
||||
stop("filename_dump: Has to be a path to the model dump file.")
|
||||
}
|
||||
|
||||
if (!class(model) %in% c("xgb.Booster", "NULL")) {
|
||||
|
||||
if (class(model) != "xgb.Booster") {
|
||||
stop("model: Has to be an object of class xgb.Booster model generaged by the xgb.train function.")
|
||||
}
|
||||
|
||||
if((is.null(data) & !is.null(label)) |(!is.null(data) & is.null(label))) {
|
||||
|
||||
if((is.null(data) & !is.null(label)) | (!is.null(data) & is.null(label))) {
|
||||
stop("data/label: Provide the two arguments if you want co-occurence computation or none of them if you are not interested but not one of them only.")
|
||||
}
|
||||
|
||||
|
||||
if(class(label) == "numeric"){
|
||||
if(sum(label == 0) / length(label) > 0.5) label <- as(label, "sparseVector")
|
||||
}
|
||||
|
||||
if(is.null(model)){
|
||||
text <- readLines(filename_dump)
|
||||
} else {
|
||||
text <- xgb.dump(model = model, with.stats = T)
|
||||
}
|
||||
treeDump <- function(feature_names, text, keepDetail){
|
||||
if(keepDetail) groupBy <- c("Feature", "Split", "MissingNo") else groupBy <- "Feature"
|
||||
xgb.model.dt.tree(feature_names = feature_names, text = text)[,"MissingNo" := Missing == No ][Feature != "Leaf",.(Gain = sum(Quality), Cover = sum(Cover), Frequency = .N), by = groupBy, with = T][,`:=`(Gain = Gain / sum(Gain), Cover = Cover / sum(Cover), Frequency = Frequency / sum(Frequency))][order(Gain, decreasing = T)]
|
||||
}
|
||||
|
||||
if(text[2] == "bias:"){
|
||||
result <- readLines(filename_dump) %>% linearDump(feature_names, .)
|
||||
linearDump <- function(feature_names, text){
|
||||
weights <- which(text == "weight:") %>% {a =. + 1; text[a:length(text)]} %>% as.numeric
|
||||
if(is.null(feature_names)) feature_names <- seq(to = length(weights))
|
||||
data.table(Feature = feature_names, Weight = weights)
|
||||
}
|
||||
|
||||
model.text.dump <- xgb.dump(model = model, with_stats = T)
|
||||
|
||||
if(model.text.dump[2] == "bias:"){
|
||||
result <- model.text.dump %>% linearDump(feature_names, .)
|
||||
if(!is.null(data) | !is.null(label)) warning("data/label: these parameters should only be provided with decision tree based models.")
|
||||
} else {
|
||||
result <- treeDump(feature_names, text = text, keepDetail = !is.null(data))
|
||||
|
||||
result <- treeDump(feature_names, text = model.text.dump, keepDetail = !is.null(data))
|
||||
|
||||
# Co-occurence computation
|
||||
if(!is.null(data) & !is.null(label) & nrow(result) > 0) {
|
||||
# Take care of missing column
|
||||
# Take care of missing column
|
||||
a <- data[, result[MissingNo == T,Feature], drop=FALSE] != 0
|
||||
# Bind the two Matrix and reorder columns
|
||||
c <- data[, result[MissingNo == F,Feature], drop=FALSE] %>% cBind(a,.) %>% .[,result[,Feature]]
|
||||
@@ -109,26 +93,14 @@ xgb.importance <- function(feature_names = NULL, filename_dump = NULL, model = N
|
||||
# Apply split
|
||||
d <- data[, result[,Feature], drop=FALSE] < as.numeric(result[,Split])
|
||||
apply(c & d, 2, . %>% target %>% sum) -> vec
|
||||
|
||||
result <- result[, "RealCover":= as.numeric(vec), with = F][, "RealCover %" := RealCover / sum(label)][,MissingNo:=NULL]
|
||||
}
|
||||
|
||||
result <- result[, "RealCover" := as.numeric(vec), with = F][, "RealCover %" := RealCover / sum(label)][,MissingNo := NULL]
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
treeDump <- function(feature_names, text, keepDetail){
|
||||
if(keepDetail) groupBy <- c("Feature", "Split", "MissingNo") else groupBy <- "Feature"
|
||||
|
||||
result <- xgb.model.dt.tree(feature_names = feature_names, text = text)[,"MissingNo":= Missing == No ][Feature!="Leaf",.(Gain = sum(Quality), Cover = sum(Cover), Frequence = .N), by = groupBy, with = T][,`:=`(Gain = Gain/sum(Gain), Cover = Cover/sum(Cover), Frequence = Frequence/sum(Frequence))][order(Gain, decreasing = T)]
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
linearDump <- function(feature_names, text){
|
||||
which(text == "weight:") %>% {a=.+1;text[a:length(text)]} %>% as.numeric %>% data.table(Feature = feature_names, Weight = .)
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(c(".", "Feature", "Split", "No", "Missing", "MissingNo", "RealCover"))
|
||||
globalVariables(c(".", ".N", "Gain", "Frequency", "Feature", "Split", "No", "Missing", "MissingNo", "RealCover"))
|
||||
|
||||
@@ -9,17 +9,16 @@
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#' xgb.save(bst, 'xgb.model')
|
||||
#' bst <- xgb.load('xgb.model')
|
||||
#' pred <- predict(bst, test$data)
|
||||
#' @export
|
||||
#'
|
||||
xgb.load <- function(modelfile) {
|
||||
if (is.null(modelfile))
|
||||
if (is.null(modelfile))
|
||||
stop("xgb.load: modelfile cannot be NULL")
|
||||
|
||||
|
||||
handle <- xgb.Booster(modelfile = modelfile)
|
||||
# re-use modelfile if it is raw so we donot need to serialize
|
||||
if (typeof(modelfile) == "raw") {
|
||||
@@ -27,6 +26,6 @@ xgb.load <- function(modelfile) {
|
||||
} else {
|
||||
bst <- xgb.handleToBooster(handle, NULL)
|
||||
}
|
||||
bst <- xgb.Booster.check(bst)
|
||||
bst <- xgb.Booster.check(bst, saveraw = TRUE)
|
||||
return(bst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,170 +1,122 @@
|
||||
#' Convert tree model dump to data.table
|
||||
#' Parse a boosted tree model text dump
|
||||
#'
|
||||
#' Read a tree model text dump and return a data.table.
|
||||
#' Parse a boosted tree model text dump into a \code{data.table} structure.
|
||||
#'
|
||||
#' @importFrom data.table data.table
|
||||
#' @importFrom data.table set
|
||||
#' @importFrom data.table rbindlist
|
||||
#' @importFrom data.table copy
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom magrittr not
|
||||
#' @importFrom magrittr add
|
||||
#' @importFrom stringr str_extract
|
||||
#' @importFrom stringr str_split
|
||||
#' @importFrom stringr str_extract
|
||||
#' @importFrom stringr str_trim
|
||||
#' @param feature_names names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#' @param filename_dump the path to the text file storing the model. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}).
|
||||
#' @param model dump generated by the \code{xgb.train} function. Avoid the creation of a dump file.
|
||||
#' @param text dump generated by the \code{xgb.dump} function. Avoid the creation of a dump file. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}).
|
||||
#' @param n_first_tree limit the plot to the n first trees. If \code{NULL}, all trees of the model are plotted. Performance can be low for huge models.
|
||||
#' @param feature_names character vector of feature names. If the model already
|
||||
#' contains feature names, this argument should be \code{NULL} (default value)
|
||||
#' @param model object of class \code{xgb.Booster}
|
||||
#' @param text \code{character} vector previously generated by the \code{xgb.dump}
|
||||
#' function (where parameter \code{with_stats = TRUE} should have been set).
|
||||
#' @param n_first_tree limit the parsing to the \code{n} first trees.
|
||||
#' If set to \code{NULL}, all trees of the model are parsed.
|
||||
#'
|
||||
#' @return A \code{data.table} of the features used in the model with their gain, cover and few other thing.
|
||||
#' @return
|
||||
#' A \code{data.table} with detailed information about model trees' nodes.
|
||||
#'
|
||||
#' @details
|
||||
#' General function to convert a text dump of tree model to a Matrix. The purpose is to help user to explore the model and get a better understanding of it.
|
||||
#'
|
||||
#' The content of the \code{data.table} is organised that way:
|
||||
#' The columns of the \code{data.table} are:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{ID}: unique identifier of a node ;
|
||||
#' \item \code{Feature}: feature used in the tree to operate a split. When Leaf is indicated, it is the end of a branch ;
|
||||
#' \item \code{Split}: value of the chosen feature where is operated the split ;
|
||||
#' \item \code{Yes}: ID of the feature for the next node in the branch when the split condition is met ;
|
||||
#' \item \code{No}: ID of the feature for the next node in the branch when the split condition is not met ;
|
||||
#' \item \code{Missing}: ID of the feature for the next node in the branch for observation where the feature used for the split are not provided ;
|
||||
#' \item \code{Quality}: it's the gain related to the split in this specific node ;
|
||||
#' \item \code{Cover}: metric to measure the number of observation affected by the split ;
|
||||
#' \item \code{Tree}: ID of the tree. It is included in the main ID ;
|
||||
#' \item \code{Yes.X} or \code{No.X}: data related to the pointer in \code{Yes} or \code{No} column ;
|
||||
#' \item \code{Tree}: ID of a tree in a model
|
||||
#' \item \code{Node}: ID of a node in a tree
|
||||
#' \item \code{ID}: unique identifier of a node in a model
|
||||
#' \item \code{Feature}: for a branch node, it's a feature id or name (when available);
|
||||
#' for a leaf note, it simply labels it as \code{'Leaf'}
|
||||
#' \item \code{Split}: location of the split for a branch node (split condition is always "less than")
|
||||
#' \item \code{Yes}: ID of the next node when the split condition is met
|
||||
#' \item \code{No}: ID of the next node when the split condition is not met
|
||||
#' \item \code{Missing}: ID of the next node when branch value is missing
|
||||
#' \item \code{Quality}: either the split gain (change in loss) or the leaf value
|
||||
#' \item \code{Cover}: metric related to the number of observation either seen by a split
|
||||
#' or collected by a leaf during training.
|
||||
#' }
|
||||
#'
|
||||
#'
|
||||
#' @examples
|
||||
#' # Basic use:
|
||||
#'
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#'
|
||||
#' #Both dataset are list with two items, a sparse matrix and labels
|
||||
#' #(labels = outcome column which will be learned).
|
||||
#' #Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
#' train <- agaricus.train
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' (dt <- xgb.model.dt.tree(colnames(agaricus.train$data), bst))
|
||||
#'
|
||||
#' #agaricus.test$data@@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
#' xgb.model.dt.tree(agaricus.train$data@@Dimnames[[2]], model = bst)
|
||||
#'
|
||||
#' # How to match feature names of splits that are following a current 'Yes' branch:
|
||||
#'
|
||||
#' merge(dt, dt[, .(ID, Y.Feature=Feature)], by.x='Yes', by.y='ID', all.x=TRUE)[order(Tree,Node)]
|
||||
#'
|
||||
#' @export
|
||||
xgb.model.dt.tree <- function(feature_names = NULL, filename_dump = NULL, model = NULL, text = NULL, n_first_tree = NULL){
|
||||
xgb.model.dt.tree <- function(feature_names = NULL, model = NULL, text = NULL,
|
||||
n_first_tree = NULL){
|
||||
|
||||
if (!class(feature_names) %in% c("character", "NULL")) {
|
||||
stop("feature_names: Has to be a vector of character or NULL if the model dump already contains feature name. Look at this function documentation to see where to get feature names.")
|
||||
}
|
||||
if (!(class(filename_dump) %in% c("character", "NULL") && length(filename_dump) <= 1)) {
|
||||
stop("filename_dump: Has to be a character vector of size 1 representing the path to the model dump file.")
|
||||
} else if (!is.null(filename_dump) && !file.exists(filename_dump)) {
|
||||
stop("filename_dump: path to the model doesn't exist.")
|
||||
} else if(is.null(filename_dump) && is.null(model) && is.null(text)){
|
||||
stop("filename_dump & model & text: no path to dump model, no model, no text dump, have been provided.")
|
||||
if (!class(feature_names) %in% c("character", "NULL")) {
|
||||
stop("feature_names: Has to be a vector of character\n",
|
||||
" or NULL if the model dump already contains feature names.\n",
|
||||
" Look at this function documentation to see where to get feature names.")
|
||||
}
|
||||
|
||||
if (!class(model) %in% c("xgb.Booster", "NULL")) {
|
||||
stop("model: Has to be an object of class xgb.Booster model generaged by the xgb.train function.")
|
||||
}
|
||||
|
||||
if (!class(text) %in% c("character", "NULL")) {
|
||||
stop("text: Has to be a vector of character or NULL if a path to the model dump has already been provided.")
|
||||
if (class(model) != "xgb.Booster" & class(text) != "character") {
|
||||
stop("Either 'model' has to be an object of class xgb.Booster\n",
|
||||
" or 'text' has to be a character vector with the result of xgb.dump\n",
|
||||
" (or NULL if the model was provided).")
|
||||
}
|
||||
|
||||
if (!class(n_first_tree) %in% c("numeric", "NULL") | length(n_first_tree) > 1) {
|
||||
stop("n_first_tree: Has to be a numeric vector of size 1.")
|
||||
}
|
||||
|
||||
if(!is.null(model)){
|
||||
text = xgb.dump(model = model, with.stats = T)
|
||||
} else if(!is.null(filename_dump)){
|
||||
text <- readLines(filename_dump) %>% str_trim(side = "both")
|
||||
if(is.null(text)){
|
||||
text <- xgb.dump(model = model, with_stats = T)
|
||||
}
|
||||
|
||||
position <- str_match(text, "booster") %>% is.na %>% not %>% which %>% c(length(text)+1)
|
||||
position <- which(!is.na(stri_match_first_regex(text, "booster")))
|
||||
|
||||
extract <- function(x, pattern) str_extract(x, pattern) %>% str_split("=") %>% lapply(function(x) x[2] %>% as.numeric) %>% unlist
|
||||
add.tree.id <- function(x, i) paste(i, x, sep = "-")
|
||||
|
||||
n_round <- min(length(position) - 1, n_first_tree)
|
||||
anynumber_regex <- "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"
|
||||
|
||||
addTreeId <- function(x, i) paste(i,x,sep = "-")
|
||||
td <- data.table(t=text)
|
||||
td[position, Tree := 1L]
|
||||
td[, Tree := cumsum(ifelse(is.na(Tree), 0L, Tree)) - 1L]
|
||||
|
||||
allTrees <- data.table()
|
||||
|
||||
anynumber_regex<-"[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"
|
||||
for(i in 1:n_round){
|
||||
|
||||
tree <- text[(position[i]+1):(position[i+1]-1)]
|
||||
|
||||
# avoid tree made of a leaf only (no split)
|
||||
if(length(tree) <2) next
|
||||
|
||||
treeID <- i-1
|
||||
|
||||
notLeaf <- str_match(tree, "leaf") %>% is.na
|
||||
leaf <- notLeaf %>% not %>% tree[.]
|
||||
branch <- notLeaf %>% tree[.]
|
||||
idBranch <- str_extract(branch, "\\d*:") %>% str_replace(":", "") %>% addTreeId(treeID)
|
||||
idLeaf <- str_extract(leaf, "\\d*:") %>% str_replace(":", "") %>% addTreeId(treeID)
|
||||
featureBranch <- str_extract(branch, "f\\d*<") %>% str_replace("<", "") %>% str_replace("f", "") %>% as.numeric
|
||||
if(!is.null(feature_names)){
|
||||
featureBranch <- feature_names[featureBranch + 1]
|
||||
}
|
||||
featureLeaf <- rep("Leaf", length(leaf))
|
||||
splitBranch <- str_extract(branch, paste0("<",anynumber_regex,"\\]")) %>% str_replace("<", "") %>% str_replace("\\]", "")
|
||||
splitLeaf <- rep(NA, length(leaf))
|
||||
yesBranch <- extract(branch, "yes=\\d*") %>% addTreeId(treeID)
|
||||
yesLeaf <- rep(NA, length(leaf))
|
||||
noBranch <- extract(branch, "no=\\d*") %>% addTreeId(treeID)
|
||||
noLeaf <- rep(NA, length(leaf))
|
||||
missingBranch <- extract(branch, "missing=\\d+") %>% addTreeId(treeID)
|
||||
missingLeaf <- rep(NA, length(leaf))
|
||||
qualityBranch <- extract(branch, paste0("gain=",anynumber_regex))
|
||||
qualityLeaf <- extract(leaf, paste0("leaf=",anynumber_regex))
|
||||
coverBranch <- extract(branch, "cover=\\d*\\.*\\d*")
|
||||
coverLeaf <- extract(leaf, "cover=\\d*\\.*\\d*")
|
||||
dt <- data.table(ID = c(idBranch, idLeaf), Feature = c(featureBranch, featureLeaf), Split = c(splitBranch, splitLeaf), Yes = c(yesBranch, yesLeaf), No = c(noBranch, noLeaf), Missing = c(missingBranch, missingLeaf), Quality = c(qualityBranch, qualityLeaf), Cover = c(coverBranch, coverLeaf))[order(ID)][,Tree:=treeID]
|
||||
|
||||
allTrees <- rbindlist(list(allTrees, dt), use.names = T, fill = F)
|
||||
}
|
||||
n_first_tree <- min(max(td$Tree), n_first_tree)
|
||||
td <- td[Tree <= n_first_tree & !grepl('^booster', t)]
|
||||
|
||||
yes <- allTrees[!is.na(Yes),Yes]
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "Yes.Feature",
|
||||
value = allTrees[ID == yes,Feature])
|
||||
td[, Node := stri_match_first_regex(t, "(\\d+):")[,2] %>% as.numeric ]
|
||||
td[, ID := add.tree.id(Node, Tree)]
|
||||
td[, isLeaf := !is.na(stri_match_first_regex(t, "leaf"))]
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "Yes.Cover",
|
||||
value = allTrees[ID == yes,Cover])
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "Yes.Quality",
|
||||
value = allTrees[ID == yes,Quality])
|
||||
# parse branch lines
|
||||
td[isLeaf==FALSE, c("Feature", "Split", "Yes", "No", "Missing", "Quality", "Cover") := {
|
||||
rx <- paste0("f(\\d+)<(", anynumber_regex, ")\\] yes=(\\d+),no=(\\d+),missing=(\\d+),",
|
||||
"gain=(", anynumber_regex, "),cover=(", anynumber_regex, ")")
|
||||
# skip some indices with spurious capture groups from anynumber_regex
|
||||
xtr <- stri_match_first_regex(t, rx)[, c(2,3,5,6,7,8,10)]
|
||||
xtr[, 3:5] <- add.tree.id(xtr[, 3:5], Tree)
|
||||
lapply(1:ncol(xtr), function(i) xtr[,i])
|
||||
}]
|
||||
# assign feature_names when available
|
||||
td[isLeaf==FALSE & !is.null(feature_names),
|
||||
Feature := feature_names[as.numeric(Feature) + 1] ]
|
||||
|
||||
no <- allTrees[!is.na(No),No]
|
||||
# parse leaf lines
|
||||
td[isLeaf==TRUE, c("Feature", "Quality", "Cover") := {
|
||||
rx <- paste0("leaf=(", anynumber_regex, "),cover=(", anynumber_regex, ")")
|
||||
xtr <- stri_match_first_regex(t, rx)[, c(2,4)]
|
||||
c("Leaf", lapply(1:ncol(xtr), function(i) xtr[,i]))
|
||||
}]
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "No.Feature",
|
||||
value = allTrees[ID == no,Feature])
|
||||
# convert some columns to numeric
|
||||
numeric_cols <- c("Quality", "Cover")
|
||||
td[, (numeric_cols) := lapply(.SD, as.numeric), .SDcols=numeric_cols]
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "No.Cover",
|
||||
value = allTrees[ID == no,Cover])
|
||||
td[, t := NULL]
|
||||
td[, isLeaf := NULL]
|
||||
|
||||
set(allTrees, i = which(allTrees[,Feature]!= "Leaf"),
|
||||
j = "No.Quality",
|
||||
value = allTrees[ID == no,Quality])
|
||||
|
||||
allTrees
|
||||
td[order(Tree, Node)]
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(c("ID", "Tree", "Yes", ".", ".N", "Feature", "Cover", "Quality", "No", "Gain", "Frequence"))
|
||||
globalVariables(c("Tree", "Node", "ID", "Feature", "t", "isLeaf",".SD", ".SDcols"))
|
||||
|
||||
149
R-package/R/xgb.plot.deepness.R
Normal file
149
R-package/R/xgb.plot.deepness.R
Normal file
@@ -0,0 +1,149 @@
|
||||
#' Plot model trees deepness
|
||||
#'
|
||||
#' Visualizes distributions related to depth of tree leafs.
|
||||
#' \code{xgb.plot.deepness} uses base R graphics, while \code{xgb.ggplot.deepness} uses the ggplot backend.
|
||||
#'
|
||||
#' @param model either an \code{xgb.Booster} model generated by the \code{xgb.train} function
|
||||
#' or a data.table result of the \code{xgb.model.dt.tree} function.
|
||||
#' @param plot (base R barplot) whether a barplot should be produced.
|
||||
#' If FALSE, only a data.table is returned.
|
||||
#' @param which which distribution to plot (see details).
|
||||
#' @param ... other parameters passed to \code{barplot} or \code{plot}.
|
||||
#'
|
||||
#' @details
|
||||
#'
|
||||
#' When \code{which="2x1"}, two distributions with respect to the leaf depth
|
||||
#' are plotted on top of each other:
|
||||
#' \itemize{
|
||||
#' \item the distribution of the number of leafs in a tree model at a certain depth;
|
||||
#' \item the distribution of average weighted number of observations ("cover")
|
||||
#' ending up in leafs at certain depth.
|
||||
#' }
|
||||
#' Those could be helpful in determining sensible ranges of the \code{max_depth}
|
||||
#' and \code{min_child_weight} parameters.
|
||||
#'
|
||||
#' When \code{which="max.depth"} or \code{which="med.depth"}, plots of either maximum or median depth
|
||||
#' per tree with respect to tree number are created. And \code{which="med.weight"} allows to see how
|
||||
#' a tree's median absolute leaf weight changes through the iterations.
|
||||
#'
|
||||
#' This function was inspired by the blog post
|
||||
#' \url{http://aysent.github.io/2015/11/08/random-forest-leaf-visualization.html}.
|
||||
#'
|
||||
#' @return
|
||||
#'
|
||||
#' Other than producing plots (when \code{plot=TRUE}), the \code{xgb.plot.deepness} function
|
||||
#' silently returns a processed data.table where each row corresponds to a terminal leaf in a tree model,
|
||||
#' and contains information about leaf's depth, cover, and weight (which is used in calculating predictions).
|
||||
#'
|
||||
#' The \code{xgb.ggplot.deepness} silently returns either a list of two ggplot graphs when \code{which="2x1"}
|
||||
#' or a single ggplot graph for the other \code{which} options.
|
||||
#'
|
||||
#' @seealso
|
||||
#'
|
||||
#' \code{\link{xgb.train}}, \code{\link{xgb.model.dt.tree}}.
|
||||
#'
|
||||
#' @examples
|
||||
#'
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#'
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 15,
|
||||
#' eta = 0.1, nthread = 2, nrounds = 50, objective = "binary:logistic",
|
||||
#' subsample = 0.5, min_child_weight = 2)
|
||||
#'
|
||||
#' xgb.plot.deepness(bst)
|
||||
#' xgb.ggplot.deepness(bst)
|
||||
#'
|
||||
#' xgb.plot.deepness(bst, which='max.depth', pch=16, col=rgb(0,0,1,0.3), cex=2)
|
||||
#'
|
||||
#' xgb.plot.deepness(bst, which='med.weight', pch=16, col=rgb(0,0,1,0.3), cex=2)
|
||||
#'
|
||||
#' @rdname xgb.plot.deepness
|
||||
#' @export
|
||||
xgb.plot.deepness <- function(model = NULL, which = c("2x1", "max.depth", "med.depth", "med.weight"),
|
||||
plot = TRUE, ...) {
|
||||
|
||||
if (!(class(model) == "xgb.Booster" || is.data.table(model)))
|
||||
stop("model: Has to be either an xgb.Booster model generaged by the xgb.train function\n",
|
||||
"or a data.table result of the xgb.importance function")
|
||||
|
||||
if (!requireNamespace("igraph", quietly = TRUE))
|
||||
stop("igraph package is required for plotting the graph deepness.", call. = FALSE)
|
||||
|
||||
which <- match.arg(which)
|
||||
|
||||
dt_tree <- model
|
||||
if (class(model) == "xgb.Booster")
|
||||
dt_tree <- xgb.model.dt.tree(model = model)
|
||||
|
||||
if (!all(c("Feature", "Tree", "ID", "Yes", "No", "Cover") %in% colnames(dt_tree)))
|
||||
stop("Model tree columns are not as expected!\n",
|
||||
" Note that this function works only for tree models.")
|
||||
|
||||
dt_depths <- merge(get.leaf.depth(dt_tree), dt_tree[, .(ID, Cover, Weight=Quality)], by = "ID")
|
||||
setkeyv(dt_depths, c("Tree", "ID"))
|
||||
# count by depth levels, and also calculate average cover at a depth
|
||||
dt_summaries <- dt_depths[, .(.N, Cover = mean(Cover)), Depth]
|
||||
setkey(dt_summaries, "Depth")
|
||||
|
||||
if (plot) {
|
||||
if (which == "2x1") {
|
||||
op <- par(no.readonly = TRUE)
|
||||
par(mfrow=c(2,1),
|
||||
oma = c(3,1,3,1) + 0.1,
|
||||
mar = c(1,4,1,0) + 0.1)
|
||||
|
||||
dt_summaries[, barplot(N, border=NA, ylab = 'Number of leafs', ...)]
|
||||
|
||||
dt_summaries[, barplot(Cover, border=NA, ylab = "Weighted cover", names.arg=Depth, ...)]
|
||||
|
||||
title("Model complexity", xlab = "Leaf depth", outer = TRUE, line = 1)
|
||||
par(op)
|
||||
} else if (which == "max.depth") {
|
||||
dt_depths[, max(Depth), Tree][
|
||||
, plot(jitter(V1, amount = 0.1) ~ Tree, ylab = 'Max tree leaf depth', xlab = "tree #", ...)]
|
||||
} else if (which == "med.depth") {
|
||||
dt_depths[, median(as.numeric(Depth)), Tree][
|
||||
, plot(jitter(V1, amount = 0.1) ~ Tree, ylab = 'Median tree leaf depth', xlab = "tree #", ...)]
|
||||
} else if (which == "med.weight") {
|
||||
dt_depths[, median(abs(Weight)), Tree][
|
||||
, plot(V1 ~ Tree, ylab = 'Median absolute leaf weight', xlab = "tree #", ...)]
|
||||
}
|
||||
}
|
||||
invisible(dt_depths)
|
||||
}
|
||||
|
||||
# Extract path depths from root to leaf
|
||||
# from data.table containing the nodes and edges of the trees.
|
||||
# internal utility function
|
||||
get.leaf.depth <- function(dt_tree) {
|
||||
# extract tree graph's edges
|
||||
dt_edges <- rbindlist(list(
|
||||
dt_tree[Feature != "Leaf", .(ID, To=Yes, Tree)],
|
||||
dt_tree[Feature != "Leaf", .(ID, To=No, Tree)]
|
||||
))
|
||||
# whether "To" is a leaf:
|
||||
dt_edges <-
|
||||
merge(dt_edges,
|
||||
dt_tree[Feature == "Leaf", .(ID, Leaf = TRUE)],
|
||||
all.x = TRUE, by.x = "To", by.y = "ID")
|
||||
dt_edges[is.na(Leaf), Leaf := FALSE]
|
||||
|
||||
dt_edges[, {
|
||||
graph <- igraph::graph_from_data_frame(.SD[,.(ID, To)])
|
||||
# min(ID) in a tree is a root node
|
||||
paths_tmp <- igraph::shortest_paths(graph, from = min(ID), to = To[Leaf == TRUE])
|
||||
# list of paths to each leaf in a tree
|
||||
paths <- lapply(paths_tmp$vpath, names)
|
||||
# combine into a resulting path lengths table for a tree
|
||||
data.table(Depth = sapply(paths, length), ID = To[Leaf == TRUE])
|
||||
}, by = Tree]
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(
|
||||
c(
|
||||
".N", "N", "Depth", "Quality", "Cover", "Tree", "ID", "Yes", "No", "Feature"
|
||||
)
|
||||
)
|
||||
@@ -1,57 +1,125 @@
|
||||
#' Plot feature importance bar graph
|
||||
#'
|
||||
#' Read a data.table containing feature importance details and plot it.
|
||||
#'
|
||||
#' @importFrom magrittr %>%
|
||||
#' @param importance_matrix a \code{data.table} returned by the \code{xgb.importance} function.
|
||||
#' @param numberOfClusters a \code{numeric} vector containing the min and the max range of the possible number of clusters of bars.
|
||||
#' Plot feature importance as a bar graph
|
||||
#'
|
||||
#' @return A \code{ggplot2} bar graph representing each feature by a horizontal bar. Longer is the bar, more important is the feature. Features are classified by importance and clustered by importance. The group is represented through the color of the bar.
|
||||
#' Represents previously calculated feature importance as a bar graph.
|
||||
#' \code{xgb.plot.importance} uses base R graphics, while \code{xgb.ggplot.importance} uses the ggplot backend.
|
||||
#'
|
||||
#' @details
|
||||
#' The purpose of this function is to easily represent the importance of each feature of a model.
|
||||
#' The function return a ggplot graph, therefore each of its characteristic can be overriden (to customize it).
|
||||
#' In particular you may want to override the title of the graph. To do so, add \code{+ ggtitle("A GRAPH NAME")} next to the value returned by this function.
|
||||
#'
|
||||
#' @param importance_matrix a \code{data.table} returned by \code{\link{xgb.importance}}.
|
||||
#' @param top_n maximal number of top features to include into the plot.
|
||||
#' @param measure the name of importance measure to plot.
|
||||
#' When \code{NULL}, 'Gain' would be used for trees and 'Weight' would be used for gblinear.
|
||||
#' @param rel_to_first whether importance values should be represented as relative to the highest ranked feature.
|
||||
#' See Details.
|
||||
#' @param left_margin (base R barplot) allows to adjust the left margin size to fit feature names.
|
||||
#' When it is NULL, the existing \code{par('mar')} is used.
|
||||
#' @param cex (base R barplot) passed as \code{cex.names} parameter to \code{barplot}.
|
||||
#' @param plot (base R barplot) whether a barplot should be produced.
|
||||
#' If FALSE, only a data.table is returned.
|
||||
#' @param n_clusters (ggplot only) a \code{numeric} vector containing the min and the max range
|
||||
#' of the possible number of clusters of bars.
|
||||
#' @param ... other parameters passed to \code{barplot} (except horiz, border, cex.names, names.arg, and las).
|
||||
#'
|
||||
#' @details
|
||||
#' The graph represents each feature as a horizontal bar of length proportional to the importance of a feature.
|
||||
#' Features are shown ranked in a decreasing importance order.
|
||||
#' It works for importances from both \code{gblinear} and \code{gbtree} models.
|
||||
#'
|
||||
#' When \code{rel_to_first = FALSE}, the values would be plotted as they were in \code{importance_matrix}.
|
||||
#' For gbtree model, that would mean being normalized to the total of 1
|
||||
#' ("what is feature's importance contribution relative to the whole model?").
|
||||
#' For linear models, \code{rel_to_first = FALSE} would show actual values of the coefficients.
|
||||
#' Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
||||
#' "what is feature's importance contribution relative to the most important feature?"
|
||||
#'
|
||||
#' The ggplot-backend method also performs 1-D custering of the importance values,
|
||||
#' with bar colors coresponding to different clusters that have somewhat similar importance values.
|
||||
#'
|
||||
#' @return
|
||||
#' The \code{xgb.plot.importance} function creates a \code{barplot} (when \code{plot=TRUE})
|
||||
#' and silently returns a processed data.table with \code{n_top} features sorted by importance.
|
||||
#'
|
||||
#' The \code{xgb.ggplot.importance} function returns a ggplot graph which could be customized afterwards.
|
||||
#' E.g., to change the title of the graph, add \code{+ ggtitle("A GRAPH NAME")} to the result.
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link[graphics]{barplot}}.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.train)
|
||||
#'
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 3,
|
||||
#' eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
#'
|
||||
#' importance_matrix <- xgb.importance(colnames(agaricus.train$data), model = bst)
|
||||
#'
|
||||
#' #Both dataset are list with two items, a sparse matrix and labels
|
||||
#' #(labels = outcome column which will be learned).
|
||||
#' #Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
#' train <- agaricus.train
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' #train$data@@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
#' importance_matrix <- xgb.importance(train$data@@Dimnames[[2]], model = bst)
|
||||
#' xgb.plot.importance(importance_matrix)
|
||||
#' xgb.plot.importance(importance_matrix, rel_to_first = TRUE, xlab = "Relative importance")
|
||||
#'
|
||||
#' (gg <- xgb.ggplot.importance(importance_matrix, measure = "Frequency", rel_to_first = TRUE))
|
||||
#' gg + ggplot2::ylab("Frequency")
|
||||
#'
|
||||
#' @rdname xgb.plot.importance
|
||||
#' @export
|
||||
xgb.plot.importance <- function(importance_matrix = NULL, numberOfClusters = c(1:10)){
|
||||
if (!"data.table" %in% class(importance_matrix)) {
|
||||
xgb.plot.importance <- function(importance_matrix = NULL, top_n = NULL, measure = NULL,
|
||||
rel_to_first = FALSE, left_margin = 10, cex = NULL, plot = TRUE, ...) {
|
||||
check.deprecation(...)
|
||||
if (!"data.table" %in% class(importance_matrix)) {
|
||||
stop("importance_matrix: Should be a data.table.")
|
||||
}
|
||||
if (!require(ggplot2, quietly = TRUE)) {
|
||||
stop("ggplot2 package is required for plotting the importance", call. = FALSE)
|
||||
}
|
||||
if (!requireNamespace("Ckmeans.1d.dp", quietly = TRUE)) {
|
||||
stop("Ckmeans.1d.dp package is required for plotting the importance", call. = FALSE)
|
||||
}
|
||||
|
||||
# To avoid issues in clustering when co-occurences are used
|
||||
importance_matrix <- importance_matrix[, .(Gain = sum(Gain)), by = Feature]
|
||||
imp_names <- colnames(importance_matrix)
|
||||
if (is.null(measure)) {
|
||||
if (all(c("Feature", "Gain") %in% imp_names)) {
|
||||
measure <- "Gain"
|
||||
} else if (all(c("Feature", "Weight") %in% imp_names)) {
|
||||
measure <- "Weight"
|
||||
} else {
|
||||
stop("Importance matrix column names are not as expected!")
|
||||
}
|
||||
} else {
|
||||
if (!measure %in% imp_names)
|
||||
stop("Invalid `measure`")
|
||||
if (!"Feature" %in% imp_names)
|
||||
stop("Importance matrix column names are not as expected!")
|
||||
}
|
||||
|
||||
clusters <- suppressWarnings(Ckmeans.1d.dp::Ckmeans.1d.dp(importance_matrix[,Gain], numberOfClusters))
|
||||
importance_matrix[,"Cluster":=clusters$cluster %>% as.character]
|
||||
# also aggregate, just in case when the values were not yet summed up by feature
|
||||
importance_matrix <- importance_matrix[, Importance := sum(get(measure)), by = Feature]
|
||||
|
||||
# make sure it's ordered
|
||||
importance_matrix <- importance_matrix[order(-abs(Importance))]
|
||||
|
||||
if (!is.null(top_n)) {
|
||||
top_n <- min(top_n, nrow(importance_matrix))
|
||||
importance_matrix <- head(importance_matrix, top_n)
|
||||
}
|
||||
if (rel_to_first) {
|
||||
importance_matrix[, Importance := Importance/max(abs(Importance))]
|
||||
}
|
||||
if (is.null(cex)) {
|
||||
cex <- 2.5/log2(1 + nrow(importance_matrix))
|
||||
}
|
||||
|
||||
if (plot) {
|
||||
op <- par(no.readonly = TRUE)
|
||||
mar <- op$mar
|
||||
if (!is.null(left_margin))
|
||||
mar[2] <- left_margin
|
||||
par(mar = mar)
|
||||
|
||||
plot <- ggplot(importance_matrix, aes(x=reorder(Feature, Gain), y = Gain, width= 0.05), environment = environment())+ geom_bar(aes(fill=Cluster), stat="identity", position="identity") + coord_flip() + xlab("Features") + ylab("Gain") + ggtitle("Feature importance") + theme(plot.title = element_text(lineheight=.9, face="bold"), panel.grid.major.y = element_blank() )
|
||||
# reverse the order of rows to have the highest ranked at the top
|
||||
importance_matrix[nrow(importance_matrix):1,
|
||||
barplot(Importance, horiz=TRUE, border=NA, cex.names=cex,
|
||||
names.arg=Feature, las=1, ...)]
|
||||
grid(NULL, NA)
|
||||
# redraw over the grid
|
||||
importance_matrix[nrow(importance_matrix):1,
|
||||
barplot(Importance, horiz=TRUE, border=NA, add=TRUE)]
|
||||
par(op)
|
||||
}
|
||||
|
||||
return(plot)
|
||||
invisible(importance_matrix)
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(c("Feature", "Gain", "Cluster", "ggplot", "aes", "geom_bar", "coord_flip", "xlab", "ylab", "ggtitle", "theme", "element_blank", "element_text"))
|
||||
globalVariables(c("Feature", "Importance"))
|
||||
|
||||
108
R-package/R/xgb.plot.multi.trees.R
Normal file
108
R-package/R/xgb.plot.multi.trees.R
Normal file
@@ -0,0 +1,108 @@
|
||||
#' Project all trees on one tree and plot it
|
||||
#'
|
||||
#' Visualization of the ensemble of trees as a single collective unit.
|
||||
#'
|
||||
#' @param model dump generated by the \code{xgb.train} function.
|
||||
#' @param feature_names names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#' @param features_keep number of features to keep in each position of the multi trees.
|
||||
#' @param plot_width width in pixels of the graph to produce
|
||||
#' @param plot_height height in pixels of the graph to produce
|
||||
#' @param ... currently not used
|
||||
#'
|
||||
#' @return Two graphs showing the distribution of the model deepness.
|
||||
#'
|
||||
#' @details
|
||||
#'
|
||||
#' This function tries to capture the complexity of gradient boosted tree ensemble
|
||||
#' in a cohesive way.
|
||||
#'
|
||||
#' The goal is to improve the interpretability of the model generally seen as black box.
|
||||
#' The function is dedicated to boosting applied to decision trees only.
|
||||
#'
|
||||
#' The purpose is to move from an ensemble of trees to a single tree only.
|
||||
#'
|
||||
#' It takes advantage of the fact that the shape of a binary tree is only defined by
|
||||
#' its deepness (therefore in a boosting model, all trees have the same shape).
|
||||
#'
|
||||
#' Moreover, the trees tend to reuse the same features.
|
||||
#'
|
||||
#' The function will project each tree on one, and keep for each position the
|
||||
#' \code{features_keep} first features (based on Gain per feature measure).
|
||||
#'
|
||||
#' This function is inspired by this blog post:
|
||||
#' \url{https://wellecks.wordpress.com/2015/02/21/peering-into-the-black-box-visualizing-lambdamart/}
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#'
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 15,
|
||||
#' eta = 1, nthread = 2, nrounds = 30, objective = "binary:logistic",
|
||||
#' min_child_weight = 50)
|
||||
#'
|
||||
#' p <- xgb.plot.multi.trees(model = bst, feature_names = colnames(agaricus.train$data), features_keep = 3)
|
||||
#' print(p)
|
||||
#'
|
||||
#' @export
|
||||
xgb.plot.multi.trees <- function(model, feature_names = NULL, features_keep = 5, plot_width = NULL, plot_height = NULL, ...){
|
||||
check.deprecation(...)
|
||||
tree.matrix <- xgb.model.dt.tree(feature_names = feature_names, model = model)
|
||||
|
||||
# first number of the path represents the tree, then the following numbers are related to the path to follow
|
||||
# root init
|
||||
root.nodes <- tree.matrix[stri_detect_regex(ID, "\\d+-0"), ID]
|
||||
tree.matrix[ID %in% root.nodes, abs.node.position:=root.nodes]
|
||||
|
||||
precedent.nodes <- root.nodes
|
||||
|
||||
while(tree.matrix[,sum(is.na(abs.node.position))] > 0) {
|
||||
yes.row.nodes <- tree.matrix[abs.node.position %in% precedent.nodes & !is.na(Yes)]
|
||||
no.row.nodes <- tree.matrix[abs.node.position %in% precedent.nodes & !is.na(No)]
|
||||
yes.nodes.abs.pos <- yes.row.nodes[, abs.node.position] %>% paste0("_0")
|
||||
no.nodes.abs.pos <- no.row.nodes[, abs.node.position] %>% paste0("_1")
|
||||
|
||||
tree.matrix[ID %in% yes.row.nodes[, Yes], abs.node.position := yes.nodes.abs.pos]
|
||||
tree.matrix[ID %in% no.row.nodes[, No], abs.node.position := no.nodes.abs.pos]
|
||||
precedent.nodes <- c(yes.nodes.abs.pos, no.nodes.abs.pos)
|
||||
}
|
||||
|
||||
tree.matrix[!is.na(Yes),Yes:= paste0(abs.node.position, "_0")]
|
||||
tree.matrix[!is.na(No),No:= paste0(abs.node.position, "_1")]
|
||||
|
||||
|
||||
|
||||
remove.tree <- . %>% stri_replace_first_regex(pattern = "^\\d+-", replacement = "")
|
||||
|
||||
tree.matrix[,`:=`(abs.node.position=remove.tree(abs.node.position), Yes=remove.tree(Yes), No=remove.tree(No))]
|
||||
|
||||
nodes.dt <- tree.matrix[,.(Quality = sum(Quality)),by = .(abs.node.position, Feature)][,.(Text =paste0(Feature[1:min(length(Feature), features_keep)], " (", Quality[1:min(length(Quality), features_keep)], ")") %>% paste0(collapse = "\n")), by=abs.node.position]
|
||||
edges.dt <- tree.matrix[Feature != "Leaf",.(abs.node.position, Yes)] %>% list(tree.matrix[Feature != "Leaf",.(abs.node.position, No)]) %>% rbindlist() %>% setnames(c("From", "To")) %>% .[,.N,.(From, To)] %>% .[,N:=NULL]
|
||||
|
||||
nodes <- DiagrammeR::create_nodes(nodes = nodes.dt[,abs.node.position],
|
||||
label = nodes.dt[,Text],
|
||||
style = "filled",
|
||||
color = "DimGray",
|
||||
fillcolor= "Beige",
|
||||
shape = "oval",
|
||||
fontname = "Helvetica"
|
||||
)
|
||||
|
||||
edges <- DiagrammeR::create_edges(from = edges.dt[,From],
|
||||
to = edges.dt[,To],
|
||||
color = "DimGray",
|
||||
arrowsize = "1.5",
|
||||
arrowhead = "vee",
|
||||
fontname = "Helvetica",
|
||||
rel = "leading_to")
|
||||
|
||||
graph <- DiagrammeR::create_graph(nodes_df = nodes,
|
||||
edges_df = edges,
|
||||
graph_attrs = "rankdir = LR")
|
||||
|
||||
DiagrammeR::render_graph(graph, width = plot_width, height = plot_height)
|
||||
}
|
||||
|
||||
globalVariables(
|
||||
c(
|
||||
".N", "N", "From", "To", "Text", "Feature", "no.nodes.abs.pos", "ID", "Yes", "No", "Tree", "yes.nodes.abs.pos", "abs.node.position"
|
||||
)
|
||||
)
|
||||
@@ -1,27 +1,13 @@
|
||||
#' Plot a boosted tree model
|
||||
#'
|
||||
#' Read a tree model text dump.
|
||||
#' Plotting only works for boosted tree model (not linear model).
|
||||
#' Read a tree model text dump and plot the model.
|
||||
#'
|
||||
#' @importFrom data.table data.table
|
||||
#' @importFrom data.table set
|
||||
#' @importFrom data.table rbindlist
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom data.table copy
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom magrittr not
|
||||
#' @importFrom magrittr add
|
||||
#' @importFrom stringr str_extract
|
||||
#' @importFrom stringr str_split
|
||||
#' @importFrom stringr str_extract
|
||||
#' @importFrom stringr str_trim
|
||||
#' @param feature_names names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#' @param filename_dump the path to the text file storing the model. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}). Possible to provide a model directly (see \code{model} argument).
|
||||
#' @param feature_names names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.
|
||||
#' @param model generated by the \code{xgb.train} function. Avoid the creation of a dump file.
|
||||
#' @param n_first_tree limit the plot to the n first trees. If \code{NULL}, all trees of the model are plotted. Performance can be low for huge models.
|
||||
#' @param CSSstyle a \code{character} vector storing a css style to customize the appearance of nodes. Look at the \href{https://github.com/knsv/mermaid/wiki}{Mermaid wiki} for more information.
|
||||
#' @param width the width of the diagram in pixels.
|
||||
#' @param height the height of the diagram in pixels.
|
||||
#' @param plot_width the width of the diagram in pixels.
|
||||
#' @param plot_height the height of the diagram in pixels.
|
||||
#' @param ... currently not used.
|
||||
#'
|
||||
#' @return A \code{DiagrammeR} of the model.
|
||||
#'
|
||||
@@ -30,68 +16,66 @@
|
||||
#' The content of each node is organised that way:
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{feature} value ;
|
||||
#' \item \code{cover}: the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be ;
|
||||
#' \item \code{feature} value;
|
||||
#' \item \code{cover}: the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be;
|
||||
#' \item \code{gain}: metric the importance of the node in the model.
|
||||
#' }
|
||||
#'
|
||||
#' Each branch finishes with a leaf. For each leaf, only the \code{cover} is indicated.
|
||||
#' It uses \href{https://github.com/knsv/mermaid/}{Mermaid} library for that purpose.
|
||||
#' The function uses \href{http://www.graphviz.org/}{GraphViz} library for that purpose.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#'
|
||||
#' #Both dataset are list with two items, a sparse matrix and labels
|
||||
#' #(labels = outcome column which will be learned).
|
||||
#' #Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
#' train <- agaricus.train
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#'
|
||||
#' #agaricus.test$data@@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
#' xgb.plot.tree(agaricus.train$data@@Dimnames[[2]], model = bst)
|
||||
#' xgb.plot.tree(feature_names = colnames(agaricus.train$data), model = bst)
|
||||
#'
|
||||
#' @export
|
||||
#'
|
||||
xgb.plot.tree <- function(feature_names = NULL, filename_dump = NULL, model = NULL, n_first_tree = NULL, CSSstyle = NULL, width = NULL, height = NULL){
|
||||
|
||||
if (!(class(CSSstyle) %in% c("character", "NULL") && length(CSSstyle) <= 1)) {
|
||||
stop("style: Has to be a character vector of size 1.")
|
||||
}
|
||||
|
||||
if (!class(model) %in% c("xgb.Booster", "NULL")) {
|
||||
xgb.plot.tree <- function(feature_names = NULL, model = NULL, n_first_tree = NULL, plot_width = NULL, plot_height = NULL, ...){
|
||||
check.deprecation(...)
|
||||
if (class(model) != "xgb.Booster") {
|
||||
stop("model: Has to be an object of class xgb.Booster model generaged by the xgb.train function.")
|
||||
}
|
||||
|
||||
|
||||
if (!requireNamespace("DiagrammeR", quietly = TRUE)) {
|
||||
stop("DiagrammeR package is required for xgb.plot.tree", call. = FALSE)
|
||||
}
|
||||
|
||||
if(is.null(model)){
|
||||
allTrees <- xgb.model.dt.tree(feature_names = feature_names, filename_dump = filename_dump, n_first_tree = n_first_tree)
|
||||
} else {
|
||||
allTrees <- xgb.model.dt.tree(feature_names = feature_names, model = model, n_first_tree = n_first_tree)
|
||||
}
|
||||
allTrees <- xgb.model.dt.tree(feature_names = feature_names, model = model, n_first_tree = n_first_tree)
|
||||
|
||||
allTrees[Feature!="Leaf" ,yesPath:= paste(ID,"(", Feature, "<br/>Cover: ", Cover, "<br/>Gain: ", Quality, ")-->|< ", Split, "|", Yes, ">", Yes.Feature, "]", sep = "")]
|
||||
allTrees[, label:= paste0(Feature, "\nCover: ", Cover, "\nGain: ", Quality)]
|
||||
allTrees[, shape:= "rectangle"][Feature == "Leaf", shape:= "oval"]
|
||||
allTrees[, filledcolor:= "Beige"][Feature == "Leaf", filledcolor:= "Khaki"]
|
||||
|
||||
allTrees[Feature!="Leaf" ,noPath:= paste(ID,"(", Feature, ")-->|>= ", Split, "|", No, ">", No.Feature, "]", sep = "")]
|
||||
# rev is used to put the first tree on top.
|
||||
nodes <- DiagrammeR::create_nodes(nodes = allTrees[,ID] %>% rev,
|
||||
label = allTrees[,label] %>% rev,
|
||||
style = "filled",
|
||||
color = "DimGray",
|
||||
fillcolor= allTrees[,filledcolor] %>% rev,
|
||||
shape = allTrees[,shape] %>% rev,
|
||||
data = allTrees[,Feature] %>% rev,
|
||||
fontname = "Helvetica"
|
||||
)
|
||||
|
||||
edges <- DiagrammeR::create_edges(from = allTrees[Feature != "Leaf", c(ID)] %>% rep(2),
|
||||
to = allTrees[Feature != "Leaf", c(Yes, No)],
|
||||
label = allTrees[Feature != "Leaf", paste("<",Split)] %>% c(rep("",nrow(allTrees[Feature != "Leaf"]))),
|
||||
color = "DimGray",
|
||||
arrowsize = "1.5",
|
||||
arrowhead = "vee",
|
||||
fontname = "Helvetica",
|
||||
rel = "leading_to")
|
||||
|
||||
graph <- DiagrammeR::create_graph(nodes_df = nodes,
|
||||
edges_df = edges,
|
||||
graph_attrs = "rankdir = LR")
|
||||
|
||||
if(is.null(CSSstyle)){
|
||||
CSSstyle <- "classDef greenNode fill:#A2EB86, stroke:#04C4AB, stroke-width:2px;classDef redNode fill:#FFA070, stroke:#FF5E5E, stroke-width:2px"
|
||||
}
|
||||
|
||||
yes <- allTrees[Feature!="Leaf", c(Yes)] %>% paste(collapse = ",") %>% paste("class ", ., " greenNode", sep = "")
|
||||
|
||||
no <- allTrees[Feature!="Leaf", c(No)] %>% paste(collapse = ",") %>% paste("class ", ., " redNode", sep = "")
|
||||
|
||||
path <- allTrees[Feature!="Leaf", c(yesPath, noPath)] %>% .[order(.)] %>% paste(sep = "", collapse = ";") %>% paste("graph LR", .,collapse = "", sep = ";") %>% paste(CSSstyle, yes, no, sep = ";")
|
||||
DiagrammeR::mermaid(path, width, height)
|
||||
DiagrammeR::render_graph(graph, width = plot_width, height = plot_height)
|
||||
}
|
||||
|
||||
# Avoid error messages during CRAN check.
|
||||
# The reason is that these variables are never declared
|
||||
# They are mainly column names inferred by Data.table...
|
||||
globalVariables(c("Feature", "yesPath", "ID", "Cover", "Quality", "Split", "Yes", "Yes.Feature", "noPath", "No", "No.Feature", "."))
|
||||
globalVariables(c("Feature", "ID", "Cover", "Quality", "Split", "Yes", "No", ".", "shape", "filledcolor", "label"))
|
||||
|
||||
@@ -3,30 +3,25 @@
|
||||
#' Save xgboost model from xgboost or xgb.train
|
||||
#'
|
||||
#' @param model the model object.
|
||||
#' @param fname the name of the binary file.
|
||||
#' @param fname the name of the file to write.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#' xgb.save(bst, 'xgb.model')
|
||||
#' bst <- xgb.load('xgb.model')
|
||||
#' pred <- predict(bst, test$data)
|
||||
#' @export
|
||||
#'
|
||||
xgb.save <- function(model, fname) {
|
||||
if (typeof(fname) != "character") {
|
||||
stop("xgb.save: fname must be character")
|
||||
}
|
||||
if (class(model) == "xgb.Booster") {
|
||||
model <- xgb.Booster.check(model)
|
||||
.Call("XGBoosterSaveModel_R", model$handle, fname, PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
stop("xgb.save: the input must be xgb.Booster. Use xgb.DMatrix.save to save
|
||||
xgb.DMatrix object.")
|
||||
return(FALSE)
|
||||
}
|
||||
if (typeof(fname) != "character")
|
||||
stop("fname must be character")
|
||||
if (class(model) != "xgb.Booster")
|
||||
stop("the input must be xgb.Booster. Use xgb.DMatrix.save to save xgb.DMatrix object.")
|
||||
|
||||
.Call("XGBoosterSaveModel_R", model$handle, fname, PACKAGE = "xgboost")
|
||||
return(TRUE)
|
||||
}
|
||||
|
||||
@@ -10,21 +10,14 @@
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
#' eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
#' raw <- xgb.save.raw(bst)
|
||||
#' bst <- xgb.load(raw)
|
||||
#' pred <- predict(bst, test$data)
|
||||
#'
|
||||
#' @export
|
||||
#'
|
||||
xgb.save.raw <- function(model) {
|
||||
if (class(model) == "xgb.Booster"){
|
||||
model <- model$handle
|
||||
}
|
||||
if (class(model) == "xgb.Booster.handle") {
|
||||
raw <- .Call("XGBoosterModelToRaw_R", model, PACKAGE = "xgboost")
|
||||
return(raw)
|
||||
}
|
||||
stop("xgb.raw: the input must be xgb.Booster.handle. Use xgb.DMatrix.save to save
|
||||
xgb.DMatrix object.")
|
||||
model <- xgb.get.handle(model)
|
||||
.Call("XGBoosterModelToRaw_R", model, PACKAGE = "xgboost")
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#' eXtreme Gradient Boosting Training
|
||||
#'
|
||||
#' An advanced interface for training xgboost model. Look at \code{\link{xgboost}} function for a simpler interface.
|
||||
#' \code{xgb.train} is an advanced interface for training an xgboost model. The \code{xgboost} function provides a simpler interface.
|
||||
#'
|
||||
#' @param params the list of parameters.
|
||||
#' The complete list of parameters is available at \url{http://xgboost.readthedocs.io/en/latest/parameter.html}.
|
||||
#' Below is a shorter summary:
|
||||
#'
|
||||
#' 1. General Parameters
|
||||
#'
|
||||
@@ -19,7 +21,7 @@
|
||||
#' \item \code{eta} control the learning rate: scale the contribution of each tree by a factor of \code{0 < eta < 1} when it is added to the current approximation. Used to prevent overfitting by making the boosting process more conservative. Lower value for \code{eta} implies larger value for \code{nrounds}: low \code{eta} value means model more robust to overfitting but slower to compute. Default: 0.3
|
||||
#' \item \code{gamma} minimum loss reduction required to make a further partition on a leaf node of the tree. the larger, the more conservative the algorithm will be.
|
||||
#' \item \code{max_depth} maximum depth of a tree. Default: 6
|
||||
#' \item \code{min_child_weight} minimum sum of instance weight(hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will be. Default: 1
|
||||
#' \item \code{min_child_weight} minimum sum of instance weight (hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will be. Default: 1
|
||||
#' \item \code{subsample} subsample ratio of the training instance. Setting it to 0.5 means that xgboost randomly collected half of the data instances to grow trees and this will prevent overfitting. It makes computation shorter (because less data to analyse). It is advised to use this parameter with \code{eta} and increase \code{nround}. Default: 1
|
||||
#' \item \code{colsample_bytree} subsample ratio of columns when constructing each tree. Default: 1
|
||||
#' \item \code{num_parallel_tree} Experimental parameter. number of trees to grow per round. Useful to test Random Forest through Xgboost (set \code{colsample_bytree < 1}, \code{subsample < 1} and \code{round = 1}) accordingly. Default: 1
|
||||
@@ -36,74 +38,146 @@
|
||||
#' 3. Task Parameters
|
||||
#'
|
||||
#' \itemize{
|
||||
#' \item \code{objective} specify the learning task and the corresponding learning objective, and the objective options are below:
|
||||
#' \item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
||||
#' \itemize{
|
||||
#' \item \code{reg:linear} linear regression (Default).
|
||||
#' \item \code{reg:logistic} logistic regression.
|
||||
#' \item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
||||
#' \item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
||||
#' \item \code{num_class} set the number of classes. To use only with multiclass objectives.
|
||||
#' \item \code{multi:softmax} set xgboost to do multiclass classification using the softmax objective. Class is represented by a number and should be from 0 to \code{tonum_class}.
|
||||
#' \item \code{multi:softprob} same as softmax, but output a vector of ndata * nclass, which can be further reshaped to ndata, nclass matrix. The result contains predicted probabilities of each data point belonging to each class.
|
||||
#' \item \code{multi:softmax} set xgboost to do multiclass classification using the softmax objective. Class is represented by a number and should be from 0 to \code{num_class - 1}.
|
||||
#' \item \code{multi:softprob} same as softmax, but prediction outputs a vector of ndata * nclass elements, which can be further reshaped to ndata, nclass matrix. The result contains predicted probabilities of each data point belonging to each class.
|
||||
#' \item \code{rank:pairwise} set xgboost to do ranking task by minimizing the pairwise loss.
|
||||
#' }
|
||||
#' \item \code{base_score} the initial prediction score of all instances, global bias. Default: 0.5
|
||||
#' \item \code{eval_metric} evaluation metrics for validation data. Default: metric will be assigned according to objective(rmse for regression, and error for classification, mean average precision for ranking). List is provided in detail section.
|
||||
#' \item \code{eval_metric} evaluation metrics for validation data. Users can pass a self-defined function to it. Default: metric will be assigned according to objective(rmse for regression, and error for classification, mean average precision for ranking). List is provided in detail section.
|
||||
#' }
|
||||
#'
|
||||
#' @param data takes an \code{xgb.DMatrix} as the input.
|
||||
#' @param data input dataset. \code{xgb.train} takes only an \code{xgb.DMatrix} as the input.
|
||||
#' \code{xgboost}, in addition, also accepts \code{matrix}, \code{dgCMatrix}, or local data file.
|
||||
#' @param nrounds the max number of iterations
|
||||
#' @param watchlist what information should be printed when \code{verbose=1} or
|
||||
#' \code{verbose=2}. Watchlist is used to specify validation set monitoring
|
||||
#' during training. For example user can specify
|
||||
#' watchlist=list(validation1=mat1, validation2=mat2) to watch
|
||||
#' the performance of each round's model on mat1 and mat2
|
||||
#' \code{verbose=2}. Watchlist is used to specify validation set monitoring
|
||||
#' during training. For example user can specify
|
||||
#' watchlist=list(validation1=mat1, validation2=mat2) to watch
|
||||
#' the performance of each round's model on mat1 and mat2
|
||||
#'
|
||||
#' @param obj customized objective function. Returns gradient and second order
|
||||
#' gradient with given prediction and dtrain,
|
||||
#' gradient with given prediction and dtrain.
|
||||
#' @param feval custimized evaluation function. Returns
|
||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||
#' prediction and dtrain,
|
||||
#' \code{list(metric='metric-name', value='metric-value')} with given
|
||||
#' prediction and dtrain.
|
||||
#' @param verbose If 0, xgboost will stay silent. If 1, xgboost will print
|
||||
#' information of performance. If 2, xgboost will print information of both
|
||||
#' @param printEveryN Print every N progress messages when \code{verbose>0}. Default is 1 which means all messages are printed.
|
||||
#' @param early_stop_round If \code{NULL}, the early stopping function is not triggered.
|
||||
#' If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
#' keeps getting worse consecutively for \code{k} rounds.
|
||||
#' @param early.stop.round An alternative of \code{early_stop_round}.
|
||||
#' @param maximize If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
#' \code{maximize=TRUE} means the larger the evaluation score the better.
|
||||
#' information of performance. If 2, xgboost will print some additional information.
|
||||
#' Setting \code{verbose > 0} automatically engages the \code{\link{cb.evaluation.log}} and
|
||||
#' \code{\link{cb.print.evaluation}} callback functions.
|
||||
#' @param print_every_n Print each n-th iteration evaluation messages when \code{verbose>0}.
|
||||
#' Default is 1 which means all messages are printed. This parameter is passed to the
|
||||
#' \code{\link{cb.print.evaluation}} callback.
|
||||
#' @param early_stopping_rounds If \code{NULL}, the early stopping function is not triggered.
|
||||
#' If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
#' doesn't improve for \code{k} rounds.
|
||||
#' Setting this parameter engages the \code{\link{cb.early.stop}} callback.
|
||||
#' @param maximize If \code{feval} and \code{early_stopping_rounds} are set,
|
||||
#' then this parameter must be set as well.
|
||||
#' When it is \code{TRUE}, it means the larger the evaluation score the better.
|
||||
#' This parameter is passed to the \code{\link{cb.early.stop}} callback.
|
||||
#' @param save_period when it is non-NULL, model is saved to disk after every \code{save_period} rounds,
|
||||
#' 0 means save at the end. The saving is handled by the \code{\link{cb.save.model}} callback.
|
||||
#' @param save_name the name or path for periodically saved model file.
|
||||
#' @param xgb_model a previously built model to continue the trainig from.
|
||||
#' Could be either an object of class \code{xgb.Booster}, or its raw data, or the name of a
|
||||
#' file with a previously saved model.
|
||||
#' @param callbacks a list of callback functions to perform various task during boosting.
|
||||
#' See \code{\link{callbacks}}. Some of the callbacks are automatically created depending on the
|
||||
#' parameters' values. User can provide either existing or their own callback methods in order
|
||||
#' to customize the training process.
|
||||
#' @param ... other parameters to pass to \code{params}.
|
||||
#' @param label vector of response values. Should not be provided when data is
|
||||
#' a local data file name or an \code{xgb.DMatrix}.
|
||||
#' @param missing by default is set to NA, which means that NA values should be considered as 'missing'
|
||||
#' by the algorithm. Sometimes, 0 or other extreme value might be used to represent missing values.
|
||||
#' This parameter is only used when input is a dense matrix.
|
||||
#' @param weight a vector indicating the weight for each row of the input.
|
||||
#'
|
||||
#' @details
|
||||
#' This is the training function for \code{xgboost}.
|
||||
#' These are the training functions for \code{xgboost}.
|
||||
#'
|
||||
#' It supports advanced features such as \code{watchlist}, customized objective function (\code{feval}),
|
||||
#' therefore it is more flexible than \code{\link{xgboost}} function.
|
||||
#' The \code{xgb.train} interface supports advanced features such as \code{watchlist},
|
||||
#' customized objective and evaluation metric functions, therefore it is more flexible
|
||||
#' than the \code{\link{xgboost}} interface.
|
||||
#'
|
||||
#' Parallelization is automatically enabled if \code{OpenMP} is present.
|
||||
#' Number of threads can also be manually specified via \code{nthread} parameter.
|
||||
#'
|
||||
#' \code{eval_metric} parameter (not listed above) is set automatically by Xgboost but can be overriden by parameter. Below is provided the list of different metric optimized by Xgboost to help you to understand how it works inside or to use them with the \code{watchlist} parameter.
|
||||
#' The evaluation metric is chosen automatically by Xgboost (according to the objective)
|
||||
#' when the \code{eval_metric} parameter is not provided.
|
||||
#' User may set one or several \code{eval_metric} parameters.
|
||||
#' Note that when using a customized metric, only this single metric can be used.
|
||||
#' The folloiwing is the list of built-in metrics for which Xgboost provides optimized implementation:
|
||||
#' \itemize{
|
||||
#' \item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
||||
#' \item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
||||
#' \item \code{error} Binary classification error rate. It is calculated as \code{(wrong cases) / (all cases)}. For the predictions, the evaluation will regard the instances with prediction value larger than 0.5 as positive instances, and the others as negative instances.
|
||||
#' \item \code{merror} Multiclass classification error rate. It is calculated as \code{(wrong cases) / (all cases)}.
|
||||
#' \item \code{mlogloss} multiclass logloss. \url{https://www.kaggle.com/wiki/MultiClassLogLoss}
|
||||
#' \item \code{error} Binary classification error rate. It is calculated as \code{(# wrong cases) / (# all cases)}.
|
||||
#' By default, it uses the 0.5 threshold for predicted values to define negative and positive instances.
|
||||
#' Different threshold (e.g., 0.) could be specified as "error@0."
|
||||
#' \item \code{merror} Multiclass classification error rate. It is calculated as \code{(# wrong cases) / (# all cases)}.
|
||||
#' \item \code{auc} Area under the curve. \url{http://en.wikipedia.org/wiki/Receiver_operating_characteristic#'Area_under_curve} for ranking evaluation.
|
||||
#' \item \code{ndcg} Normalized Discounted Cumulative Gain (for ranking task). \url{http://en.wikipedia.org/wiki/NDCG}
|
||||
#' }
|
||||
#'
|
||||
#' Full list of parameters is available in the Wiki \url{https://github.com/dmlc/xgboost/wiki/Parameters}.
|
||||
#'
|
||||
#' This function only accepts an \code{\link{xgb.DMatrix}} object as the input.
|
||||
#' The following callbacks are automatically created when certain parameters are set:
|
||||
#' \itemize{
|
||||
#' \item \code{cb.print.evaluation} is turned on when \code{verbose > 0};
|
||||
#' and the \code{print_every_n} parameter is passed to it.
|
||||
#' \item \code{cb.evaluation.log} is on when \code{verbose > 0} and \code{watchlist} is present.
|
||||
#' \item \code{cb.early.stop}: when \code{early_stopping_rounds} is set.
|
||||
#' \item \code{cb.save.model}: when \code{save_period > 0} is set.
|
||||
#' }
|
||||
#'
|
||||
#' @return
|
||||
#' An object of class \code{xgb.Booster} with the following elements:
|
||||
#' \itemize{
|
||||
#' \item \code{handle} a handle (pointer) to the xgboost model in memory.
|
||||
#' \item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
||||
#' \item \code{niter} number of boosting iterations.
|
||||
#' \item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
||||
#' first column corresponding to iteration number and the rest corresponding to evaluation
|
||||
#' metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||
#' \item \code{call} a function call.
|
||||
#' \item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||
#' capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||
#' \item \code{callbacks} callback functions that were either automatically assigned or
|
||||
#' explicitely passed.
|
||||
#' \item \code{best_iteration} iteration number with the best evaluation metric value
|
||||
#' (only available with early stopping).
|
||||
#' \item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||
#' which could further be used in \code{predict} method
|
||||
#' (only available with early stopping).
|
||||
#' \item \code{best_score} the best evaluation metric value during early stopping.
|
||||
#' (only available with early stopping).
|
||||
#' }
|
||||
#'
|
||||
#' @seealso
|
||||
#' \code{\link{callbacks}},
|
||||
#' \code{\link{predict.xgb.Booster}},
|
||||
#' \code{\link{xgb.cv}}
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#'
|
||||
#' dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
#' dtest <- dtrain
|
||||
#' dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
#' watchlist <- list(eval = dtest, train = dtrain)
|
||||
#' param <- list(max.depth = 2, eta = 1, silent = 1)
|
||||
#'
|
||||
#' ## A simple xgb.train example:
|
||||
#' param <- list(max_depth = 2, eta = 1, silent = 1,
|
||||
#' objective = "binary:logistic", eval_metric = "auc")
|
||||
#' bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist)
|
||||
#'
|
||||
#' ## An xgb.train example where custom objective and evaluation metric are used:
|
||||
#' logregobj <- function(preds, dtrain) {
|
||||
#' labels <- getinfo(dtrain, "label")
|
||||
#' preds <- 1/(1 + exp(-preds))
|
||||
@@ -116,93 +190,145 @@
|
||||
#' err <- as.numeric(sum(labels != (preds > 0)))/length(labels)
|
||||
#' return(list(metric = "error", value = err))
|
||||
#' }
|
||||
#' bst <- xgb.train(param, dtrain, nthread = 2, nround = 2, watchlist, logregobj, evalerror)
|
||||
#' @export
|
||||
#' bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist)
|
||||
#'
|
||||
xgb.train <- function(params=list(), data, nrounds, watchlist = list(),
|
||||
obj = NULL, feval = NULL, verbose = 1, printEveryN=1L,
|
||||
early_stop_round = NULL, early.stop.round = NULL,
|
||||
maximize = NULL, ...) {
|
||||
#' ## An xgb.train example of using variable learning rates at each iteration:
|
||||
#' my_etas <- list(eta = c(0.5, 0.1))
|
||||
#' bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist,
|
||||
#' callbacks = list(cb.reset.parameters(my_etas)))
|
||||
#'
|
||||
#' ## Explicit use of the cb.evaluation.log callback allows to run
|
||||
#' ## xgb.train silently but still store the evaluation results:
|
||||
#' bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist,
|
||||
#' verbose = 0, callbacks = list(cb.evaluation.log()))
|
||||
#' print(bst$evaluation_log)
|
||||
#'
|
||||
#' ## An 'xgboost' interface example:
|
||||
#' bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label,
|
||||
#' max_depth = 2, eta = 1, nthread = 2, nrounds = 2,
|
||||
#' objective = "binary:logistic")
|
||||
#' pred <- predict(bst, agaricus.test$data)
|
||||
#'
|
||||
#' @rdname xgb.train
|
||||
#' @export
|
||||
xgb.train <- function(params = list(), data, nrounds, watchlist = list(),
|
||||
obj = NULL, feval = NULL, verbose = 1, print_every_n=1L,
|
||||
early_stopping_rounds = NULL, maximize = NULL,
|
||||
save_period = NULL, save_name = "xgboost.model",
|
||||
xgb_model = NULL, callbacks = list(), ...) {
|
||||
|
||||
check.deprecation(...)
|
||||
|
||||
params <- check.booster.params(params, ...)
|
||||
|
||||
check.custom.obj()
|
||||
check.custom.eval()
|
||||
|
||||
# data & watchlist checks
|
||||
dtrain <- data
|
||||
if (typeof(params) != "list") {
|
||||
stop("xgb.train: first argument params must be list")
|
||||
if (class(dtrain) != "xgb.DMatrix")
|
||||
stop("second argument dtrain must be xgb.DMatrix")
|
||||
if (length(watchlist) > 0) {
|
||||
if (typeof(watchlist) != "list" ||
|
||||
!all(sapply(watchlist, class) == "xgb.DMatrix"))
|
||||
stop("watchlist must be a list of xgb.DMatrix elements")
|
||||
evnames <- names(watchlist)
|
||||
if (is.null(evnames) || any(evnames == ""))
|
||||
stop("each element of the watchlist must have a name tag")
|
||||
}
|
||||
if (class(dtrain) != "xgb.DMatrix") {
|
||||
stop("xgb.train: second argument dtrain must be xgb.DMatrix")
|
||||
|
||||
# evaluation printing callback
|
||||
params <- c(params, list(silent = ifelse(verbose > 1, 0, 1)))
|
||||
print_every_n <- max( as.integer(print_every_n), 1L)
|
||||
if (!has.callbacks(callbacks, 'cb.print.evaluation') && verbose) {
|
||||
callbacks <- add.cb(callbacks, cb.print.evaluation(print_every_n))
|
||||
}
|
||||
if (verbose > 1) {
|
||||
params <- append(params, list(silent = 0))
|
||||
} else {
|
||||
params <- append(params, list(silent = 1))
|
||||
# evaluation log callback: it is automatically enabled only when verbose > 0
|
||||
evaluation_log <- list()
|
||||
if (verbose > 0 &&
|
||||
!has.callbacks(callbacks, 'cb.evaluation.log') &&
|
||||
length(watchlist) > 0) {
|
||||
callbacks <- add.cb(callbacks, cb.evaluation.log())
|
||||
}
|
||||
if (length(watchlist) != 0 && verbose == 0) {
|
||||
warning('watchlist is provided but verbose=0, no evaluation information will be printed')
|
||||
watchlist <- list()
|
||||
# Model saving callback
|
||||
if (!is.null(save_period) &&
|
||||
!has.callbacks(callbacks, 'cb.save.model')) {
|
||||
callbacks <- add.cb(callbacks, cb.save.model(save_period, save_name))
|
||||
}
|
||||
params = append(params, list(...))
|
||||
# Early stopping callback
|
||||
stop_condition <- FALSE
|
||||
if (!is.null(early_stopping_rounds) &&
|
||||
!has.callbacks(callbacks, 'cb.early.stop')) {
|
||||
callbacks <- add.cb(callbacks, cb.early.stop(early_stopping_rounds,
|
||||
maximize=maximize, verbose=verbose))
|
||||
}
|
||||
# Sort the callbacks into categories
|
||||
cb <- categorize.callbacks(callbacks)
|
||||
|
||||
|
||||
# Early stopping
|
||||
if (is.null(early_stop_round) && !is.null(early.stop.round))
|
||||
early_stop_round = early.stop.round
|
||||
if (!is.null(early_stop_round)){
|
||||
if (!is.null(feval) && is.null(maximize))
|
||||
stop('Please set maximize to note whether the model is maximizing the evaluation or not.')
|
||||
if (length(watchlist) == 0)
|
||||
stop('For early stopping you need at least one set in watchlist.')
|
||||
if (is.null(maximize) && is.null(params$eval_metric))
|
||||
stop('Please set maximize to note whether the model is maximizing the evaluation or not.')
|
||||
if (is.null(maximize))
|
||||
{
|
||||
if (params$eval_metric %in% c('rmse','logloss','error','merror','mlogloss')) {
|
||||
maximize = FALSE
|
||||
} else {
|
||||
maximize = TRUE
|
||||
}
|
||||
}
|
||||
|
||||
if (maximize) {
|
||||
bestScore = 0
|
||||
} else {
|
||||
bestScore = Inf
|
||||
}
|
||||
bestInd = 0
|
||||
earlyStopflag = FALSE
|
||||
|
||||
if (length(watchlist)>1)
|
||||
warning('Only the first data set in watchlist is used for early stopping process.')
|
||||
}
|
||||
|
||||
|
||||
handle <- xgb.Booster(params, append(watchlist, dtrain))
|
||||
# Construct a booster (either a new one or load from xgb_model)
|
||||
handle <- xgb.Booster(params, append(watchlist, dtrain), xgb_model)
|
||||
bst <- xgb.handleToBooster(handle)
|
||||
printEveryN=max( as.integer(printEveryN), 1L)
|
||||
for (i in 1:nrounds) {
|
||||
succ <- xgb.iter.update(bst$handle, dtrain, i - 1, obj)
|
||||
if (length(watchlist) != 0) {
|
||||
msg <- xgb.iter.eval(bst$handle, watchlist, i - 1, feval)
|
||||
if (0== ( (i-1) %% printEveryN))
|
||||
cat(paste(msg, "\n", sep=""))
|
||||
if (!is.null(early_stop_round))
|
||||
{
|
||||
score = strsplit(msg,':|\\s+')[[1]][3]
|
||||
score = as.numeric(score)
|
||||
if ((maximize && score>bestScore) || (!maximize && score<bestScore)) {
|
||||
bestScore = score
|
||||
bestInd = i
|
||||
} else {
|
||||
if (i-bestInd>=early_stop_round) {
|
||||
earlyStopflag = TRUE
|
||||
cat('Stopping. Best iteration:',bestInd)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# extract parameters that can affect the relationship b/w #trees and #iterations
|
||||
num_class <- max(as.numeric(NVL(params[['num_class']], 1)), 1)
|
||||
num_parallel_tree <- max(as.numeric(NVL(params[['num_parallel_tree']], 1)), 1)
|
||||
|
||||
# When the 'xgb_model' was set, find out how many boosting iterations it has
|
||||
niter_skip <- 0
|
||||
if (!is.null(xgb_model)) {
|
||||
niter_skip <- as.numeric(xgb.attr(bst, 'niter')) + 1
|
||||
if (length(niter_skip) == 0) {
|
||||
niter_skip <- xgb.ntree(bst) %/% (num_parallel_tree * num_class)
|
||||
}
|
||||
}
|
||||
bst <- xgb.Booster.check(bst)
|
||||
if (!is.null(early_stop_round)) {
|
||||
bst$bestScore = bestScore
|
||||
bst$bestInd = bestInd
|
||||
|
||||
# TODO: distributed code
|
||||
rank <- 0
|
||||
|
||||
begin_iteration <- niter_skip + 1
|
||||
end_iteration <- niter_skip + nrounds
|
||||
|
||||
# the main loop for boosting iterations
|
||||
for (iteration in begin_iteration:end_iteration) {
|
||||
|
||||
for (f in cb$pre_iter) f()
|
||||
|
||||
xgb.iter.update(bst$handle, dtrain, iteration - 1, obj)
|
||||
|
||||
bst_evaluation <- numeric(0)
|
||||
if (length(watchlist) > 0)
|
||||
bst_evaluation <- xgb.iter.eval(bst$handle, watchlist, iteration - 1, feval)
|
||||
|
||||
xgb.attr(bst$handle, 'niter') <- iteration - 1
|
||||
|
||||
for (f in cb$post_iter) f()
|
||||
|
||||
if (stop_condition) break
|
||||
}
|
||||
for (f in cb$finalize) f(finalize=TRUE)
|
||||
|
||||
bst <- xgb.Booster.check(bst, saveraw = TRUE)
|
||||
|
||||
# store the total number of boosting iterations
|
||||
bst$niter = end_iteration
|
||||
|
||||
# store the evaluation results
|
||||
if (length(evaluation_log) > 0 &&
|
||||
nrow(evaluation_log) > 0) {
|
||||
# include the previous compatible history when available
|
||||
if (class(xgb_model) == 'xgb.Booster' &&
|
||||
!is.null(xgb_model$evaluation_log) &&
|
||||
all.equal(colnames(evaluation_log),
|
||||
colnames(xgb_model$evaluation_log))) {
|
||||
evaluation_log <- rbindlist(list(xgb_model$evaluation_log, evaluation_log))
|
||||
}
|
||||
bst$evaluation_log <- evaluation_log
|
||||
}
|
||||
|
||||
bst$call <- match.call()
|
||||
bst$params <- params
|
||||
bst$callbacks <- callbacks
|
||||
|
||||
return(bst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +1,27 @@
|
||||
#' eXtreme Gradient Boosting (Tree) library
|
||||
#'
|
||||
#' A simple interface for training xgboost model. Look at \code{\link{xgb.train}} function for a more advanced interface.
|
||||
#'
|
||||
#' @param data takes \code{matrix}, \code{dgCMatrix}, local data file or
|
||||
#' \code{xgb.DMatrix}.
|
||||
#' @param label the response variable. User should not set this field,
|
||||
#' if data is local data file or \code{xgb.DMatrix}.
|
||||
#' @param params the list of parameters.
|
||||
#'
|
||||
#' Commonly used ones are:
|
||||
#' \itemize{
|
||||
#' \item \code{objective} objective function, common ones are
|
||||
#' \itemize{
|
||||
#' \item \code{reg:linear} linear regression
|
||||
#' \item \code{binary:logistic} logistic regression for classification
|
||||
#' }
|
||||
#' \item \code{eta} step size of each boosting step
|
||||
#' \item \code{max.depth} maximum depth of the tree
|
||||
#' \item \code{nthread} number of thread used in training, if not set, all threads are used
|
||||
#' }
|
||||
#'
|
||||
#' Look at \code{\link{xgb.train}} for a more complete list of parameters or \url{https://github.com/dmlc/xgboost/wiki/Parameters} for the full list.
|
||||
#'
|
||||
#' See also \code{demo/} for walkthrough example in R.
|
||||
#'
|
||||
#' @param nrounds the max number of iterations
|
||||
#' @param verbose If 0, xgboost will stay silent. If 1, xgboost will print
|
||||
#' information of performance. If 2, xgboost will print information of both
|
||||
#' performance and construction progress information
|
||||
#' @param printEveryN Print every N progress messages when \code{verbose>0}. Default is 1 which means all messages are printed.
|
||||
#' @param missing Missing is only used when input is dense matrix, pick a float
|
||||
#' value that represents missing value. Sometimes a data use 0 or other extreme value to represents missing values.
|
||||
#' @param early_stop_round If \code{NULL}, the early stopping function is not triggered.
|
||||
#' If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
#' keeps getting worse consecutively for \code{k} rounds.
|
||||
#' @param early.stop.round An alternative of \code{early_stop_round}.
|
||||
#' @param maximize If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
#' \code{maximize=TRUE} means the larger the evaluation score the better.
|
||||
#' @param ... other parameters to pass to \code{params}.
|
||||
#'
|
||||
#' @details
|
||||
#' This is the modeling function for Xgboost.
|
||||
#'
|
||||
#' Parallelization is automatically enabled if \code{OpenMP} is present.
|
||||
#'
|
||||
#' Number of threads can also be manually specified via \code{nthread} parameter.
|
||||
#'
|
||||
#' @examples
|
||||
#' data(agaricus.train, package='xgboost')
|
||||
#' data(agaricus.test, package='xgboost')
|
||||
#' train <- agaricus.train
|
||||
#' test <- agaricus.test
|
||||
#' bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
#' eta = 1, nthread = 2, nround = 2, objective = "binary:logistic")
|
||||
#' pred <- predict(bst, test$data)
|
||||
#'
|
||||
# Simple interface for training an xgboost model.
|
||||
# Its documentation is combined with xgb.train.
|
||||
#
|
||||
#' @rdname xgb.train
|
||||
#' @export
|
||||
#'
|
||||
xgboost <- function(data = NULL, label = NULL, missing = NULL, params = list(), nrounds,
|
||||
verbose = 1, printEveryN=1L, early_stop_round = NULL, early.stop.round = NULL,
|
||||
maximize = NULL, ...) {
|
||||
if (is.null(missing)) {
|
||||
dtrain <- xgb.get.DMatrix(data, label)
|
||||
} else {
|
||||
dtrain <- xgb.get.DMatrix(data, label, missing)
|
||||
}
|
||||
|
||||
params <- append(params, list(...))
|
||||
|
||||
if (verbose > 0) {
|
||||
watchlist <- list(train = dtrain)
|
||||
} else {
|
||||
watchlist <- list()
|
||||
}
|
||||
|
||||
bst <- xgb.train(params, dtrain, nrounds, watchlist, verbose = verbose, printEveryN=printEveryN,
|
||||
early_stop_round = early_stop_round,
|
||||
early.stop.round = early.stop.round)
|
||||
|
||||
return(bst)
|
||||
}
|
||||
xgboost <- function(data = NULL, label = NULL, missing = NA, weight = NULL,
|
||||
params = list(), nrounds,
|
||||
verbose = 1, print_every_n = 1L,
|
||||
early_stopping_rounds = NULL, maximize = NULL,
|
||||
save_period = 0, save_name = "xgboost.model",
|
||||
xgb_model = NULL, callbacks = list(), ...) {
|
||||
|
||||
dtrain <- xgb.get.DMatrix(data, label, missing, weight)
|
||||
|
||||
watchlist <- list()
|
||||
if (verbose > 0)
|
||||
watchlist$train = dtrain
|
||||
|
||||
bst <- xgb.train(params, dtrain, nrounds, watchlist, verbose = verbose, print_every_n=print_every_n,
|
||||
early_stopping_rounds = early_stopping_rounds, maximize = maximize,
|
||||
save_period = save_period, save_name = save_name,
|
||||
xgb_model = xgb_model, callbacks = callbacks, ...)
|
||||
return(bst)
|
||||
}
|
||||
|
||||
#' Training part from Mushroom Data Set
|
||||
#'
|
||||
@@ -135,3 +76,29 @@ NULL
|
||||
#' @format A list containing a label vector, and a dgCMatrix object with 1611
|
||||
#' rows and 126 variables
|
||||
NULL
|
||||
|
||||
# Various imports
|
||||
#' @importClassesFrom Matrix dgCMatrix dgeMatrix
|
||||
#' @importFrom Matrix cBind
|
||||
#' @importFrom Matrix colSums
|
||||
#' @importFrom Matrix sparse.model.matrix
|
||||
#' @importFrom Matrix sparseVector
|
||||
#' @importFrom data.table data.table
|
||||
#' @importFrom data.table as.data.table
|
||||
#' @importFrom data.table :=
|
||||
#' @importFrom data.table rbindlist
|
||||
#' @importFrom data.table setkey
|
||||
#' @importFrom data.table setkeyv
|
||||
#' @importFrom data.table setnames
|
||||
#' @importFrom magrittr %>%
|
||||
#' @importFrom stringi stri_detect_regex
|
||||
#' @importFrom stringi stri_match_first_regex
|
||||
#' @importFrom stringi stri_replace_first_regex
|
||||
#' @importFrom stringi stri_replace_all_regex
|
||||
#' @importFrom stringi stri_split_regex
|
||||
#' @importFrom utils object.size str tail
|
||||
#' @importFrom stats predict
|
||||
#'
|
||||
#' @import methods
|
||||
#' @useDynLib xgboost
|
||||
NULL
|
||||
|
||||
@@ -1,20 +1,73 @@
|
||||
# R package for xgboost.
|
||||
XGBoost R Package for Scalable GBM
|
||||
==================================
|
||||
|
||||
## Installation
|
||||
[](http://cran.r-project.org/web/packages/xgboost)
|
||||
[](http://cran.rstudio.com/web/packages/xgboost/index.html)
|
||||
[](http://xgboost.readthedocs.org/en/latest/R-package/index.html)
|
||||
|
||||
For up-to-date version (which is recommended), please install from github. Windows user will need to install [RTools](http://cran.r-project.org/bin/windows/Rtools/) first.
|
||||
Resources
|
||||
---------
|
||||
* [XGBoost R Package Online Documentation](http://xgboost.readthedocs.org/en/latest/R-package/index.html)
|
||||
- Check this out for detailed documents, examples and tutorials.
|
||||
|
||||
```r
|
||||
devtools::install_github('dmlc/xgboost',subdir='R-package')
|
||||
```
|
||||
Installation
|
||||
------------
|
||||
|
||||
For stable version on CRAN, please run
|
||||
We are [on CRAN](https://cran.r-project.org/web/packages/xgboost/index.html) now. For stable/pre-compiled(for Windows and OS X) version, please install from CRAN:
|
||||
|
||||
```r
|
||||
install.packages('xgboost')
|
||||
```
|
||||
|
||||
## Examples
|
||||
You can also install from our weekly updated drat repo:
|
||||
```r
|
||||
install.packages("drat", repos="https://cran.rstudio.com")
|
||||
drat:::addRepo("dmlc")
|
||||
install.packages("xgboost", repos="http://dmlc.ml/drat/", type="source")
|
||||
```
|
||||
|
||||
***Important*** Due to the usage of submodule, `install_github` is no longer support to install the
|
||||
latest version of R package.
|
||||
For up-to-date version, please install from github.
|
||||
|
||||
Windows users will need to install [RTools](http://cran.r-project.org/bin/windows/Rtools/) first. They also need to download [MinGW-W64](http://iweb.dl.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe) using x86_64 architecture during installation.
|
||||
|
||||
Run the following command to add MinGW to PATH in Windows if not already added.
|
||||
|
||||
```cmd
|
||||
PATH %PATH%;C:\Program Files\mingw-w64\x86_64-5.3.0-posix-seh-rt_v4-rev0\mingw64\bin
|
||||
```
|
||||
|
||||
To compile xgboost at the root of your storage, run the following bash script.
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/dmlc/xgboost
|
||||
cd xgboost
|
||||
git submodule init
|
||||
git submodule update
|
||||
alias make='mingw32-make'
|
||||
cd dmlc-core
|
||||
make -j4
|
||||
cd ../rabit
|
||||
make lib/librabit_empty.a -j4
|
||||
cd ..
|
||||
cp make/mingw64.mk config.mk
|
||||
make -j4
|
||||
```
|
||||
|
||||
Run the following R script to install xgboost package from the root directory.
|
||||
|
||||
```r
|
||||
install.package('devtools') # if not installed
|
||||
setwd('C:/xgboost/')
|
||||
library(devtools)
|
||||
install('R-package')
|
||||
```
|
||||
|
||||
For more detailed installation instructions, please see [here](http://xgboost.readthedocs.org/en/latest/build.html#r-package-installation).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
* Please visit [walk through example](demo).
|
||||
* See also the [example scripts](../demo/kaggle-higgs) for Kaggle Higgs Challenge, including [speedtest script](../demo/kaggle-higgs/speedtest.R) on this dataset and the one related to [Otto challenge](../demo/kaggle-otto), including a [RMarkdown documentation](../demo/kaggle-otto/understandingXGBoostModel.Rmd).
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
basic_walkthrough Basic feature walkthrough
|
||||
caret_wrapper Use xgboost to train in caret library
|
||||
custom_objective Cutomize loss function, and evaluation metric
|
||||
boost_from_prediction Boosting from existing prediction
|
||||
predict_first_ntree Predicting using first n trees
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
XGBoost R Feature Walkthrough
|
||||
====
|
||||
* [Basic walkthrough of wrappers](basic_walkthrough.R)
|
||||
* [Basic walkthrough of wrappers](basic_walkthrough.R)
|
||||
* [Train a xgboost model from caret library](caret_wrapper.R)
|
||||
* [Cutomize loss function, and evaluation metric](custom_objective.R)
|
||||
* [Boosting from existing prediction](boost_from_prediction.R)
|
||||
* [Predicting using first n trees](predict_first_ntree.R)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
require(xgboost)
|
||||
require(methods)
|
||||
|
||||
# we load in the agaricus dataset
|
||||
# In this example, we are aiming to predict whether a mushroom can be eated
|
||||
# In this example, we are aiming to predict whether a mushroom is edible
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
@@ -12,36 +13,36 @@ class(train$data)
|
||||
|
||||
#-------------Basic Training using XGBoost-----------------
|
||||
# this is the basic usage of xgboost you can put matrix in data field
|
||||
# note: we are puting in sparse matrix here, xgboost naturally handles sparse input
|
||||
# use sparse matrix when your feature is sparse(e.g. when you using one-hot encoding vector)
|
||||
print("training xgboost with sparseMatrix")
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2, eta = 1, nround = 2,
|
||||
# note: we are putting in sparse matrix here, xgboost naturally handles sparse input
|
||||
# use sparse matrix when your feature is sparse(e.g. when you are using one-hot encoding vector)
|
||||
print("Training xgboost with sparseMatrix")
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2, eta = 1, nrounds = 2,
|
||||
nthread = 2, objective = "binary:logistic")
|
||||
# alternatively, you can put in dense matrix, i.e. basic R-matrix
|
||||
print("training xgboost with Matrix")
|
||||
bst <- xgboost(data = as.matrix(train$data), label = train$label, max.depth = 2, eta = 1, nround = 2,
|
||||
print("Training xgboost with Matrix")
|
||||
bst <- xgboost(data = as.matrix(train$data), label = train$label, max_depth = 2, eta = 1, nrounds = 2,
|
||||
nthread = 2, objective = "binary:logistic")
|
||||
|
||||
# you can also put in xgb.DMatrix object, stores label, data and other meta datas needed for advanced features
|
||||
print("training xgboost with xgb.DMatrix")
|
||||
# you can also put in xgb.DMatrix object, which stores label, data and other meta datas needed for advanced features
|
||||
print("Training xgboost with xgb.DMatrix")
|
||||
dtrain <- xgb.DMatrix(data = train$data, label = train$label)
|
||||
bst <- xgboost(data = dtrain, max.depth = 2, eta = 1, nround = 2, nthread = 2,
|
||||
bst <- xgboost(data = dtrain, max_depth = 2, eta = 1, nrounds = 2, nthread = 2,
|
||||
objective = "binary:logistic")
|
||||
|
||||
# Verbose = 0,1,2
|
||||
print ('train xgboost with verbose 0, no message')
|
||||
bst <- xgboost(data = dtrain, max.depth = 2, eta = 1, nround = 2,
|
||||
print("Train xgboost with verbose 0, no message")
|
||||
bst <- xgboost(data = dtrain, max_depth = 2, eta = 1, nrounds = 2,
|
||||
nthread = 2, objective = "binary:logistic", verbose = 0)
|
||||
print ('train xgboost with verbose 1, print evaluation metric')
|
||||
bst <- xgboost(data = dtrain, max.depth = 2, eta = 1, nround = 2,
|
||||
print("Train xgboost with verbose 1, print evaluation metric")
|
||||
bst <- xgboost(data = dtrain, max_depth = 2, eta = 1, nrounds = 2,
|
||||
nthread = 2, objective = "binary:logistic", verbose = 1)
|
||||
print ('train xgboost with verbose 2, also print information about tree')
|
||||
bst <- xgboost(data = dtrain, max.depth = 2, eta = 1, nround = 2,
|
||||
print("Train xgboost with verbose 2, also print information about tree")
|
||||
bst <- xgboost(data = dtrain, max_depth = 2, eta = 1, nrounds = 2,
|
||||
nthread = 2, objective = "binary:logistic", verbose = 2)
|
||||
|
||||
# you can also specify data as file path to a LibSVM format input
|
||||
# since we do not have this file with us, the following line is just for illustration
|
||||
# bst <- xgboost(data = 'agaricus.train.svm', max.depth = 2, eta = 1, nround = 2,objective = "binary:logistic")
|
||||
# bst <- xgboost(data = 'agaricus.train.svm', max_depth = 2, eta = 1, nrounds = 2,objective = "binary:logistic")
|
||||
|
||||
#--------------------basic prediction using xgboost--------------
|
||||
# you can do prediction using the following line
|
||||
@@ -64,32 +65,32 @@ raw = xgb.save.raw(bst)
|
||||
# load binary model to R
|
||||
bst3 <- xgb.load(raw)
|
||||
pred3 <- predict(bst3, test$data)
|
||||
# pred2 should be identical to pred
|
||||
print(paste("sum(abs(pred3-pred))=", sum(abs(pred2-pred))))
|
||||
# pred3 should be identical to pred
|
||||
print(paste("sum(abs(pred3-pred))=", sum(abs(pred3-pred))))
|
||||
|
||||
#----------------Advanced features --------------
|
||||
# to use advanced features, we need to put data in xgb.DMatrix
|
||||
dtrain <- xgb.DMatrix(data = train$data, label=train$label)
|
||||
dtest <- xgb.DMatrix(data = test$data, label=test$label)
|
||||
#---------------Using watchlist----------------
|
||||
# watchlist is a list of xgb.DMatrix, each of them tagged with name
|
||||
# watchlist is a list of xgb.DMatrix, each of them is tagged with name
|
||||
watchlist <- list(train=dtrain, test=dtest)
|
||||
# to train with watchlist, use xgb.train, which contains more advanced features
|
||||
# watchlist allows us to monitor the evaluation result on all data in the list
|
||||
print ('train xgboost using xgb.train with watchlist')
|
||||
bst <- xgb.train(data=dtrain, max.depth=2, eta=1, nround=2, watchlist=watchlist,
|
||||
print("Train xgboost using xgb.train with watchlist")
|
||||
bst <- xgb.train(data=dtrain, max_depth=2, eta=1, nrounds=2, watchlist=watchlist,
|
||||
nthread = 2, objective = "binary:logistic")
|
||||
# we can change evaluation metrics, or use multiple evaluation metrics
|
||||
print ('train xgboost using xgb.train with watchlist, watch logloss and error')
|
||||
bst <- xgb.train(data=dtrain, max.depth=2, eta=1, nround=2, watchlist=watchlist,
|
||||
eval.metric = "error", eval.metric = "logloss",
|
||||
print("train xgboost using xgb.train with watchlist, watch logloss and error")
|
||||
bst <- xgb.train(data=dtrain, max_depth=2, eta=1, nrounds=2, watchlist=watchlist,
|
||||
eval_metric = "error", eval_metric = "logloss",
|
||||
nthread = 2, objective = "binary:logistic")
|
||||
|
||||
# xgb.DMatrix can also be saved using xgb.DMatrix.save
|
||||
xgb.DMatrix.save(dtrain, "dtrain.buffer")
|
||||
# to load it in, simply call xgb.DMatrix
|
||||
dtrain2 <- xgb.DMatrix("dtrain.buffer")
|
||||
bst <- xgb.train(data=dtrain2, max.depth=2, eta=1, nround=2, watchlist=watchlist,
|
||||
bst <- xgb.train(data=dtrain2, max_depth=2, eta=1, nrounds=2, watchlist=watchlist,
|
||||
nthread = 2, objective = "binary:logistic")
|
||||
# information can be extracted from xgb.DMatrix using getinfo
|
||||
label = getinfo(dtest, "label")
|
||||
@@ -98,8 +99,13 @@ err <- as.numeric(sum(as.integer(pred > 0.5) != label))/length(label)
|
||||
print(paste("test-error=", err))
|
||||
|
||||
# You can dump the tree you learned using xgb.dump into a text file
|
||||
xgb.dump(bst, "dump.raw.txt", with.stats = T)
|
||||
xgb.dump(bst, "dump.raw.txt", with_stats = T)
|
||||
|
||||
# Finally, you can check which features are the most important.
|
||||
print("Most important features (look at column Gain):")
|
||||
print(xgb.importance(feature_names = train$data@Dimnames[[2]], filename_dump = "dump.raw.txt"))
|
||||
imp_matrix <- xgb.importance(feature_names = colnames(train$data), model = bst)
|
||||
print(imp_matrix)
|
||||
|
||||
# Feature importance bar plot by gain
|
||||
print("Feature importance Plot : ")
|
||||
print(xgb.plot.importance(importance_matrix = imp_matrix))
|
||||
|
||||
@@ -11,8 +11,8 @@ watchlist <- list(eval = dtest, train = dtrain)
|
||||
#
|
||||
print('start running example to start from a initial prediction')
|
||||
# train xgboost for 1 round
|
||||
param <- list(max.depth=2,eta=1,nthread = 2, silent=1,objective='binary:logistic')
|
||||
bst <- xgb.train( param, dtrain, 1, watchlist )
|
||||
param <- list(max_depth=2, eta=1, nthread = 2, silent=1, objective='binary:logistic')
|
||||
bst <- xgb.train(param, dtrain, 1, watchlist)
|
||||
# Note: we need the margin value instead of transformed prediction in set_base_margin
|
||||
# do predict with output_margin=TRUE, will always give you margin values before logistic transformation
|
||||
ptrain <- predict(bst, dtrain, outputmargin=TRUE)
|
||||
@@ -23,4 +23,4 @@ setinfo(dtrain, "base_margin", ptrain)
|
||||
setinfo(dtest, "base_margin", ptest)
|
||||
|
||||
print('this is result of boost from initial prediction')
|
||||
bst <- xgb.train( param, dtrain, 1, watchlist )
|
||||
bst <- xgb.train(params = param, data = dtrain, nrounds = 1, watchlist = watchlist)
|
||||
|
||||
35
R-package/demo/caret_wrapper.R
Normal file
35
R-package/demo/caret_wrapper.R
Normal file
@@ -0,0 +1,35 @@
|
||||
# install development version of caret library that contains xgboost models
|
||||
devtools::install_github("topepo/caret/pkg/caret")
|
||||
require(caret)
|
||||
require(xgboost)
|
||||
require(data.table)
|
||||
require(vcd)
|
||||
require(e1071)
|
||||
|
||||
# Load Arthritis dataset in memory.
|
||||
data(Arthritis)
|
||||
# Create a copy of the dataset with data.table package (data.table is 100% compliant with R dataframe but its syntax is a lot more consistent and its performance are really good).
|
||||
df <- data.table(Arthritis, keep.rownames = F)
|
||||
|
||||
# Let's add some new categorical features to see if it helps. Of course these feature are highly correlated to the Age feature. Usually it's not a good thing in ML, but Tree algorithms (including boosted trees) are able to select the best features, even in case of highly correlated features.
|
||||
# For the first feature we create groups of age by rounding the real age. Note that we transform it to factor (categorical data) so the algorithm treat them as independant values.
|
||||
df[,AgeDiscret:= as.factor(round(Age/10,0))]
|
||||
|
||||
# Here is an even stronger simplification of the real age with an arbitrary split at 30 years old. I choose this value based on nothing. We will see later if simplifying the information based on arbitrary values is a good strategy (I am sure you already have an idea of how well it will work!).
|
||||
df[,AgeCat:= as.factor(ifelse(Age > 30, "Old", "Young"))]
|
||||
|
||||
# We remove ID as there is nothing to learn from this feature (it will just add some noise as the dataset is small).
|
||||
df[,ID:=NULL]
|
||||
|
||||
#-------------Basic Training using XGBoost in caret Library-----------------
|
||||
# Set up control parameters for caret::train
|
||||
# Here we use 10-fold cross-validation, repeating twice, and using random search for tuning hyper-parameters.
|
||||
fitControl <- trainControl(method = "cv", number = 10, repeats = 2, search = "random")
|
||||
# train a xgbTree model using caret::train
|
||||
model <- train(factor(Improved)~., data = df, method = "xgbTree", trControl = fitControl)
|
||||
|
||||
# Instead of tree for our boosters, you can also fit a linear regression or logistic regression model using xgbLinear
|
||||
# model <- train(factor(Improved)~., data = df, method = "xgbLinear", trControl = fitControl)
|
||||
|
||||
# See model results
|
||||
print(model)
|
||||
@@ -1,11 +1,13 @@
|
||||
require(xgboost)
|
||||
require(Matrix)
|
||||
require(data.table)
|
||||
if (!require(vcd)) install.packages('vcd') #Available in Cran. Used for its dataset with categorical values.
|
||||
|
||||
if (!require(vcd)) {
|
||||
install.packages('vcd') #Available in Cran. Used for its dataset with categorical values.
|
||||
require(vcd)
|
||||
}
|
||||
# According to its documentation, Xgboost works only on numbers.
|
||||
# Sometimes the dataset we have to work on have categorical data.
|
||||
# A categorical variable is one which have a fixed number of values. By exemple, if for each observation a variable called "Colour" can have only "red", "blue" or "green" as value, it is a categorical variable.
|
||||
# A categorical variable is one which have a fixed number of values. By example, if for each observation a variable called "Colour" can have only "red", "blue" or "green" as value, it is a categorical variable.
|
||||
#
|
||||
# In R, categorical variable is called Factor.
|
||||
# Type ?factor in console for more information.
|
||||
@@ -63,20 +65,18 @@ output_vector = df[,Y:=0][Improved == "Marked",Y:=1][,Y]
|
||||
|
||||
# Following is the same process as other demo
|
||||
cat("Learning...\n")
|
||||
bst <- xgboost(data = sparse_matrix, label = output_vector, max.depth = 9,
|
||||
eta = 1, nthread = 2, nround = 10,objective = "binary:logistic")
|
||||
xgb.dump(bst, 'xgb.model.dump', with.stats = T)
|
||||
bst <- xgboost(data = sparse_matrix, label = output_vector, max_depth = 9,
|
||||
eta = 1, nthread = 2, nrounds = 10, objective = "binary:logistic")
|
||||
|
||||
# sparse_matrix@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
importance <- xgb.importance(sparse_matrix@Dimnames[[2]], 'xgb.model.dump')
|
||||
importance <- xgb.importance(feature_names = colnames(sparse_matrix), model = bst)
|
||||
print(importance)
|
||||
# According to the matrix below, the most important feature in this dataset to predict if the treatment will work is the Age. The second most important feature is having received a placebo or not. The sex is third. Then we see our generated features (AgeDiscret). We can see that their contribution is very low (Gain column).
|
||||
|
||||
# Does these results make sense?
|
||||
# Does these result make sense?
|
||||
# Let's check some Chi2 between each of these features and the outcome.
|
||||
|
||||
print(chisq.test(df$Age, df$Y))
|
||||
# Pearson correlation between Age and illness disapearing is 35
|
||||
# Pearson correlation between Age and illness disappearing is 35
|
||||
|
||||
print(chisq.test(df$AgeDiscret, df$Y))
|
||||
# Our first simplification of Age gives a Pearson correlation of 8.
|
||||
@@ -84,6 +84,6 @@ print(chisq.test(df$AgeDiscret, df$Y))
|
||||
print(chisq.test(df$AgeCat, df$Y))
|
||||
# The perfectly random split I did between young and old at 30 years old have a low correlation of 2. It's a result we may expect as may be in my mind > 30 years is being old (I am 32 and starting feeling old, this may explain that), but for the illness we are studying, the age to be vulnerable is not the same. Don't let your "gut" lower the quality of your model. In "data science", there is science :-)
|
||||
|
||||
# As you can see, in general destroying information by simplying it won't improve your model. Chi2 just demonstrates that. But in more complex cases, creating a new feature based on existing one which makes link with the outcome more obvious may help the algorithm and improve the model. The case studied here is not enough complex to show that. Check Kaggle forum for some challenging datasets.
|
||||
# As you can see, in general destroying information by simplifying it won't improve your model. Chi2 just demonstrates that. But in more complex cases, creating a new feature based on existing one which makes link with the outcome more obvious may help the algorithm and improve the model. The case studied here is not enough complex to show that. Check Kaggle forum for some challenging datasets.
|
||||
# However it's almost always worse when you add some arbitrary rules.
|
||||
# Moreover, you can notice that even if we have added some not useful new features highly correlated with other features, the boosting tree algorithm have been able to choose the best one, which in this case is the Age. Linear model may not be that strong in these scenario.
|
||||
|
||||
@@ -6,7 +6,7 @@ dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
|
||||
nround <- 2
|
||||
param <- list(max.depth=2,eta=1,silent=1,nthread = 2, objective='binary:logistic')
|
||||
param <- list(max_depth=2, eta=1, silent=1, nthread=2, objective='binary:logistic')
|
||||
|
||||
cat('running cross validation\n')
|
||||
# do cross validation, this will print result out as
|
||||
@@ -19,7 +19,7 @@ cat('running cross validation, disable standard deviation display\n')
|
||||
# [iteration] metric_name:mean_value+std_value
|
||||
# std_value is standard deviation of the metric
|
||||
xgb.cv(param, dtrain, nround, nfold=5,
|
||||
metrics={'error'}, showsd = FALSE)
|
||||
metrics='error', showsd = FALSE)
|
||||
|
||||
###
|
||||
# you can also do cross validation with cutomized loss function
|
||||
@@ -40,12 +40,12 @@ evalerror <- function(preds, dtrain) {
|
||||
return(list(metric = "error", value = err))
|
||||
}
|
||||
|
||||
param <- list(max.depth=2,eta=1,silent=1)
|
||||
param <- list(max_depth=2, eta=1, silent=1,
|
||||
objective = logregobj, eval_metric = evalerror)
|
||||
# train with customized objective
|
||||
xgb.cv(param, dtrain, nround, nfold = 5,
|
||||
obj = logregobj, feval=evalerror)
|
||||
xgb.cv(params = param, data = dtrain, nrounds = nround, nfold = 5)
|
||||
|
||||
# do cross validation with prediction values for each fold
|
||||
res <- xgb.cv(param, dtrain, nround, nfold=5, prediction = TRUE)
|
||||
res$dt
|
||||
res <- xgb.cv(params = param, data = dtrain, nrounds = nround, nfold = 5, prediction = TRUE)
|
||||
res$evaluation_log
|
||||
length(res$pred)
|
||||
|
||||
@@ -8,7 +8,6 @@ dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
# note: for customized objective function, we leave objective as default
|
||||
# note: what we are getting is margin value in prediction
|
||||
# you must know what you are doing
|
||||
param <- list(max.depth=2,eta=1,nthread = 2, silent=1)
|
||||
watchlist <- list(eval = dtest, train = dtrain)
|
||||
num_round <- 2
|
||||
|
||||
@@ -33,10 +32,13 @@ evalerror <- function(preds, dtrain) {
|
||||
err <- as.numeric(sum(labels != (preds > 0)))/length(labels)
|
||||
return(list(metric = "error", value = err))
|
||||
}
|
||||
|
||||
param <- list(max_depth=2, eta=1, nthread = 2, silent=1,
|
||||
objective=logregobj, eval_metric=evalerror)
|
||||
print ('start training with user customized objective')
|
||||
# training with customized objective, we can also do step by step training
|
||||
# simply look at xgboost.py's implementation of train
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist, logregobj, evalerror)
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
||||
|
||||
#
|
||||
# there can be cases where you want additional information
|
||||
@@ -55,8 +57,9 @@ logregobjattr <- function(preds, dtrain) {
|
||||
hess <- preds * (1 - preds)
|
||||
return(list(grad = grad, hess = hess))
|
||||
}
|
||||
|
||||
param <- list(max_depth=2, eta=1, nthread = 2, silent=1,
|
||||
objective=logregobjattr, eval_metric=evalerror)
|
||||
print ('start training with user customized objective, with additional attributes in DMatrix')
|
||||
# training with customized objective, we can also do step by step training
|
||||
# simply look at xgboost.py's implementation of train
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist, logregobjattr, evalerror)
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist)
|
||||
|
||||
@@ -7,7 +7,7 @@ dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
# note: for customized objective function, we leave objective as default
|
||||
# note: what we are getting is margin value in prediction
|
||||
# you must know what you are doing
|
||||
param <- list(max.depth=2,eta=1,nthread = 2, silent=1)
|
||||
param <- list(max_depth=2, eta=1, nthread = 2, silent=1)
|
||||
watchlist <- list(eval = dtest)
|
||||
num_round <- 20
|
||||
# user define objective function, given prediction, return gradient and second order gradient
|
||||
@@ -31,9 +31,10 @@ evalerror <- function(preds, dtrain) {
|
||||
return(list(metric = "error", value = err))
|
||||
}
|
||||
print ('start training with early Stopping setting')
|
||||
# training with customized objective, we can also do step by step training
|
||||
# simply look at xgboost.py's implementation of train
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist, logregobj, evalerror, maximize = FALSE,
|
||||
early.stop.round = 3)
|
||||
bst <- xgb.cv(param, dtrain, num_round, nfold=5, obj=logregobj, feval = evalerror,
|
||||
maximize = FALSE, early.stop.round = 3)
|
||||
|
||||
bst <- xgb.train(param, dtrain, num_round, watchlist,
|
||||
objective = logregobj, eval_metric = evalerror, maximize = FALSE,
|
||||
early_stopping_round = 3)
|
||||
bst <- xgb.cv(param, dtrain, num_round, nfold = 5,
|
||||
objective = logregobj, eval_metric = evalerror,
|
||||
maximize = FALSE, early_stopping_rounds = 3)
|
||||
|
||||
@@ -5,7 +5,7 @@ data(agaricus.test, package='xgboost')
|
||||
dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
|
||||
param <- list(max.depth=2,eta=1,silent=1,objective='binary:logistic')
|
||||
param <- list(max_depth=2, eta=1, silent=1, objective='binary:logistic')
|
||||
watchlist <- list(eval = dtest, train = dtrain)
|
||||
nround = 2
|
||||
|
||||
|
||||
@@ -1,21 +1,52 @@
|
||||
require(xgboost)
|
||||
require(data.table)
|
||||
require(Matrix)
|
||||
|
||||
set.seed(1982)
|
||||
|
||||
# load in the agaricus dataset
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
dtrain <- xgb.DMatrix(data = agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- xgb.DMatrix(data = agaricus.test$data, label = agaricus.test$label)
|
||||
|
||||
param <- list(max.depth=2,eta=1,silent=1,objective='binary:logistic')
|
||||
watchlist <- list(eval = dtest, train = dtrain)
|
||||
nround = 5
|
||||
param <- list(max_depth=2, eta=1, silent=1, objective='binary:logistic')
|
||||
nround = 4
|
||||
|
||||
# training the model for two rounds
|
||||
bst = xgb.train(param, dtrain, nround, nthread = 2, watchlist)
|
||||
cat('start testing prediction from first n trees\n')
|
||||
bst = xgb.train(params = param, data = dtrain, nrounds = nround, nthread = 2)
|
||||
|
||||
# Model accuracy without new features
|
||||
accuracy.before <- sum((predict(bst, agaricus.test$data) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
|
||||
### predict using first 2 tree
|
||||
pred_with_leaf = predict(bst, dtest, ntreelimit = 2, predleaf = TRUE)
|
||||
head(pred_with_leaf)
|
||||
# by default, we predict using all the trees
|
||||
|
||||
pred_with_leaf = predict(bst, dtest, predleaf = TRUE)
|
||||
head(pred_with_leaf)
|
||||
|
||||
create.new.tree.features <- function(model, original.features){
|
||||
pred_with_leaf <- predict(model, original.features, predleaf = TRUE)
|
||||
cols <- list()
|
||||
for(i in 1:length(trees)){
|
||||
# max is not the real max but it s not important for the purpose of adding features
|
||||
leaf.id <- sort(unique(pred_with_leaf[,i]))
|
||||
cols[[i]] <- factor(x = pred_with_leaf[,i], level = leaf.id)
|
||||
}
|
||||
cBind(original.features, sparse.model.matrix( ~ . -1, as.data.frame(cols)))
|
||||
}
|
||||
|
||||
# Convert previous features to one hot encoding
|
||||
new.features.train <- create.new.tree.features(bst, agaricus.train$data)
|
||||
new.features.test <- create.new.tree.features(bst, agaricus.test$data)
|
||||
|
||||
# learning with new features
|
||||
new.dtrain <- xgb.DMatrix(data = new.features.train, label = agaricus.train$label)
|
||||
new.dtest <- xgb.DMatrix(data = new.features.test, label = agaricus.test$label)
|
||||
watchlist <- list(train = new.dtrain)
|
||||
bst <- xgb.train(params = param, data = new.dtrain, nrounds = nround, nthread = 2)
|
||||
|
||||
# Model accuracy with new features
|
||||
accuracy.after <- sum((predict(bst, new.dtest) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
|
||||
# Here the accuracy was already good and is now perfect.
|
||||
cat(paste("The accuracy was", accuracy.before, "before adding leaf features and it is now", accuracy.after, "!\n"))
|
||||
|
||||
@@ -9,3 +9,4 @@ demo(create_sparse_matrix)
|
||||
demo(predict_leaf_indices)
|
||||
demo(early_stopping)
|
||||
demo(poisson_regression)
|
||||
demo(caret_wrapper)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgboost.R
|
||||
\docType{data}
|
||||
\name{agaricus.test}
|
||||
\alias{agaricus.test}
|
||||
\title{Test part from Mushroom Data Set}
|
||||
\format{A list containing a label vector, and a dgCMatrix object with 1611
|
||||
\format{A list containing a label vector, and a dgCMatrix object with 1611
|
||||
rows and 126 variables}
|
||||
\usage{
|
||||
data(agaricus.test)
|
||||
@@ -24,8 +24,8 @@ This data set includes the following fields:
|
||||
\references{
|
||||
https://archive.ics.uci.edu/ml/datasets/Mushroom
|
||||
|
||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
School of Information and Computer Science.
|
||||
}
|
||||
\keyword{datasets}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgboost.R
|
||||
\docType{data}
|
||||
\name{agaricus.train}
|
||||
\alias{agaricus.train}
|
||||
\title{Training part from Mushroom Data Set}
|
||||
\format{A list containing a label vector, and a dgCMatrix object with 6513
|
||||
\format{A list containing a label vector, and a dgCMatrix object with 6513
|
||||
rows and 127 variables}
|
||||
\usage{
|
||||
data(agaricus.train)
|
||||
@@ -24,8 +24,8 @@ This data set includes the following fields:
|
||||
\references{
|
||||
https://archive.ics.uci.edu/ml/datasets/Mushroom
|
||||
|
||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
||||
[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
|
||||
School of Information and Computer Science.
|
||||
}
|
||||
\keyword{datasets}
|
||||
|
||||
38
R-package/man/callbacks.Rd
Normal file
38
R-package/man/callbacks.Rd
Normal file
@@ -0,0 +1,38 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{callbacks}
|
||||
\alias{callbacks}
|
||||
\title{Callback closures for booster training.}
|
||||
\description{
|
||||
These are used to perform various service tasks either during boosting iterations or at the end.
|
||||
This approach helps to modularize many of such tasks without bloating the main training methods,
|
||||
and it offers .
|
||||
}
|
||||
\details{
|
||||
By default, a callback function is run after each boosting iteration.
|
||||
An R-attribute \code{is_pre_iteration} could be set for a callback to define a pre-iteration function.
|
||||
|
||||
When a callback function has \code{finalize} parameter, its finalizer part will also be run after
|
||||
the boosting is completed.
|
||||
|
||||
WARNING: side-effects!!! Be aware that these callback functions access and modify things in
|
||||
the environment from which they are called from, which is a fairly uncommon thing to do in R.
|
||||
|
||||
To write a custom callback closure, make sure you first understand the main concepts about R envoronments.
|
||||
Check either R documentation on \code{\link[base]{environment}} or the
|
||||
\href{http://adv-r.had.co.nz/Environments.html}{Environments chapter} from the "Advanced R"
|
||||
book by Hadley Wickham. Further, the best option is to read the code of some of the existing callbacks -
|
||||
choose ones that do something similar to what you want to achieve. Also, you would need to get familiar
|
||||
with the objects available inside of the \code{xgb.train} and \code{xgb.cv} internal environments.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{cb.print.evaluation}},
|
||||
\code{\link{cb.evaluation.log}},
|
||||
\code{\link{cb.reset.parameters}},
|
||||
\code{\link{cb.early.stop}},
|
||||
\code{\link{cb.save.model}},
|
||||
\code{\link{cb.cv.predict}},
|
||||
\code{\link{xgb.train}},
|
||||
\code{\link{xgb.cv}}
|
||||
}
|
||||
|
||||
43
R-package/man/cb.cv.predict.Rd
Normal file
43
R-package/man/cb.cv.predict.Rd
Normal file
@@ -0,0 +1,43 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.cv.predict}
|
||||
\alias{cb.cv.predict}
|
||||
\title{Callback closure for returning cross-validation based predictions.}
|
||||
\usage{
|
||||
cb.cv.predict(save_models = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{save_models}{a flag for whether to save the folds' models.}
|
||||
}
|
||||
\value{
|
||||
Predictions are returned inside of the \code{pred} element, which is either a vector or a matrix,
|
||||
depending on the number of prediction outputs per data row. The order of predictions corresponds
|
||||
to the order of rows in the original dataset. Note that when a custom \code{folds} list is
|
||||
provided in \code{xgb.cv}, the predictions would only be returned properly when this list is a
|
||||
non-overlapping list of k sets of indices, as in a standard k-fold CV. The predictions would not be
|
||||
meaningful when user-profided folds have overlapping indices as in, e.g., random sampling splits.
|
||||
When some of the indices in the training dataset are not included into user-provided \code{folds},
|
||||
their prediction value would be \code{NA}.
|
||||
}
|
||||
\description{
|
||||
Callback closure for returning cross-validation based predictions.
|
||||
}
|
||||
\details{
|
||||
This callback function saves predictions for all of the test folds,
|
||||
and also allows to save the folds' models.
|
||||
|
||||
It is a "finalizer" callback and it uses early stopping information whenever it is available,
|
||||
thus it must be run after the early stopping callback if the early stopping is used.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{bst_folds},
|
||||
\code{basket},
|
||||
\code{data},
|
||||
\code{end_iteration},
|
||||
\code{num_parallel_tree},
|
||||
\code{num_class}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}}
|
||||
}
|
||||
|
||||
63
R-package/man/cb.early.stop.Rd
Normal file
63
R-package/man/cb.early.stop.Rd
Normal file
@@ -0,0 +1,63 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.early.stop}
|
||||
\alias{cb.early.stop}
|
||||
\title{Callback closure to activate the early stopping.}
|
||||
\usage{
|
||||
cb.early.stop(stopping_rounds, maximize = FALSE, metric_name = NULL,
|
||||
verbose = TRUE)
|
||||
}
|
||||
\arguments{
|
||||
\item{stopping_rounds}{The number of rounds with no improvement in
|
||||
the evaluation metric in order to stop the training.}
|
||||
|
||||
\item{maximize}{whether to maximize the evaluation metric}
|
||||
|
||||
\item{metric_name}{the name of an evaluation column to use as a criteria for early
|
||||
stopping. If not set, the last column would be used.
|
||||
Let's say the test data in \code{watchlist} was labelled as \code{dtest},
|
||||
and one wants to use the AUC in test data for early stopping regardless of where
|
||||
it is in the \code{watchlist}, then one of the following would need to be set:
|
||||
\code{metric_name='dtest-auc'} or \code{metric_name='dtest_auc'}.
|
||||
All dash '-' characters in metric names are considered equivalent to '_'.}
|
||||
|
||||
\item{verbose}{whether to print the early stopping information.}
|
||||
}
|
||||
\description{
|
||||
Callback closure to activate the early stopping.
|
||||
}
|
||||
\details{
|
||||
This callback function determines the condition for early stopping
|
||||
by setting the \code{stop_condition = TRUE} flag in its calling frame.
|
||||
|
||||
The following additional fields are assigned to the model's R object:
|
||||
\itemize{
|
||||
\item \code{best_score} the evaluation score at the best iteration
|
||||
\item \code{best_iteration} at which boosting iteration the best score has occurred (1-based index)
|
||||
\item \code{best_ntreelimit} to use with the \code{ntreelimit} parameter in \code{predict}.
|
||||
It differs from \code{best_iteration} in multiclass or random forest settings.
|
||||
}
|
||||
|
||||
The Same values are also stored as xgb-attributes:
|
||||
\itemize{
|
||||
\item \code{best_iteration} is stored as a 0-based iteration index (for interoperability of binary models)
|
||||
\item \code{best_msg} message string is also stored.
|
||||
}
|
||||
|
||||
At least one data element is required in the evaluation watchlist for early stopping to work.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{stop_condition},
|
||||
\code{bst_evaluation},
|
||||
\code{rank},
|
||||
\code{bst} (or \code{bst_folds} and \code{basket}),
|
||||
\code{iteration},
|
||||
\code{begin_iteration},
|
||||
\code{end_iteration},
|
||||
\code{num_parallel_tree}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}},
|
||||
\code{\link{xgb.attr}}
|
||||
}
|
||||
|
||||
32
R-package/man/cb.evaluation.log.Rd
Normal file
32
R-package/man/cb.evaluation.log.Rd
Normal file
@@ -0,0 +1,32 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.evaluation.log}
|
||||
\alias{cb.evaluation.log}
|
||||
\title{Callback closure for logging the evaluation history}
|
||||
\usage{
|
||||
cb.evaluation.log()
|
||||
}
|
||||
\description{
|
||||
Callback closure for logging the evaluation history
|
||||
}
|
||||
\details{
|
||||
This callback function appends the current iteration evaluation results \code{bst_evaluation}
|
||||
available in the calling parent frame to the \code{evaluation_log} list in a calling frame.
|
||||
|
||||
The finalizer callback (called with \code{finalize = TURE} in the end) converts
|
||||
the \code{evaluation_log} list into a final data.table.
|
||||
|
||||
The iteration evaluation result \code{bst_evaluation} must be a named numeric vector.
|
||||
|
||||
Note: in the column names of the final data.table, the dash '-' character is replaced with
|
||||
the underscore '_' in order to make the column names more like regular R identifiers.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{evaluation_log},
|
||||
\code{bst_evaluation},
|
||||
\code{iteration}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}}
|
||||
}
|
||||
|
||||
28
R-package/man/cb.print.evaluation.Rd
Normal file
28
R-package/man/cb.print.evaluation.Rd
Normal file
@@ -0,0 +1,28 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.print.evaluation}
|
||||
\alias{cb.print.evaluation}
|
||||
\title{Callback closure for printing the result of evaluation}
|
||||
\usage{
|
||||
cb.print.evaluation(period = 1)
|
||||
}
|
||||
\arguments{
|
||||
\item{period}{results would be printed every number of periods}
|
||||
}
|
||||
\description{
|
||||
Callback closure for printing the result of evaluation
|
||||
}
|
||||
\details{
|
||||
The callback function prints the result of evaluation at every \code{period} iterations.
|
||||
The initial and the last iteration's evaluations are always printed.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{bst_evaluation} (also \code{bst_evaluation_err} when available),
|
||||
\code{iteration},
|
||||
\code{begin_iteration},
|
||||
\code{end_iteration}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}}
|
||||
}
|
||||
|
||||
37
R-package/man/cb.reset.parameters.Rd
Normal file
37
R-package/man/cb.reset.parameters.Rd
Normal file
@@ -0,0 +1,37 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.reset.parameters}
|
||||
\alias{cb.reset.parameters}
|
||||
\title{Callback closure for restetting the booster's parameters at each iteration.}
|
||||
\usage{
|
||||
cb.reset.parameters(new_params)
|
||||
}
|
||||
\arguments{
|
||||
\item{new_params}{a list where each element corresponds to a parameter that needs to be reset.
|
||||
Each element's value must be either a vector of values of length \code{nrounds}
|
||||
to be set at each iteration,
|
||||
or a function of two parameters \code{learning_rates(iteration, nrounds)}
|
||||
which returns a new parameter value by using the current iteration number
|
||||
and the total number of boosting rounds.}
|
||||
}
|
||||
\description{
|
||||
Callback closure for restetting the booster's parameters at each iteration.
|
||||
}
|
||||
\details{
|
||||
This is a "pre-iteration" callback function used to reset booster's parameters
|
||||
at the beginning of each iteration.
|
||||
|
||||
Note that when training is resumed from some previous model, and a function is used to
|
||||
reset a parameter value, the \code{nround} argument in this function would be the
|
||||
the number of boosting rounds in the current training.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{bst} or \code{bst_folds},
|
||||
\code{iteration},
|
||||
\code{begin_iteration},
|
||||
\code{end_iteration}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}}
|
||||
}
|
||||
|
||||
34
R-package/man/cb.save.model.Rd
Normal file
34
R-package/man/cb.save.model.Rd
Normal file
@@ -0,0 +1,34 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/callbacks.R
|
||||
\name{cb.save.model}
|
||||
\alias{cb.save.model}
|
||||
\title{Callback closure for saving a model file.}
|
||||
\usage{
|
||||
cb.save.model(save_period = 0, save_name = "xgboost.model")
|
||||
}
|
||||
\arguments{
|
||||
\item{save_period}{save the model to disk after every
|
||||
\code{save_period} iterations; 0 means save the model at the end.}
|
||||
|
||||
\item{save_name}{the name or path for the saved model file.
|
||||
It can contain a \code{\link[base]{sprintf}} formatting specifier
|
||||
to include the integer iteration number in the file name.
|
||||
E.g., with \code{save_name} = 'xgboost_%04d.model',
|
||||
the file saved at iteration 50 would be named "xgboost_0050.model".}
|
||||
}
|
||||
\description{
|
||||
Callback closure for saving a model file.
|
||||
}
|
||||
\details{
|
||||
This callback function allows to save an xgb-model file, either periodically after each \code{save_period}'s or at the end.
|
||||
|
||||
Callback function expects the following values to be set in its calling frame:
|
||||
\code{bst},
|
||||
\code{iteration},
|
||||
\code{begin_iteration},
|
||||
\code{end_iteration}.
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}}
|
||||
}
|
||||
|
||||
29
R-package/man/dim.xgb.DMatrix.Rd
Normal file
29
R-package/man/dim.xgb.DMatrix.Rd
Normal file
@@ -0,0 +1,29 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{dim.xgb.DMatrix}
|
||||
\alias{dim.xgb.DMatrix}
|
||||
\title{Dimensions of xgb.DMatrix}
|
||||
\usage{
|
||||
\method{dim}{xgb.DMatrix}(x)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{Object of class \code{xgb.DMatrix}}
|
||||
}
|
||||
\description{
|
||||
Returns a vector of numbers of rows and of columns in an \code{xgb.DMatrix}.
|
||||
}
|
||||
\details{
|
||||
Note: since \code{nrow} and \code{ncol} internally use \code{dim}, they can also
|
||||
be directly used with an \code{xgb.DMatrix} object.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
|
||||
stopifnot(nrow(dtrain) == nrow(train$data))
|
||||
stopifnot(ncol(dtrain) == ncol(train$data))
|
||||
stopifnot(all(dim(dtrain) == dim(train$data)))
|
||||
|
||||
}
|
||||
|
||||
36
R-package/man/dimnames.xgb.DMatrix.Rd
Normal file
36
R-package/man/dimnames.xgb.DMatrix.Rd
Normal file
@@ -0,0 +1,36 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{dimnames.xgb.DMatrix}
|
||||
\alias{dimnames.xgb.DMatrix}
|
||||
\alias{dimnames<-.xgb.DMatrix}
|
||||
\title{Handling of column names of \code{xgb.DMatrix}}
|
||||
\usage{
|
||||
\method{dimnames}{xgb.DMatrix}(x)
|
||||
|
||||
\method{dimnames}{xgb.DMatrix}(x) <- value
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{object of class \code{xgb.DMatrix}}
|
||||
|
||||
\item{value}{a list of two elements: the first one is ignored
|
||||
and the second one is column names}
|
||||
}
|
||||
\description{
|
||||
Only column names are supported for \code{xgb.DMatrix}, thus setting of
|
||||
row names would have no effect and returnten row names would be NULL.
|
||||
}
|
||||
\details{
|
||||
Generic \code{dimnames} methods are used by \code{colnames}.
|
||||
Since row names are irrelevant, it is recommended to use \code{colnames} directly.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
dimnames(dtrain)
|
||||
colnames(dtrain)
|
||||
colnames(dtrain) <- make.names(1:ncol(train$data))
|
||||
print(dtrain, verbose=TRUE)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/getinfo.xgb.DMatrix.R
|
||||
\docType{methods}
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{getinfo}
|
||||
\alias{getinfo}
|
||||
\alias{getinfo,xgb.DMatrix-method}
|
||||
\alias{getinfo.xgb.DMatrix}
|
||||
\title{Get information of an xgb.DMatrix object}
|
||||
\usage{
|
||||
getinfo(object, ...)
|
||||
|
||||
\S4method{getinfo}{xgb.DMatrix}(object, name)
|
||||
\method{getinfo}{xgb.DMatrix}(object, name, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class \code{xgb.DMatrix}}
|
||||
|
||||
\item{...}{other parameters}
|
||||
|
||||
\item{name}{the name of the field to get}
|
||||
\item{name}{the name of the information field to get (see details)}
|
||||
}
|
||||
\description{
|
||||
Get information of an xgb.DMatrix object
|
||||
}
|
||||
\details{
|
||||
The information can be one of the following:
|
||||
The \code{name} field can be one of the following:
|
||||
|
||||
\itemize{
|
||||
\item \code{label}: label Xgboost learn from ;
|
||||
@@ -34,8 +33,10 @@ The information can be one of the following:
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
|
||||
labels <- getinfo(dtrain, 'label')
|
||||
setinfo(dtrain, 'label', 1-labels)
|
||||
|
||||
labels2 <- getinfo(dtrain, 'label')
|
||||
stopifnot(all(labels2 == 1-labels))
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/nrow.xgb.DMatrix.R
|
||||
\docType{methods}
|
||||
\name{nrow,xgb.DMatrix-method}
|
||||
\alias{nrow,xgb.DMatrix-method}
|
||||
\title{Number of xgb.DMatrix rows}
|
||||
\usage{
|
||||
\S4method{nrow}{xgb.DMatrix}(x)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{Object of class \code{xgb.DMatrix}}
|
||||
}
|
||||
\description{
|
||||
\code{nrow} return the number of rows present in the \code{xgb.DMatrix}.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
stopifnot(nrow(dtrain) == nrow(train$data))
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/predict.xgb.Booster.R
|
||||
\docType{methods}
|
||||
\name{predict,xgb.Booster-method}
|
||||
\alias{predict,xgb.Booster-method}
|
||||
\title{Predict method for eXtreme Gradient Boosting model}
|
||||
\usage{
|
||||
\S4method{predict}{xgb.Booster}(object, newdata, missing = NULL,
|
||||
outputmargin = FALSE, ntreelimit = NULL, predleaf = FALSE)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class "xgb.Boost"}
|
||||
|
||||
\item{newdata}{takes \code{matrix}, \code{dgCMatrix}, local data file or
|
||||
\code{xgb.DMatrix}.}
|
||||
|
||||
\item{missing}{Missing is only used when input is dense matrix, pick a float
|
||||
value that represents missing value. Sometime a data use 0 or other extreme value to represents missing values.}
|
||||
|
||||
\item{outputmargin}{whether the prediction should be shown in the original
|
||||
value of sum of functions, when outputmargin=TRUE, the prediction is
|
||||
untransformed margin value. In logistic regression, outputmargin=T will
|
||||
output value before logistic transformation.}
|
||||
|
||||
\item{ntreelimit}{limit number of trees used in prediction, this parameter is
|
||||
only valid for gbtree, but not for gblinear. set it to be value bigger
|
||||
than 0. It will use all trees by default.}
|
||||
|
||||
\item{predleaf}{whether predict leaf index instead. If set to TRUE, the output will be a matrix object.}
|
||||
}
|
||||
\description{
|
||||
Predicted values based on xgboost model object.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
pred <- predict(bst, test$data)
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/predict.xgb.Booster.handle.R
|
||||
\docType{methods}
|
||||
\name{predict,xgb.Booster.handle-method}
|
||||
\alias{predict,xgb.Booster.handle-method}
|
||||
\title{Predict method for eXtreme Gradient Boosting model handle}
|
||||
\usage{
|
||||
\S4method{predict}{xgb.Booster.handle}(object, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class "xgb.Boost.handle"}
|
||||
|
||||
\item{...}{Parameters pass to \code{predict.xgb.Booster}}
|
||||
}
|
||||
\description{
|
||||
Predicted values based on xgb.Booster.handle object.
|
||||
}
|
||||
|
||||
129
R-package/man/predict.xgb.Booster.Rd
Normal file
129
R-package/man/predict.xgb.Booster.Rd
Normal file
@@ -0,0 +1,129 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.Booster.R
|
||||
\name{predict.xgb.Booster}
|
||||
\alias{predict.xgb.Booster}
|
||||
\alias{predict.xgb.Booster.handle}
|
||||
\title{Predict method for eXtreme Gradient Boosting model}
|
||||
\usage{
|
||||
\method{predict}{xgb.Booster}(object, newdata, missing = NA,
|
||||
outputmargin = FALSE, ntreelimit = NULL, predleaf = FALSE,
|
||||
reshape = FALSE, ...)
|
||||
|
||||
\method{predict}{xgb.Booster.handle}(object, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}}
|
||||
|
||||
\item{newdata}{takes \code{matrix}, \code{dgCMatrix}, local data file or \code{xgb.DMatrix}.}
|
||||
|
||||
\item{missing}{Missing is only used when input is dense matrix. Pick a float value that represents
|
||||
missing values in data (e.g., sometimes 0 or some other extreme value is used).}
|
||||
|
||||
\item{outputmargin}{whether the prediction should be returned in the for of original untransformed
|
||||
sum of predictions from boosting iterations' results. E.g., setting \code{outputmargin=TRUE} for
|
||||
logistic regression would result in predictions for log-odds instead of probabilities.}
|
||||
|
||||
\item{ntreelimit}{limit the number of model's trees or boosting iterations used in prediction (see Details).
|
||||
It will use all the trees by default (\code{NULL} value).}
|
||||
|
||||
\item{predleaf}{whether predict leaf index instead.}
|
||||
|
||||
\item{reshape}{whether to reshape the vector of predictions to a matrix form when there are several
|
||||
prediction outputs per case. This option has no effect when \code{predleaf = TRUE}.}
|
||||
|
||||
\item{...}{Parameters passed to \code{predict.xgb.Booster}}
|
||||
}
|
||||
\value{
|
||||
For regression or binary classification, it returns a vector of length \code{nrows(newdata)}.
|
||||
For multiclass classification, either a \code{num_class * nrows(newdata)} vector or
|
||||
a \code{(nrows(newdata), num_class)} dimension matrix is returned, depending on
|
||||
the \code{reshape} value.
|
||||
|
||||
When \code{predleaf = TRUE}, the output is a matrix object with the
|
||||
number of columns corresponding to the number of trees.
|
||||
}
|
||||
\description{
|
||||
Predicted values based on either xgboost model or model handle object.
|
||||
}
|
||||
\details{
|
||||
Note that \code{ntreelimit} is not necesserily equal to the number of boosting iterations
|
||||
and it is not necesserily equal to the number of trees in a model.
|
||||
E.g., in a random forest-like model, \code{ntreelimit} would limit the number of trees.
|
||||
But for multiclass classification, there are multiple trees per iteration,
|
||||
but \code{ntreelimit} limits the number of boosting iterations.
|
||||
|
||||
Also note that \code{ntreelimit} would currently do nothing for predictions from gblinear,
|
||||
since gblinear doesn't keep its boosting history.
|
||||
|
||||
One possible practical applications of the \code{predleaf} option is to use the model
|
||||
as a generator of new features which capture non-linearity and interactions,
|
||||
e.g., as implemented in \code{\link{xgb.create.features}}.
|
||||
}
|
||||
\examples{
|
||||
## binary classification:
|
||||
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
# use all trees by default
|
||||
pred <- predict(bst, test$data)
|
||||
# use only the 1st tree
|
||||
pred <- predict(bst, test$data, ntreelimit = 1)
|
||||
|
||||
|
||||
## multiclass classification in iris dataset:
|
||||
|
||||
lb <- as.numeric(iris$Species) - 1
|
||||
num_class <- 3
|
||||
set.seed(11)
|
||||
bst <- xgboost(data = as.matrix(iris[, -5]), label = lb,
|
||||
max_depth = 4, eta = 0.5, nthread = 2, nrounds = 10, subsample = 0.5,
|
||||
objective = "multi:softprob", num_class = num_class)
|
||||
# predict for softmax returns num_class probability numbers per case:
|
||||
pred <- predict(bst, as.matrix(iris[, -5]))
|
||||
str(pred)
|
||||
# reshape it to a num_class-columns matrix
|
||||
pred <- matrix(pred, ncol=num_class, byrow=TRUE)
|
||||
# convert the probabilities to softmax labels
|
||||
pred_labels <- max.col(pred) - 1
|
||||
# the following should result in the same error as seen in the last iteration
|
||||
sum(pred_labels != lb)/length(lb)
|
||||
|
||||
# compare that to the predictions from softmax:
|
||||
set.seed(11)
|
||||
bst <- xgboost(data = as.matrix(iris[, -5]), label = lb,
|
||||
max_depth = 4, eta = 0.5, nthread = 2, nrounds = 10, subsample = 0.5,
|
||||
objective = "multi:softmax", num_class = num_class)
|
||||
pred <- predict(bst, as.matrix(iris[, -5]))
|
||||
str(pred)
|
||||
all.equal(pred, pred_labels)
|
||||
# prediction from using only 5 iterations should result
|
||||
# in the same error as seen in iteration 5:
|
||||
pred5 <- predict(bst, as.matrix(iris[, -5]), ntreelimit=5)
|
||||
sum(pred5 != lb)/length(lb)
|
||||
|
||||
|
||||
## random forest-like model of 25 trees for binary classification:
|
||||
|
||||
set.seed(11)
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 5,
|
||||
nthread = 2, nrounds = 1, objective = "binary:logistic",
|
||||
num_parallel_tree = 25, subsample = 0.6, colsample_bytree = 0.1)
|
||||
# Inspect the prediction error vs number of trees:
|
||||
lb <- test$label
|
||||
dtest <- xgb.DMatrix(test$data, label=lb)
|
||||
err <- sapply(1:25, function(n) {
|
||||
pred <- predict(bst, dtest, ntreelimit=n)
|
||||
sum((pred > 0.5) != lb)/length(lb)
|
||||
})
|
||||
plot(err, type='l', ylim=c(0,0.1), xlab='#trees')
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{xgb.train}}.
|
||||
}
|
||||
|
||||
30
R-package/man/print.xgb.Booster.Rd
Normal file
30
R-package/man/print.xgb.Booster.Rd
Normal file
@@ -0,0 +1,30 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.Booster.R
|
||||
\name{print.xgb.Booster}
|
||||
\alias{print.xgb.Booster}
|
||||
\title{Print xgb.Booster}
|
||||
\usage{
|
||||
\method{print}{xgb.Booster}(x, verbose = FALSE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{an xgb.Booster object}
|
||||
|
||||
\item{verbose}{whether to print detailed data (e.g., attribute values)}
|
||||
|
||||
\item{...}{not currently used}
|
||||
}
|
||||
\description{
|
||||
Print information about xgb.Booster.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
attr(bst, 'myattr') <- 'memo'
|
||||
|
||||
print(bst)
|
||||
print(bst, verbose=TRUE)
|
||||
|
||||
}
|
||||
|
||||
29
R-package/man/print.xgb.DMatrix.Rd
Normal file
29
R-package/man/print.xgb.DMatrix.Rd
Normal file
@@ -0,0 +1,29 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{print.xgb.DMatrix}
|
||||
\alias{print.xgb.DMatrix}
|
||||
\title{Print xgb.DMatrix}
|
||||
\usage{
|
||||
\method{print}{xgb.DMatrix}(x, verbose = FALSE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{an xgb.DMatrix object}
|
||||
|
||||
\item{verbose}{whether to print colnames (when present)}
|
||||
|
||||
\item{...}{not currently used}
|
||||
}
|
||||
\description{
|
||||
Print information about xgb.DMatrix.
|
||||
Currently it displays dimensions and presence of info-fields and colnames.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
|
||||
dtrain
|
||||
print(dtrain, verbose=TRUE)
|
||||
|
||||
}
|
||||
|
||||
32
R-package/man/print.xgb.cv.Rd
Normal file
32
R-package/man/print.xgb.cv.Rd
Normal file
@@ -0,0 +1,32 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.cv.R
|
||||
\name{print.xgb.cv.synchronous}
|
||||
\alias{print.xgb.cv.synchronous}
|
||||
\title{Print xgb.cv result}
|
||||
\usage{
|
||||
\method{print}{xgb.cv.synchronous}(x, verbose = FALSE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{x}{an \code{xgb.cv.synchronous} object}
|
||||
|
||||
\item{verbose}{whether to print detailed data}
|
||||
|
||||
\item{...}{passed to \code{data.table.print}}
|
||||
}
|
||||
\description{
|
||||
Prints formatted results of \code{xgb.cv}.
|
||||
}
|
||||
\details{
|
||||
When not verbose, it would only print the evaluation results,
|
||||
including the best iteration (when available).
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
cv <- xgb.cv(data = train$data, label = train$label, nfold = 5, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
print(cv)
|
||||
print(cv, verbose=TRUE)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/setinfo.xgb.DMatrix.R
|
||||
\docType{methods}
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{setinfo}
|
||||
\alias{setinfo}
|
||||
\alias{setinfo,xgb.DMatrix-method}
|
||||
\alias{setinfo.xgb.DMatrix}
|
||||
\title{Set information of an xgb.DMatrix object}
|
||||
\usage{
|
||||
setinfo(object, ...)
|
||||
|
||||
\S4method{setinfo}{xgb.DMatrix}(object, name, info)
|
||||
\method{setinfo}{xgb.DMatrix}(object, name, info, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class "xgb.DMatrix"}
|
||||
@@ -23,7 +22,7 @@ setinfo(object, ...)
|
||||
Set information of an xgb.DMatrix object
|
||||
}
|
||||
\details{
|
||||
It can be one of the following:
|
||||
The \code{name} field can be one of the following:
|
||||
|
||||
\itemize{
|
||||
\item \code{label}: label Xgboost learn from ;
|
||||
@@ -36,9 +35,10 @@ It can be one of the following:
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
|
||||
labels <- getinfo(dtrain, 'label')
|
||||
setinfo(dtrain, 'label', 1-labels)
|
||||
labels2 <- getinfo(dtrain, 'label')
|
||||
stopifnot(all(labels2 == 1-labels))
|
||||
stopifnot(all.equal(labels2, 1-labels))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/slice.xgb.DMatrix.R
|
||||
\docType{methods}
|
||||
\name{slice}
|
||||
\alias{slice}
|
||||
\alias{slice,xgb.DMatrix-method}
|
||||
\title{Get a new DMatrix containing the specified rows of
|
||||
orginal xgb.DMatrix object}
|
||||
\usage{
|
||||
slice(object, ...)
|
||||
|
||||
\S4method{slice}{xgb.DMatrix}(object, idxset, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class "xgb.DMatrix"}
|
||||
|
||||
\item{...}{other parameters}
|
||||
|
||||
\item{idxset}{a integer vector of indices of rows needed}
|
||||
}
|
||||
\description{
|
||||
Get a new DMatrix containing the specified rows of
|
||||
orginal xgb.DMatrix object
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
dsub <- slice(dtrain, 1:3)
|
||||
}
|
||||
|
||||
41
R-package/man/slice.xgb.DMatrix.Rd
Normal file
41
R-package/man/slice.xgb.DMatrix.Rd
Normal file
@@ -0,0 +1,41 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{slice}
|
||||
\alias{[.xgb.DMatrix}
|
||||
\alias{slice}
|
||||
\alias{slice.xgb.DMatrix}
|
||||
\title{Get a new DMatrix containing the specified rows of
|
||||
orginal xgb.DMatrix object}
|
||||
\usage{
|
||||
slice(object, ...)
|
||||
|
||||
\method{slice}{xgb.DMatrix}(object, idxset, ...)
|
||||
|
||||
\method{[}{xgb.DMatrix}(object, idxset, colset = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class "xgb.DMatrix"}
|
||||
|
||||
\item{...}{other parameters (currently not used)}
|
||||
|
||||
\item{idxset}{a integer vector of indices of rows needed}
|
||||
|
||||
\item{colset}{currently not used (columns subsetting is not available)}
|
||||
}
|
||||
\description{
|
||||
Get a new DMatrix containing the specified rows of
|
||||
orginal xgb.DMatrix object
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
dtrain <- xgb.DMatrix(train$data, label=train$label)
|
||||
|
||||
dsub <- slice(dtrain, 1:42)
|
||||
labels1 <- getinfo(dsub, 'label')
|
||||
dsub <- dtrain[1:42, ]
|
||||
labels2 <- getinfo(dsub, 'label')
|
||||
all.equal(labels1, labels2)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.R
|
||||
\name{xgb.DMatrix}
|
||||
\alias{xgb.DMatrix}
|
||||
\title{Contruct xgb.DMatrix object}
|
||||
\usage{
|
||||
xgb.DMatrix(data, info = list(), missing = 0, ...)
|
||||
xgb.DMatrix(data, info = list(), missing = NA, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{data}{a \code{matrix} object, a \code{dgCMatrix} object or a character
|
||||
indicating the data file.}
|
||||
\item{data}{a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename}
|
||||
|
||||
\item{info}{a list of information of the xgb.DMatrix object}
|
||||
|
||||
@@ -18,7 +17,8 @@ value that represents missing value. Sometime a data use 0 or other extreme valu
|
||||
\item{...}{other information to pass to \code{info}.}
|
||||
}
|
||||
\description{
|
||||
Contruct xgb.DMatrix object from dense matrix, sparse matrix or local file.
|
||||
Contruct xgb.DMatrix object from dense matrix, sparse matrix
|
||||
or local file (that was created previously by saving an \code{xgb.DMatrix}).
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.DMatrix.save.R
|
||||
\name{xgb.DMatrix.save}
|
||||
\alias{xgb.DMatrix.save}
|
||||
\title{Save xgb.DMatrix object to binary file}
|
||||
\usage{
|
||||
xgb.DMatrix.save(DMatrix, fname)
|
||||
xgb.DMatrix.save(dmatrix, fname)
|
||||
}
|
||||
\arguments{
|
||||
\item{DMatrix}{the DMatrix object}
|
||||
\item{dmatrix}{the \code{xgb.DMatrix} object}
|
||||
|
||||
\item{fname}{the name of the binary file.}
|
||||
\item{fname}{the name of the file to write.}
|
||||
}
|
||||
\description{
|
||||
Save xgb.DMatrix object to binary file
|
||||
|
||||
86
R-package/man/xgb.attr.Rd
Normal file
86
R-package/man/xgb.attr.Rd
Normal file
@@ -0,0 +1,86 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.Booster.R
|
||||
\name{xgb.attr}
|
||||
\alias{xgb.attr}
|
||||
\alias{xgb.attr<-}
|
||||
\alias{xgb.attributes}
|
||||
\alias{xgb.attributes<-}
|
||||
\title{Accessors for serializable attributes of a model.}
|
||||
\usage{
|
||||
xgb.attr(object, name)
|
||||
|
||||
xgb.attr(object, name) <- value
|
||||
|
||||
xgb.attributes(object)
|
||||
|
||||
xgb.attributes(object) <- value
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}.}
|
||||
|
||||
\item{name}{a non-empty character string specifying which attribute is to be accessed.}
|
||||
|
||||
\item{value}{a value of an attribute for \code{xgb.attr<-}; for \code{xgb.attributes<-}
|
||||
it's a list (or an object coercible to a list) with the names of attributes to set
|
||||
and the elements corresponding to attribute values.
|
||||
Non-character values are converted to character.
|
||||
When attribute value is not a scalar, only the first index is used.
|
||||
Use \code{NULL} to remove an attribute.}
|
||||
}
|
||||
\value{
|
||||
\code{xgb.attr} returns either a string value of an attribute
|
||||
or \code{NULL} if an attribute wasn't stored in a model.
|
||||
|
||||
\code{xgb.attributes} returns a list of all attribute stored in a model
|
||||
or \code{NULL} if a model has no stored attributes.
|
||||
}
|
||||
\description{
|
||||
These methods allow to manipulate the key-value attribute strings of an xgboost model.
|
||||
}
|
||||
\details{
|
||||
The primary purpose of xgboost model attributes is to store some meta-data about the model.
|
||||
Note that they are a separate concept from the object attributes in R.
|
||||
Specifically, they refer to key-value strings that can be attached to an xgboost model,
|
||||
stored together with the model's binary representation, and accessed later
|
||||
(from R or any other interface).
|
||||
In contrast, any R-attribute assigned to an R-object of \code{xgb.Booster} class
|
||||
would not be saved by \code{xgb.save} because an xgboost model is an external memory object
|
||||
and its serialization is handled extrnally.
|
||||
Also, setting an attribute that has the same name as one of xgboost's parameters wouldn't
|
||||
change the value of that parameter for a model.
|
||||
Use \code{\link{xgb.parameters<-}} to set or change model parameters.
|
||||
|
||||
The attribute setters would usually work more efficiently for \code{xgb.Booster.handle}
|
||||
than for \code{xgb.Booster}, since only just a handle (pointer) would need to be copied.
|
||||
That would only matter if attributes need to be set many times.
|
||||
Note, however, that when feeding a handle of an \code{xgb.Booster} object to the attribute setters,
|
||||
the raw model cache of an \code{xgb.Booster} object would not be automatically updated,
|
||||
and it would be user's responsibility to call \code{xgb.save.raw} to update it.
|
||||
|
||||
The \code{xgb.attributes<-} setter either updates the existing or adds one or several attributes,
|
||||
but it doesn't delete the other existing attributes.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
|
||||
xgb.attr(bst, "my_attribute") <- "my attribute value"
|
||||
print(xgb.attr(bst, "my_attribute"))
|
||||
xgb.attributes(bst) <- list(a = 123, b = "abc")
|
||||
|
||||
xgb.save(bst, 'xgb.model')
|
||||
bst1 <- xgb.load('xgb.model')
|
||||
print(xgb.attr(bst1, "my_attribute"))
|
||||
print(xgb.attributes(bst1))
|
||||
|
||||
# deletion:
|
||||
xgb.attr(bst1, "my_attribute") <- NULL
|
||||
print(xgb.attributes(bst1))
|
||||
xgb.attributes(bst1) <- list(a = NULL, b = NULL)
|
||||
print(xgb.attributes(bst1))
|
||||
|
||||
}
|
||||
|
||||
90
R-package/man/xgb.create.features.Rd
Normal file
90
R-package/man/xgb.create.features.Rd
Normal file
@@ -0,0 +1,90 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.create.features.R
|
||||
\name{xgb.create.features}
|
||||
\alias{xgb.create.features}
|
||||
\title{Create new features from a previously learned model}
|
||||
\usage{
|
||||
xgb.create.features(model, data, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{model}{decision tree boosting model learned on the original data}
|
||||
|
||||
\item{data}{original data (usually provided as a \code{dgCMatrix} matrix)}
|
||||
|
||||
\item{...}{currently not used}
|
||||
}
|
||||
\value{
|
||||
\code{dgCMatrix} matrix including both the original data and the new features.
|
||||
}
|
||||
\description{
|
||||
May improve the learning by adding new features to the training data based on the decision trees from a previously learned model.
|
||||
}
|
||||
\details{
|
||||
This is the function inspired from the paragraph 3.1 of the paper:
|
||||
|
||||
\strong{Practical Lessons from Predicting Clicks on Ads at Facebook}
|
||||
|
||||
\emph{(Xinran He, Junfeng Pan, Ou Jin, Tianbing Xu, Bo Liu, Tao Xu, Yan, xin Shi, Antoine Atallah, Ralf Herbrich, Stuart Bowers,
|
||||
Joaquin Quinonero Candela)}
|
||||
|
||||
International Workshop on Data Mining for Online Advertising (ADKDD) - August 24, 2014
|
||||
|
||||
\url{https://research.facebook.com/publications/758569837499391/practical-lessons-from-predicting-clicks-on-ads-at-facebook/}.
|
||||
|
||||
Extract explaining the method:
|
||||
|
||||
"We found that boosted decision trees are a powerful and very
|
||||
convenient way to implement non-linear and tuple transformations
|
||||
of the kind we just described. We treat each individual
|
||||
tree as a categorical feature that takes as value the
|
||||
index of the leaf an instance ends up falling in. We use
|
||||
1-of-K coding of this type of features.
|
||||
|
||||
For example, consider the boosted tree model in Figure 1 with 2 subtrees,
|
||||
where the first subtree has 3 leafs and the second 2 leafs. If an
|
||||
instance ends up in leaf 2 in the first subtree and leaf 1 in
|
||||
second subtree, the overall input to the linear classifier will
|
||||
be the binary vector \code{[0, 1, 0, 1, 0]}, where the first 3 entries
|
||||
correspond to the leaves of the first subtree and last 2 to
|
||||
those of the second subtree.
|
||||
|
||||
[...]
|
||||
|
||||
We can understand boosted decision tree
|
||||
based transformation as a supervised feature encoding that
|
||||
converts a real-valued vector into a compact binary-valued
|
||||
vector. A traversal from root node to a leaf node represents
|
||||
a rule on certain features."
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
dtrain <- xgb.DMatrix(data = agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- xgb.DMatrix(data = agaricus.test$data, label = agaricus.test$label)
|
||||
|
||||
param <- list(max_depth=2, eta=1, silent=1, objective='binary:logistic')
|
||||
nround = 4
|
||||
|
||||
bst = xgb.train(params = param, data = dtrain, nrounds = nround, nthread = 2)
|
||||
|
||||
# Model accuracy without new features
|
||||
accuracy.before <- sum((predict(bst, agaricus.test$data) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
|
||||
# Convert previous features to one hot encoding
|
||||
new.features.train <- xgb.create.features(model = bst, agaricus.train$data)
|
||||
new.features.test <- xgb.create.features(model = bst, agaricus.test$data)
|
||||
|
||||
# learning with new features
|
||||
new.dtrain <- xgb.DMatrix(data = new.features.train, label = agaricus.train$label)
|
||||
new.dtest <- xgb.DMatrix(data = new.features.test, label = agaricus.test$label)
|
||||
watchlist <- list(train = new.dtrain)
|
||||
bst <- xgb.train(params = param, data = new.dtrain, nrounds = nround, nthread = 2)
|
||||
|
||||
# Model accuracy with new features
|
||||
accuracy.after <- sum((predict(bst, new.dtest) >= 0.5) == agaricus.test$label) / length(agaricus.test$label)
|
||||
|
||||
# Here the accuracy was already good and is now perfect.
|
||||
cat(paste("The accuracy was", accuracy.before, "before adding leaf features and it is now", accuracy.after, "!\\n"))
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.cv.R
|
||||
\name{xgb.cv}
|
||||
\alias{xgb.cv}
|
||||
\title{Cross Validation}
|
||||
\usage{
|
||||
xgb.cv(params = list(), data, nrounds, nfold, label = NULL,
|
||||
missing = NULL, prediction = FALSE, showsd = TRUE, metrics = list(),
|
||||
obj = NULL, feval = NULL, stratified = TRUE, folds = NULL,
|
||||
verbose = T, early_stop_round = NULL, early.stop.round = NULL,
|
||||
maximize = NULL, ...)
|
||||
xgb.cv(params = list(), data, nrounds, nfold, label = NULL, missing = NA,
|
||||
prediction = FALSE, showsd = TRUE, metrics = list(), obj = NULL,
|
||||
feval = NULL, stratified = TRUE, folds = NULL, verbose = TRUE,
|
||||
print_every_n = 1L, early_stopping_rounds = NULL, maximize = NULL,
|
||||
callbacks = list(), ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{params}{the list of parameters. Commonly used ones are:
|
||||
@@ -19,11 +19,11 @@ xgb.cv(params = list(), data, nrounds, nfold, label = NULL,
|
||||
\item \code{binary:logistic} logistic regression for classification
|
||||
}
|
||||
\item \code{eta} step size of each boosting step
|
||||
\item \code{max.depth} maximum depth of the tree
|
||||
\item \code{max_depth} maximum depth of the tree
|
||||
\item \code{nthread} number of thread used in training, if not set, all threads are used
|
||||
}
|
||||
|
||||
See \link{xgb.train} for further details.
|
||||
See \code{\link{xgb.train}} for further details.
|
||||
See also demo/ for walkthrough example in R.}
|
||||
|
||||
\item{data}{takes an \code{xgb.DMatrix} or \code{Matrix} as the input.}
|
||||
@@ -32,16 +32,18 @@ xgb.cv(params = list(), data, nrounds, nfold, label = NULL,
|
||||
|
||||
\item{nfold}{the original dataset is randomly partitioned into \code{nfold} equal size subsamples.}
|
||||
|
||||
\item{label}{option field, when data is \code{Matrix}}
|
||||
\item{label}{vector of response values. Should be provided only when data is \code{DMatrix}.}
|
||||
|
||||
\item{missing}{Missing is only used when input is dense matrix, pick a float
|
||||
value that represents missing value. Sometime a data use 0 or other extreme value to represents missing values.}
|
||||
\item{missing}{is only used when input is a dense matrix. By default is set to NA, which means
|
||||
that NA values should be considered as 'missing' by the algorithm.
|
||||
Sometimes, 0 or other extreme value might be used to represent missing values.}
|
||||
|
||||
\item{prediction}{A logical value indicating whether to return the prediction vector.}
|
||||
\item{prediction}{A logical value indicating whether to return the test fold predictions
|
||||
from each CV model. This parameter engages the \code{\link{cb.cv.predict}} callback.}
|
||||
|
||||
\item{showsd}{\code{boolean}, whether show standard deviation of cross validation}
|
||||
\item{showsd}{\code{boolean}, whether to show standard deviation of cross validation}
|
||||
|
||||
\item{metrics,}{list of evaluation metrics to be used in corss validation,
|
||||
\item{metrics, }{list of evaluation metrics to be used in cross validation,
|
||||
when it is not specified, the evaluation metric is chosen according to objective function.
|
||||
Possible options are:
|
||||
\itemize{
|
||||
@@ -52,47 +54,76 @@ value that represents missing value. Sometime a data use 0 or other extreme valu
|
||||
\item \code{merror} Exact matching error, used to evaluate multi-class classification
|
||||
}}
|
||||
|
||||
\item{obj}{customized objective function. Returns gradient and second order
|
||||
\item{obj}{customized objective function. Returns gradient and second order
|
||||
gradient with given prediction and dtrain.}
|
||||
|
||||
\item{feval}{custimized evaluation function. Returns
|
||||
\code{list(metric='metric-name', value='metric-value')} with given
|
||||
\item{feval}{custimized evaluation function. Returns
|
||||
\code{list(metric='metric-name', value='metric-value')} with given
|
||||
prediction and dtrain.}
|
||||
|
||||
\item{stratified}{\code{boolean} whether sampling of folds should be stratified by the values of labels in \code{data}}
|
||||
\item{stratified}{a \code{boolean} indicating whether sampling of folds should be stratified
|
||||
by the values of outcome labels.}
|
||||
|
||||
\item{folds}{\code{list} provides a possibility of using a list of pre-defined CV folds (each element must be a vector of fold's indices).
|
||||
If folds are supplied, the nfold and stratified parameters would be ignored.}
|
||||
\item{folds}{\code{list} provides a possibility to use a list of pre-defined CV folds
|
||||
(each element must be a vector of test fold's indices). When folds are supplied,
|
||||
the \code{nfold} and \code{stratified} parameters are ignored.}
|
||||
|
||||
\item{verbose}{\code{boolean}, print the statistics during the process}
|
||||
|
||||
\item{early_stop_round}{If \code{NULL}, the early stopping function is not triggered.
|
||||
If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
keeps getting worse consecutively for \code{k} rounds.}
|
||||
\item{print_every_n}{Print each n-th iteration evaluation messages when \code{verbose>0}.
|
||||
Default is 1 which means all messages are printed. This parameter is passed to the
|
||||
\code{\link{cb.print.evaluation}} callback.}
|
||||
|
||||
\item{early.stop.round}{An alternative of \code{early_stop_round}.}
|
||||
\item{early_stopping_rounds}{If \code{NULL}, the early stopping function is not triggered.
|
||||
If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
doesn't improve for \code{k} rounds.
|
||||
Setting this parameter engages the \code{\link{cb.early.stop}} callback.}
|
||||
|
||||
\item{maximize}{If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
\code{maximize=TRUE} means the larger the evaluation score the better.}
|
||||
\item{maximize}{If \code{feval} and \code{early_stopping_rounds} are set,
|
||||
then this parameter must be set as well.
|
||||
When it is \code{TRUE}, it means the larger the evaluation score the better.
|
||||
This parameter is passed to the \code{\link{cb.early.stop}} callback.}
|
||||
|
||||
\item{callbacks}{a list of callback functions to perform various task during boosting.
|
||||
See \code{\link{callbacks}}. Some of the callbacks are automatically created depending on the
|
||||
parameters' values. User can provide either existing or their own callback methods in order
|
||||
to customize the training process.}
|
||||
|
||||
\item{...}{other parameters to pass to \code{params}.}
|
||||
}
|
||||
\value{
|
||||
If \code{prediction = TRUE}, a list with the following elements is returned:
|
||||
An object of class \code{xgb.cv.synchronous} with the following elements:
|
||||
\itemize{
|
||||
\item \code{dt} a \code{data.table} with each mean and standard deviation stat for training set and test set
|
||||
\item \code{pred} an array or matrix (for multiclass classification) with predictions for each CV-fold for the model having been trained on the data in all other folds.
|
||||
\item \code{call} a function call.
|
||||
\item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||
\item \code{callbacks} callback functions that were either automatically assigned or
|
||||
explicitely passed.
|
||||
\item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
||||
first column corresponding to iteration number and the rest corresponding to the
|
||||
CV-based evaluation means and standard deviations for the training and test CV-sets.
|
||||
It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||
\item \code{niter} number of boosting iterations.
|
||||
\item \code{folds} the list of CV folds' indices - either those passed through the \code{folds}
|
||||
parameter or randomly generated.
|
||||
\item \code{best_iteration} iteration number with the best evaluation metric value
|
||||
(only available with early stopping).
|
||||
\item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||
which could further be used in \code{predict} method
|
||||
(only available with early stopping).
|
||||
\item \code{pred} CV prediction values available when \code{prediction} is set.
|
||||
It is either vector or matrix (see \code{\link{cb.cv.predict}}).
|
||||
\item \code{models} a liost of the CV folds' models. It is only available with the explicit
|
||||
setting of the \code{cb.cv.predict(save_models = TRUE)} callback.
|
||||
}
|
||||
|
||||
If \code{prediction = FALSE}, just a \code{data.table} with each mean and standard deviation stat for training set and test set is returned.
|
||||
}
|
||||
\description{
|
||||
The cross valudation function of xgboost
|
||||
}
|
||||
\details{
|
||||
The original sample is randomly partitioned into \code{nfold} equal size subsamples.
|
||||
The original sample is randomly partitioned into \code{nfold} equal size subsamples.
|
||||
|
||||
Of the \code{nfold} subsamples, a single subsample is retained as the validation data for testing the model, and the remaining \code{nfold - 1} subsamples are used as training data.
|
||||
Of the \code{nfold} subsamples, a single subsample is retained as the validation data for testing the model, and the remaining \code{nfold - 1} subsamples are used as training data.
|
||||
|
||||
The cross-validation process is then repeated \code{nrounds} times, with each of the \code{nfold} subsamples used exactly once as the validation data.
|
||||
|
||||
@@ -103,8 +134,10 @@ Adapted from \url{http://en.wikipedia.org/wiki/Cross-validation_\%28statistics\%
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
history <- xgb.cv(data = dtrain, nround=3, nthread = 2, nfold = 5, metrics=list("rmse","auc"),
|
||||
max.depth =3, eta = 1, objective = "binary:logistic")
|
||||
print(history)
|
||||
cv <- xgb.cv(data = dtrain, nrounds = 3, nthread = 2, nfold = 5, metrics = list("rmse","auc"),
|
||||
max_depth = 3, eta = 1, objective = "binary:logistic")
|
||||
print(cv)
|
||||
print(cv, verbose=TRUE)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.dump.R
|
||||
\name{xgb.dump}
|
||||
\alias{xgb.dump}
|
||||
\title{Save xgboost model to text file}
|
||||
\usage{
|
||||
xgb.dump(model = NULL, fname = NULL, fmap = "", with.stats = FALSE)
|
||||
xgb.dump(model = NULL, fname = NULL, fmap = "", with_stats = FALSE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{model}{the model object.}
|
||||
|
||||
\item{fname}{the name of the text file where to save the model text dump. If not provided or set to \code{NULL} the function will return the model as a \code{character} vector.}
|
||||
|
||||
\item{fmap}{feature map file representing the type of feature.
|
||||
Detailed description could be found at
|
||||
\item{fmap}{feature map file representing the type of feature.
|
||||
Detailed description could be found at
|
||||
\url{https://github.com/dmlc/xgboost/wiki/Binary-Classification#dump-model}.
|
||||
See demo/ for walkthrough example in R, and
|
||||
\url{https://github.com/dmlc/xgboost/blob/master/demo/data/featmap.txt}
|
||||
\url{https://github.com/dmlc/xgboost/blob/master/demo/data/featmap.txt}
|
||||
for example Format.}
|
||||
|
||||
\item{with.stats}{whether dump statistics of splits
|
||||
When this option is on, the model dump comes with two additional statistics:
|
||||
gain is the approximate loss function gain we get in each split;
|
||||
cover is the sum of second order gradient in each node.}
|
||||
\item{with_stats}{whether dump statistics of splits
|
||||
When this option is on, the model dump comes with two additional statistics:
|
||||
gain is the approximate loss function gain we get in each split;
|
||||
cover is the sum of second order gradient in each node.}
|
||||
|
||||
\item{...}{currently not used}
|
||||
}
|
||||
\value{
|
||||
if fname is not provided or set to \code{NULL} the function will return the model as a \code{character} vector. Otherwise it will return \code{TRUE}.
|
||||
@@ -34,10 +36,10 @@ data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
# save the model in file 'xgb.model.dump'
|
||||
xgb.dump(bst, 'xgb.model.dump', with.stats = TRUE)
|
||||
xgb.dump(bst, 'xgb.model.dump', with_stats = TRUE)
|
||||
|
||||
# print the model without saving it to a file
|
||||
print(xgb.dump(bst))
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.importance.R
|
||||
\name{xgb.importance}
|
||||
\alias{xgb.importance}
|
||||
\title{Show importance of features in a model}
|
||||
\usage{
|
||||
xgb.importance(feature_names = NULL, filename_dump = NULL, model = NULL,
|
||||
data = NULL, label = NULL, target = function(x) ((x + label) == 2))
|
||||
xgb.importance(feature_names = NULL, model = NULL, data = NULL,
|
||||
label = NULL, target = function(x) ((x + label) == 2))
|
||||
}
|
||||
\arguments{
|
||||
\item{feature_names}{names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
\item{feature_names}{names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
|
||||
\item{filename_dump}{the path to the text file storing the model. Model dump must include the gain per feature and per tree (\code{with.stats = T} in function \code{xgb.dump}).}
|
||||
|
||||
\item{model}{generated by the \code{xgb.train} function. Avoid the creation of a dump file.}
|
||||
\item{model}{generated by the \code{xgb.train} function.}
|
||||
|
||||
\item{data}{the dataset used for the training step. Will be used with \code{label} parameter for co-occurence computation. More information in \code{Detail} part. This parameter is optional.}
|
||||
|
||||
@@ -24,23 +22,24 @@ xgb.importance(feature_names = NULL, filename_dump = NULL, model = NULL,
|
||||
A \code{data.table} of the features used in the model with their average gain (and their weight for boosted tree model) in the model.
|
||||
}
|
||||
\description{
|
||||
Read a xgboost model text dump.
|
||||
Can be tree or linear model (text dump of linear model are only supported in dev version of \code{Xgboost} for now).
|
||||
Create a \code{data.table} of the most important features of a model.
|
||||
}
|
||||
\details{
|
||||
This is the function to understand the model trained (and through your model, your data).
|
||||
This function is for both linear and tree models.
|
||||
|
||||
Results are returned for both linear and tree models.
|
||||
|
||||
\code{data.table} is returned by the function.
|
||||
There are 3 columns :
|
||||
\code{data.table} is returned by the function.
|
||||
The columns are :
|
||||
\itemize{
|
||||
\item \code{Features} name of the features as provided in \code{feature_names} or already present in the model dump.
|
||||
\item \code{Gain} contribution of each feature to the model. For boosted tree model, each gain of each feature of each tree is taken into account, then average per feature to give a vision of the entire model. Highest percentage means important feature to predict the \code{label} used for the training ;
|
||||
\item \code{Cover} metric of the number of observation related to this feature (only available for tree models) ;
|
||||
\item \code{Weight} percentage representing the relative number of times a feature have been taken into trees. \code{Gain} should be prefered to search the most important feature. For boosted linear model, this column has no meaning.
|
||||
\item \code{Features} name of the features as provided in \code{feature_names} or already present in the model dump;
|
||||
\item \code{Gain} contribution of each feature to the model. For boosted tree model, each gain of each feature of each tree is taken into account, then average per feature to give a vision of the entire model. Highest percentage means important feature to predict the \code{label} used for the training (only available for tree models);
|
||||
\item \code{Cover} metric of the number of observation related to this feature (only available for tree models);
|
||||
\item \code{Weight} percentage representing the relative number of times a feature have been taken into trees.
|
||||
}
|
||||
|
||||
If you don't provide \code{feature_names}, index of the features will be used instead.
|
||||
|
||||
Because the index is extracted from the model dump (made on the C++ side), it starts at 0 (usual in C++) instead of 1 (usual in R).
|
||||
|
||||
Co-occurence count
|
||||
------------------
|
||||
|
||||
@@ -53,18 +52,13 @@ If you need to remember one thing only: until you want to leave us early, don't
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
# Both dataset are list with two items, a sparse matrix and labels
|
||||
# (labels = outcome column which will be learned).
|
||||
# Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
train <- agaricus.train
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
|
||||
# train$data@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
xgb.importance(train$data@Dimnames[[2]], model = bst)
|
||||
xgb.importance(colnames(agaricus.train$data), model = bst)
|
||||
|
||||
# Same thing with co-occurence computation this time
|
||||
xgb.importance(train$data@Dimnames[[2]], model = bst, data = train$data, label = train$label)
|
||||
xgb.importance(colnames(agaricus.train$data), model = bst, data = agaricus.train$data, label = agaricus.train$label)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.load.R
|
||||
\name{xgb.load}
|
||||
\alias{xgb.load}
|
||||
@@ -17,8 +17,8 @@ data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
xgb.save(bst, 'xgb.model')
|
||||
bst <- xgb.load('xgb.model')
|
||||
pred <- predict(bst, test$data)
|
||||
|
||||
@@ -1,59 +1,61 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.model.dt.tree.R
|
||||
\name{xgb.model.dt.tree}
|
||||
\alias{xgb.model.dt.tree}
|
||||
\title{Convert tree model dump to data.table}
|
||||
\title{Parse a boosted tree model text dump}
|
||||
\usage{
|
||||
xgb.model.dt.tree(feature_names = NULL, filename_dump = NULL,
|
||||
model = NULL, text = NULL, n_first_tree = NULL)
|
||||
xgb.model.dt.tree(feature_names = NULL, model = NULL, text = NULL,
|
||||
n_first_tree = NULL)
|
||||
}
|
||||
\arguments{
|
||||
\item{feature_names}{names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
\item{feature_names}{character vector of feature names. If the model already
|
||||
contains feature names, this argument should be \code{NULL} (default value)}
|
||||
|
||||
\item{filename_dump}{the path to the text file storing the model. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}).}
|
||||
\item{model}{object of class \code{xgb.Booster}}
|
||||
|
||||
\item{model}{dump generated by the \code{xgb.train} function. Avoid the creation of a dump file.}
|
||||
\item{text}{\code{character} vector previously generated by the \code{xgb.dump}
|
||||
function (where parameter \code{with_stats = TRUE} should have been set).}
|
||||
|
||||
\item{text}{dump generated by the \code{xgb.dump} function. Avoid the creation of a dump file. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}).}
|
||||
|
||||
\item{n_first_tree}{limit the plot to the n first trees. If \code{NULL}, all trees of the model are plotted. Performance can be low for huge models.}
|
||||
\item{n_first_tree}{limit the parsing to the \code{n} first trees.
|
||||
If set to \code{NULL}, all trees of the model are parsed.}
|
||||
}
|
||||
\value{
|
||||
A \code{data.table} of the features used in the model with their gain, cover and few other thing.
|
||||
}
|
||||
\description{
|
||||
Read a tree model text dump and return a data.table.
|
||||
}
|
||||
\details{
|
||||
General function to convert a text dump of tree model to a Matrix. The purpose is to help user to explore the model and get a better understanding of it.
|
||||
A \code{data.table} with detailed information about model trees' nodes.
|
||||
|
||||
The content of the \code{data.table} is organised that way:
|
||||
The columns of the \code{data.table} are:
|
||||
|
||||
\itemize{
|
||||
\item \code{ID}: unique identifier of a node ;
|
||||
\item \code{Feature}: feature used in the tree to operate a split. When Leaf is indicated, it is the end of a branch ;
|
||||
\item \code{Split}: value of the chosen feature where is operated the split ;
|
||||
\item \code{Yes}: ID of the feature for the next node in the branch when the split condition is met ;
|
||||
\item \code{No}: ID of the feature for the next node in the branch when the split condition is not met ;
|
||||
\item \code{Missing}: ID of the feature for the next node in the branch for observation where the feature used for the split are not provided ;
|
||||
\item \code{Quality}: it's the gain related to the split in this specific node ;
|
||||
\item \code{Cover}: metric to measure the number of observation affected by the split ;
|
||||
\item \code{Tree}: ID of the tree. It is included in the main ID ;
|
||||
\item \code{Yes.X} or \code{No.X}: data related to the pointer in \code{Yes} or \code{No} column ;
|
||||
\item \code{Tree}: ID of a tree in a model
|
||||
\item \code{Node}: ID of a node in a tree
|
||||
\item \code{ID}: unique identifier of a node in a model
|
||||
\item \code{Feature}: for a branch node, it's a feature id or name (when available);
|
||||
for a leaf note, it simply labels it as \code{'Leaf'}
|
||||
\item \code{Split}: location of the split for a branch node (split condition is always "less than")
|
||||
\item \code{Yes}: ID of the next node when the split condition is met
|
||||
\item \code{No}: ID of the next node when the split condition is not met
|
||||
\item \code{Missing}: ID of the next node when branch value is missing
|
||||
\item \code{Quality}: either the split gain (change in loss) or the leaf value
|
||||
\item \code{Cover}: metric related to the number of observation either seen by a split
|
||||
or collected by a leaf during training.
|
||||
}
|
||||
}
|
||||
\description{
|
||||
Parse a boosted tree model text dump into a \code{data.table} structure.
|
||||
}
|
||||
\examples{
|
||||
# Basic use:
|
||||
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
#Both dataset are list with two items, a sparse matrix and labels
|
||||
#(labels = outcome column which will be learned).
|
||||
#Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
train <- agaricus.train
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
(dt <- xgb.model.dt.tree(colnames(agaricus.train$data), bst))
|
||||
|
||||
#agaricus.test$data@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
xgb.model.dt.tree(agaricus.train$data@Dimnames[[2]], model = bst)
|
||||
|
||||
# How to match feature names of splits that are following a current 'Yes' branch:
|
||||
|
||||
merge(dt, dt[, .(ID, Y.Feature=Feature)], by.x='Yes', by.y='ID', all.x=TRUE)[order(Tree,Node)]
|
||||
|
||||
}
|
||||
|
||||
|
||||
32
R-package/man/xgb.parameters.Rd
Normal file
32
R-package/man/xgb.parameters.Rd
Normal file
@@ -0,0 +1,32 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.Booster.R
|
||||
\name{xgb.parameters<-}
|
||||
\alias{xgb.parameters<-}
|
||||
\title{Accessors for model parameters.}
|
||||
\usage{
|
||||
xgb.parameters(object) <- value
|
||||
}
|
||||
\arguments{
|
||||
\item{object}{Object of class \code{xgb.Booster} or \code{xgb.Booster.handle}.}
|
||||
|
||||
\item{value}{a list (or an object coercible to a list) with the names of parameters to set
|
||||
and the elements corresponding to parameter values.}
|
||||
}
|
||||
\description{
|
||||
Only the setter for xgboost parameters is currently implemented.
|
||||
}
|
||||
\details{
|
||||
Note that the setter would usually work more efficiently for \code{xgb.Booster.handle}
|
||||
than for \code{xgb.Booster}, since only just a handle would need to be copied.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
train <- agaricus.train
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
|
||||
xgb.parameters(bst) <- list(eta = 0.1)
|
||||
|
||||
}
|
||||
|
||||
74
R-package/man/xgb.plot.deepness.Rd
Normal file
74
R-package/man/xgb.plot.deepness.Rd
Normal file
@@ -0,0 +1,74 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.ggplot.R, R/xgb.plot.deepness.R
|
||||
\name{xgb.ggplot.deepness}
|
||||
\alias{xgb.ggplot.deepness}
|
||||
\alias{xgb.plot.deepness}
|
||||
\title{Plot model trees deepness}
|
||||
\usage{
|
||||
xgb.ggplot.deepness(model = NULL, which = c("2x1", "max.depth", "med.depth",
|
||||
"med.weight"))
|
||||
|
||||
xgb.plot.deepness(model = NULL, which = c("2x1", "max.depth", "med.depth",
|
||||
"med.weight"), plot = TRUE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{model}{either an \code{xgb.Booster} model generated by the \code{xgb.train} function
|
||||
or a data.table result of the \code{xgb.model.dt.tree} function.}
|
||||
|
||||
\item{which}{which distribution to plot (see details).}
|
||||
|
||||
\item{plot}{(base R barplot) whether a barplot should be produced.
|
||||
If FALSE, only a data.table is returned.}
|
||||
|
||||
\item{...}{other parameters passed to \code{barplot} or \code{plot}.}
|
||||
}
|
||||
\value{
|
||||
Other than producing plots (when \code{plot=TRUE}), the \code{xgb.plot.deepness} function
|
||||
silently returns a processed data.table where each row corresponds to a terminal leaf in a tree model,
|
||||
and contains information about leaf's depth, cover, and weight (which is used in calculating predictions).
|
||||
|
||||
The \code{xgb.ggplot.deepness} silently returns either a list of two ggplot graphs when \code{which="2x1"}
|
||||
or a single ggplot graph for the other \code{which} options.
|
||||
}
|
||||
\description{
|
||||
Visualizes distributions related to depth of tree leafs.
|
||||
\code{xgb.plot.deepness} uses base R graphics, while \code{xgb.ggplot.deepness} uses the ggplot backend.
|
||||
}
|
||||
\details{
|
||||
When \code{which="2x1"}, two distributions with respect to the leaf depth
|
||||
are plotted on top of each other:
|
||||
\itemize{
|
||||
\item the distribution of the number of leafs in a tree model at a certain depth;
|
||||
\item the distribution of average weighted number of observations ("cover")
|
||||
ending up in leafs at certain depth.
|
||||
}
|
||||
Those could be helpful in determining sensible ranges of the \code{max_depth}
|
||||
and \code{min_child_weight} parameters.
|
||||
|
||||
When \code{which="max.depth"} or \code{which="med.depth"}, plots of either maximum or median depth
|
||||
per tree with respect to tree number are created. And \code{which="med.weight"} allows to see how
|
||||
a tree's median absolute leaf weight changes through the iterations.
|
||||
|
||||
This function was inspired by the blog post
|
||||
\url{http://aysent.github.io/2015/11/08/random-forest-leaf-visualization.html}.
|
||||
}
|
||||
\examples{
|
||||
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 15,
|
||||
eta = 0.1, nthread = 2, nrounds = 50, objective = "binary:logistic",
|
||||
subsample = 0.5, min_child_weight = 2)
|
||||
|
||||
xgb.plot.deepness(bst)
|
||||
xgb.ggplot.deepness(bst)
|
||||
|
||||
xgb.plot.deepness(bst, which='max.depth', pch=16, col=rgb(0,0,1,0.3), cex=2)
|
||||
|
||||
xgb.plot.deepness(bst, which='med.weight', pch=16, col=rgb(0,0,1,0.3), cex=2)
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{xgb.train}}, \code{\link{xgb.model.dt.tree}}.
|
||||
}
|
||||
|
||||
@@ -1,40 +1,82 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/xgb.plot.importance.R
|
||||
\name{xgb.plot.importance}
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.ggplot.R, R/xgb.plot.importance.R
|
||||
\name{xgb.ggplot.importance}
|
||||
\alias{xgb.ggplot.importance}
|
||||
\alias{xgb.plot.importance}
|
||||
\title{Plot feature importance bar graph}
|
||||
\title{Plot feature importance as a bar graph}
|
||||
\usage{
|
||||
xgb.plot.importance(importance_matrix = NULL, numberOfClusters = c(1:10))
|
||||
xgb.ggplot.importance(importance_matrix = NULL, top_n = NULL,
|
||||
measure = NULL, rel_to_first = FALSE, n_clusters = c(1:10), ...)
|
||||
|
||||
xgb.plot.importance(importance_matrix = NULL, top_n = NULL,
|
||||
measure = NULL, rel_to_first = FALSE, left_margin = 10, cex = NULL,
|
||||
plot = TRUE, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{importance_matrix}{a \code{data.table} returned by the \code{xgb.importance} function.}
|
||||
\item{importance_matrix}{a \code{data.table} returned by \code{\link{xgb.importance}}.}
|
||||
|
||||
\item{numberOfClusters}{a \code{numeric} vector containing the min and the max range of the possible number of clusters of bars.}
|
||||
\item{top_n}{maximal number of top features to include into the plot.}
|
||||
|
||||
\item{measure}{the name of importance measure to plot.
|
||||
When \code{NULL}, 'Gain' would be used for trees and 'Weight' would be used for gblinear.}
|
||||
|
||||
\item{rel_to_first}{whether importance values should be represented as relative to the highest ranked feature.
|
||||
See Details.}
|
||||
|
||||
\item{n_clusters}{(ggplot only) a \code{numeric} vector containing the min and the max range
|
||||
of the possible number of clusters of bars.}
|
||||
|
||||
\item{...}{other parameters passed to \code{barplot} (except horiz, border, cex.names, names.arg, and las).}
|
||||
|
||||
\item{left_margin}{(base R barplot) allows to adjust the left margin size to fit feature names.
|
||||
When it is NULL, the existing \code{par('mar')} is used.}
|
||||
|
||||
\item{cex}{(base R barplot) passed as \code{cex.names} parameter to \code{barplot}.}
|
||||
|
||||
\item{plot}{(base R barplot) whether a barplot should be produced.
|
||||
If FALSE, only a data.table is returned.}
|
||||
}
|
||||
\value{
|
||||
A \code{ggplot2} bar graph representing each feature by a horizontal bar. Longer is the bar, more important is the feature. Features are classified by importance and clustered by importance. The group is represented through the color of the bar.
|
||||
The \code{xgb.plot.importance} function creates a \code{barplot} (when \code{plot=TRUE})
|
||||
and silently returns a processed data.table with \code{n_top} features sorted by importance.
|
||||
|
||||
The \code{xgb.ggplot.importance} function returns a ggplot graph which could be customized afterwards.
|
||||
E.g., to change the title of the graph, add \code{+ ggtitle("A GRAPH NAME")} to the result.
|
||||
}
|
||||
\description{
|
||||
Read a data.table containing feature importance details and plot it.
|
||||
Represents previously calculated feature importance as a bar graph.
|
||||
\code{xgb.plot.importance} uses base R graphics, while \code{xgb.ggplot.importance} uses the ggplot backend.
|
||||
}
|
||||
\details{
|
||||
The purpose of this function is to easily represent the importance of each feature of a model.
|
||||
The function return a ggplot graph, therefore each of its characteristic can be overriden (to customize it).
|
||||
In particular you may want to override the title of the graph. To do so, add \code{+ ggtitle("A GRAPH NAME")} next to the value returned by this function.
|
||||
The graph represents each feature as a horizontal bar of length proportional to the importance of a feature.
|
||||
Features are shown ranked in a decreasing importance order.
|
||||
It works for importances from both \code{gblinear} and \code{gbtree} models.
|
||||
|
||||
When \code{rel_to_first = FALSE}, the values would be plotted as they were in \code{importance_matrix}.
|
||||
For gbtree model, that would mean being normalized to the total of 1
|
||||
("what is feature's importance contribution relative to the whole model?").
|
||||
For linear models, \code{rel_to_first = FALSE} would show actual values of the coefficients.
|
||||
Setting \code{rel_to_first = TRUE} allows to see the picture from the perspective of
|
||||
"what is feature's importance contribution relative to the most important feature?"
|
||||
|
||||
The ggplot-backend method also performs 1-D custering of the importance values,
|
||||
with bar colors coresponding to different clusters that have somewhat similar importance values.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.train)
|
||||
|
||||
#Both dataset are list with two items, a sparse matrix and labels
|
||||
#(labels = outcome column which will be learned).
|
||||
#Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
train <- agaricus.train
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 3,
|
||||
eta = 1, nthread = 2, nrounds = 2, objective = "binary:logistic")
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
importance_matrix <- xgb.importance(colnames(agaricus.train$data), model = bst)
|
||||
|
||||
#train$data@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
importance_matrix <- xgb.importance(train$data@Dimnames[[2]], model = bst)
|
||||
xgb.plot.importance(importance_matrix)
|
||||
xgb.plot.importance(importance_matrix, rel_to_first = TRUE, xlab = "Relative importance")
|
||||
|
||||
(gg <- xgb.ggplot.importance(importance_matrix, measure = "Frequency", rel_to_first = TRUE))
|
||||
gg + ggplot2::ylab("Frequency")
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link[graphics]{barplot}}.
|
||||
}
|
||||
|
||||
|
||||
60
R-package/man/xgb.plot.multi.trees.Rd
Normal file
60
R-package/man/xgb.plot.multi.trees.Rd
Normal file
@@ -0,0 +1,60 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.plot.multi.trees.R
|
||||
\name{xgb.plot.multi.trees}
|
||||
\alias{xgb.plot.multi.trees}
|
||||
\title{Project all trees on one tree and plot it}
|
||||
\usage{
|
||||
xgb.plot.multi.trees(model, feature_names = NULL, features_keep = 5,
|
||||
plot_width = NULL, plot_height = NULL, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{model}{dump generated by the \code{xgb.train} function.}
|
||||
|
||||
\item{feature_names}{names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
|
||||
\item{features_keep}{number of features to keep in each position of the multi trees.}
|
||||
|
||||
\item{plot_width}{width in pixels of the graph to produce}
|
||||
|
||||
\item{plot_height}{height in pixels of the graph to produce}
|
||||
|
||||
\item{...}{currently not used}
|
||||
}
|
||||
\value{
|
||||
Two graphs showing the distribution of the model deepness.
|
||||
}
|
||||
\description{
|
||||
Visualization of the ensemble of trees as a single collective unit.
|
||||
}
|
||||
\details{
|
||||
This function tries to capture the complexity of gradient boosted tree ensemble
|
||||
in a cohesive way.
|
||||
|
||||
The goal is to improve the interpretability of the model generally seen as black box.
|
||||
The function is dedicated to boosting applied to decision trees only.
|
||||
|
||||
The purpose is to move from an ensemble of trees to a single tree only.
|
||||
|
||||
It takes advantage of the fact that the shape of a binary tree is only defined by
|
||||
its deepness (therefore in a boosting model, all trees have the same shape).
|
||||
|
||||
Moreover, the trees tend to reuse the same features.
|
||||
|
||||
The function will project each tree on one, and keep for each position the
|
||||
\code{features_keep} first features (based on Gain per feature measure).
|
||||
|
||||
This function is inspired by this blog post:
|
||||
\url{https://wellecks.wordpress.com/2015/02/21/peering-into-the-black-box-visualizing-lambdamart/}
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 15,
|
||||
eta = 1, nthread = 2, nrounds = 30, objective = "binary:logistic",
|
||||
min_child_weight = 50)
|
||||
|
||||
p <- xgb.plot.multi.trees(model = bst, feature_names = colnames(agaricus.train$data), features_keep = 3)
|
||||
print(p)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,58 +1,49 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.plot.tree.R
|
||||
\name{xgb.plot.tree}
|
||||
\alias{xgb.plot.tree}
|
||||
\title{Plot a boosted tree model}
|
||||
\usage{
|
||||
xgb.plot.tree(feature_names = NULL, filename_dump = NULL, model = NULL,
|
||||
n_first_tree = NULL, CSSstyle = NULL, width = NULL, height = NULL)
|
||||
xgb.plot.tree(feature_names = NULL, model = NULL, n_first_tree = NULL,
|
||||
plot_width = NULL, plot_height = NULL, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{feature_names}{names of each feature as a character vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
|
||||
\item{filename_dump}{the path to the text file storing the model. Model dump must include the gain per feature and per tree (parameter \code{with.stats = T} in function \code{xgb.dump}). Possible to provide a model directly (see \code{model} argument).}
|
||||
\item{feature_names}{names of each feature as a \code{character} vector. Can be extracted from a sparse matrix (see example). If model dump already contains feature names, this argument should be \code{NULL}.}
|
||||
|
||||
\item{model}{generated by the \code{xgb.train} function. Avoid the creation of a dump file.}
|
||||
|
||||
\item{n_first_tree}{limit the plot to the n first trees. If \code{NULL}, all trees of the model are plotted. Performance can be low for huge models.}
|
||||
|
||||
\item{CSSstyle}{a \code{character} vector storing a css style to customize the appearance of nodes. Look at the \href{https://github.com/knsv/mermaid/wiki}{Mermaid wiki} for more information.}
|
||||
\item{plot_width}{the width of the diagram in pixels.}
|
||||
|
||||
\item{width}{the width of the diagram in pixels.}
|
||||
\item{plot_height}{the height of the diagram in pixels.}
|
||||
|
||||
\item{height}{the height of the diagram in pixels.}
|
||||
\item{...}{currently not used.}
|
||||
}
|
||||
\value{
|
||||
A \code{DiagrammeR} of the model.
|
||||
}
|
||||
\description{
|
||||
Read a tree model text dump.
|
||||
Plotting only works for boosted tree model (not linear model).
|
||||
Read a tree model text dump and plot the model.
|
||||
}
|
||||
\details{
|
||||
The content of each node is organised that way:
|
||||
|
||||
\itemize{
|
||||
\item \code{feature} value ;
|
||||
\item \code{cover}: the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be ;
|
||||
\item \code{feature} value;
|
||||
\item \code{cover}: the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be;
|
||||
\item \code{gain}: metric the importance of the node in the model.
|
||||
}
|
||||
}
|
||||
|
||||
Each branch finishes with a leaf. For each leaf, only the \code{cover} is indicated.
|
||||
It uses \href{https://github.com/knsv/mermaid/}{Mermaid} library for that purpose.
|
||||
The function uses \href{http://www.graphviz.org/}{GraphViz} library for that purpose.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
|
||||
#Both dataset are list with two items, a sparse matrix and labels
|
||||
#(labels = outcome column which will be learned).
|
||||
#Each column of the sparse Matrix is a feature in one hot encoding format.
|
||||
train <- agaricus.train
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
xgb.plot.tree(feature_names = colnames(agaricus.train$data), model = bst)
|
||||
|
||||
#agaricus.test$data@Dimnames[[2]] represents the column names of the sparse matrix.
|
||||
xgb.plot.tree(agaricus.train$data@Dimnames[[2]], model = bst)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.save.R
|
||||
\name{xgb.save}
|
||||
\alias{xgb.save}
|
||||
@@ -9,7 +9,7 @@ xgb.save(model, fname)
|
||||
\arguments{
|
||||
\item{model}{the model object.}
|
||||
|
||||
\item{fname}{the name of the binary file.}
|
||||
\item{fname}{the name of the file to write.}
|
||||
}
|
||||
\description{
|
||||
Save xgboost model from xgboost or xgb.train
|
||||
@@ -19,8 +19,8 @@ data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
xgb.save(bst, 'xgb.model')
|
||||
bst <- xgb.load('xgb.model')
|
||||
pred <- predict(bst, test$data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.save.raw.R
|
||||
\name{xgb.save.raw}
|
||||
\alias{xgb.save.raw}
|
||||
@@ -18,10 +18,11 @@ data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2,objective = "binary:logistic")
|
||||
bst <- xgboost(data = train$data, label = train$label, max_depth = 2,
|
||||
eta = 1, nthread = 2, nrounds = 2,objective = "binary:logistic")
|
||||
raw <- xgb.save.raw(bst)
|
||||
bst <- xgb.load(raw)
|
||||
pred <- predict(bst, test$data)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/xgb.train.R
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/xgb.train.R, R/xgboost.R
|
||||
\name{xgb.train}
|
||||
\alias{xgb.train}
|
||||
\alias{xgboost}
|
||||
\title{eXtreme Gradient Boosting Training}
|
||||
\usage{
|
||||
xgb.train(params = list(), data, nrounds, watchlist = list(), obj = NULL,
|
||||
feval = NULL, verbose = 1, printEveryN=1L, early_stop_round = NULL,
|
||||
early.stop.round = NULL, maximize = NULL, ...)
|
||||
feval = NULL, verbose = 1, print_every_n = 1L,
|
||||
early_stopping_rounds = NULL, maximize = NULL, save_period = NULL,
|
||||
save_name = "xgboost.model", xgb_model = NULL, callbacks = list(), ...)
|
||||
|
||||
xgboost(data = NULL, label = NULL, missing = NA, weight = NULL,
|
||||
params = list(), nrounds, verbose = 1, print_every_n = 1L,
|
||||
early_stopping_rounds = NULL, maximize = NULL, save_period = 0,
|
||||
save_name = "xgboost.model", xgb_model = NULL, callbacks = list(), ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{params}{the list of parameters.
|
||||
\item{params}{the list of parameters.
|
||||
The complete list of parameters is available at \url{http://xgboost.readthedocs.io/en/latest/parameter.html}.
|
||||
Below is a shorter summary:
|
||||
|
||||
1. General Parameters
|
||||
|
||||
@@ -17,112 +26,185 @@ xgb.train(params = list(), data, nrounds, watchlist = list(), obj = NULL,
|
||||
\item \code{booster} which booster to use, can be \code{gbtree} or \code{gblinear}. Default: \code{gbtree}
|
||||
\item \code{silent} 0 means printing running messages, 1 means silent mode. Default: 0
|
||||
}
|
||||
|
||||
|
||||
2. Booster Parameters
|
||||
|
||||
2.1. Parameter for Tree Booster
|
||||
|
||||
\itemize{
|
||||
\item \code{eta} control the learning rate: scale the contribution of each tree by a factor of \code{0 < eta < 1} when it is added to the current approximation. Used to prevent overfitting by making the boosting process more conservative. Lower value for \code{eta} implies larger value for \code{nrounds}: low \code{eta} value means model more robust to overfitting but slower to compute. Default: 0.3
|
||||
\item \code{gamma} minimum loss reduction required to make a further partition on a leaf node of the tree. the larger, the more conservative the algorithm will be.
|
||||
\item \code{gamma} minimum loss reduction required to make a further partition on a leaf node of the tree. the larger, the more conservative the algorithm will be.
|
||||
\item \code{max_depth} maximum depth of a tree. Default: 6
|
||||
\item \code{min_child_weight} minimum sum of instance weight(hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will be. Default: 1
|
||||
\item \code{subsample} subsample ratio of the training instance. Setting it to 0.5 means that xgboost randomly collected half of the data instances to grow trees and this will prevent overfitting. It makes computation shorter (because less data to analyse). It is advised to use this parameter with \code{eta} and increase \code{nround}. Default: 1
|
||||
\item \code{min_child_weight} minimum sum of instance weight (hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will be. Default: 1
|
||||
\item \code{subsample} subsample ratio of the training instance. Setting it to 0.5 means that xgboost randomly collected half of the data instances to grow trees and this will prevent overfitting. It makes computation shorter (because less data to analyse). It is advised to use this parameter with \code{eta} and increase \code{nround}. Default: 1
|
||||
\item \code{colsample_bytree} subsample ratio of columns when constructing each tree. Default: 1
|
||||
\item \code{num_parallel_tree} Experimental parameter. number of trees to grow per round. Useful to test Random Forest through Xgboost (set \code{colsample_bytree < 1}, \code{subsample < 1} and \code{round = 1}) accordingly. Default: 1
|
||||
}
|
||||
|
||||
2.2. Parameter for Linear Booster
|
||||
|
||||
|
||||
\itemize{
|
||||
\item \code{lambda} L2 regularization term on weights. Default: 0
|
||||
\item \code{lambda_bias} L2 regularization term on bias. Default: 0
|
||||
\item \code{alpha} L1 regularization term on weights. (there is no L1 reg on bias because it is not important). Default: 0
|
||||
}
|
||||
|
||||
3. Task Parameters
|
||||
3. Task Parameters
|
||||
|
||||
\itemize{
|
||||
\item \code{objective} specify the learning task and the corresponding learning objective, and the objective options are below:
|
||||
\item \code{objective} specify the learning task and the corresponding learning objective, users can pass a self-defined function to it. The default objective options are below:
|
||||
\itemize{
|
||||
\item \code{reg:linear} linear regression (Default).
|
||||
\item \code{reg:logistic} logistic regression.
|
||||
\item \code{binary:logistic} logistic regression for binary classification. Output probability.
|
||||
\item \code{binary:logitraw} logistic regression for binary classification, output score before logistic transformation.
|
||||
\item \code{num_class} set the number of classes. To use only with multiclass objectives.
|
||||
\item \code{multi:softmax} set xgboost to do multiclass classification using the softmax objective. Class is represented by a number and should be from 0 to \code{tonum_class}.
|
||||
\item \code{multi:softprob} same as softmax, but output a vector of ndata * nclass, which can be further reshaped to ndata, nclass matrix. The result contains predicted probabilities of each data point belonging to each class.
|
||||
\item \code{multi:softmax} set xgboost to do multiclass classification using the softmax objective. Class is represented by a number and should be from 0 to \code{num_class - 1}.
|
||||
\item \code{multi:softprob} same as softmax, but prediction outputs a vector of ndata * nclass elements, which can be further reshaped to ndata, nclass matrix. The result contains predicted probabilities of each data point belonging to each class.
|
||||
\item \code{rank:pairwise} set xgboost to do ranking task by minimizing the pairwise loss.
|
||||
}
|
||||
\item \code{base_score} the initial prediction score of all instances, global bias. Default: 0.5
|
||||
\item \code{eval_metric} evaluation metrics for validation data. Default: metric will be assigned according to objective(rmse for regression, and error for classification, mean average precision for ranking). List is provided in detail section.
|
||||
\item \code{eval_metric} evaluation metrics for validation data. Users can pass a self-defined function to it. Default: metric will be assigned according to objective(rmse for regression, and error for classification, mean average precision for ranking). List is provided in detail section.
|
||||
}}
|
||||
|
||||
\item{data}{takes an \code{xgb.DMatrix} as the input.}
|
||||
\item{data}{input dataset. \code{xgb.train} takes only an \code{xgb.DMatrix} as the input.
|
||||
\code{xgboost}, in addition, also accepts \code{matrix}, \code{dgCMatrix}, or local data file.}
|
||||
|
||||
\item{nrounds}{the max number of iterations}
|
||||
|
||||
\item{watchlist}{what information should be printed when \code{verbose=1} or
|
||||
\code{verbose=2}. Watchlist is used to specify validation set monitoring
|
||||
during training. For example user can specify
|
||||
watchlist=list(validation1=mat1, validation2=mat2) to watch
|
||||
the performance of each round's model on mat1 and mat2}
|
||||
\code{verbose=2}. Watchlist is used to specify validation set monitoring
|
||||
during training. For example user can specify
|
||||
watchlist=list(validation1=mat1, validation2=mat2) to watch
|
||||
the performance of each round's model on mat1 and mat2}
|
||||
|
||||
\item{obj}{customized objective function. Returns gradient and second order
|
||||
gradient with given prediction and dtrain,}
|
||||
\item{obj}{customized objective function. Returns gradient and second order
|
||||
gradient with given prediction and dtrain.}
|
||||
|
||||
\item{feval}{custimized evaluation function. Returns
|
||||
\code{list(metric='metric-name', value='metric-value')} with given
|
||||
prediction and dtrain,}
|
||||
\item{feval}{custimized evaluation function. Returns
|
||||
\code{list(metric='metric-name', value='metric-value')} with given
|
||||
prediction and dtrain.}
|
||||
|
||||
\item{verbose}{If 0, xgboost will stay silent. If 1, xgboost will print
|
||||
information of performance. If 2, xgboost will print information of both}
|
||||
\item{verbose}{If 0, xgboost will stay silent. If 1, xgboost will print
|
||||
information of performance. If 2, xgboost will print some additional information.
|
||||
Setting \code{verbose > 0} automatically engages the \code{\link{cb.evaluation.log}} and
|
||||
\code{\link{cb.print.evaluation}} callback functions.}
|
||||
|
||||
\item{printEveryN}{Print every N progress messages when \code{verbose>0}. Default is 1 which means all messages are printed.}
|
||||
\item{print_every_n}{Print each n-th iteration evaluation messages when \code{verbose>0}.
|
||||
Default is 1 which means all messages are printed. This parameter is passed to the
|
||||
\code{\link{cb.print.evaluation}} callback.}
|
||||
|
||||
\item{early_stop_round}{If \code{NULL}, the early stopping function is not triggered.
|
||||
If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
keeps getting worse consecutively for \code{k} rounds.}
|
||||
\item{early_stopping_rounds}{If \code{NULL}, the early stopping function is not triggered.
|
||||
If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
doesn't improve for \code{k} rounds.
|
||||
Setting this parameter engages the \code{\link{cb.early.stop}} callback.}
|
||||
|
||||
\item{early.stop.round}{An alternative of \code{early_stop_round}.}
|
||||
\item{maximize}{If \code{feval} and \code{early_stopping_rounds} are set,
|
||||
then this parameter must be set as well.
|
||||
When it is \code{TRUE}, it means the larger the evaluation score the better.
|
||||
This parameter is passed to the \code{\link{cb.early.stop}} callback.}
|
||||
|
||||
\item{maximize}{If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
\code{maximize=TRUE} means the larger the evaluation score the better.}
|
||||
\item{save_period}{when it is non-NULL, model is saved to disk after every \code{save_period} rounds,
|
||||
0 means save at the end. The saving is handled by the \code{\link{cb.save.model}} callback.}
|
||||
|
||||
\item{save_name}{the name or path for periodically saved model file.}
|
||||
|
||||
\item{xgb_model}{a previously built model to continue the trainig from.
|
||||
Could be either an object of class \code{xgb.Booster}, or its raw data, or the name of a
|
||||
file with a previously saved model.}
|
||||
|
||||
\item{callbacks}{a list of callback functions to perform various task during boosting.
|
||||
See \code{\link{callbacks}}. Some of the callbacks are automatically created depending on the
|
||||
parameters' values. User can provide either existing or their own callback methods in order
|
||||
to customize the training process.}
|
||||
|
||||
\item{...}{other parameters to pass to \code{params}.}
|
||||
|
||||
\item{label}{vector of response values. Should not be provided when data is
|
||||
a local data file name or an \code{xgb.DMatrix}.}
|
||||
|
||||
\item{missing}{by default is set to NA, which means that NA values should be considered as 'missing'
|
||||
by the algorithm. Sometimes, 0 or other extreme value might be used to represent missing values.
|
||||
This parameter is only used when input is a dense matrix.}
|
||||
|
||||
\item{weight}{a vector indicating the weight for each row of the input.}
|
||||
}
|
||||
\value{
|
||||
An object of class \code{xgb.Booster} with the following elements:
|
||||
\itemize{
|
||||
\item \code{handle} a handle (pointer) to the xgboost model in memory.
|
||||
\item \code{raw} a cached memory dump of the xgboost model saved as R's \code{raw} type.
|
||||
\item \code{niter} number of boosting iterations.
|
||||
\item \code{evaluation_log} evaluation history storead as a \code{data.table} with the
|
||||
first column corresponding to iteration number and the rest corresponding to evaluation
|
||||
metrics' values. It is created by the \code{\link{cb.evaluation.log}} callback.
|
||||
\item \code{call} a function call.
|
||||
\item \code{params} parameters that were passed to the xgboost library. Note that it does not
|
||||
capture parameters changed by the \code{\link{cb.reset.parameters}} callback.
|
||||
\item \code{callbacks} callback functions that were either automatically assigned or
|
||||
explicitely passed.
|
||||
\item \code{best_iteration} iteration number with the best evaluation metric value
|
||||
(only available with early stopping).
|
||||
\item \code{best_ntreelimit} the \code{ntreelimit} value corresponding to the best iteration,
|
||||
which could further be used in \code{predict} method
|
||||
(only available with early stopping).
|
||||
\item \code{best_score} the best evaluation metric value during early stopping.
|
||||
(only available with early stopping).
|
||||
}
|
||||
}
|
||||
\description{
|
||||
An advanced interface for training xgboost model. Look at \code{\link{xgboost}} function for a simpler interface.
|
||||
\code{xgb.train} is an advanced interface for training an xgboost model. The \code{xgboost} function provides a simpler interface.
|
||||
}
|
||||
\details{
|
||||
This is the training function for \code{xgboost}.
|
||||
These are the training functions for \code{xgboost}.
|
||||
|
||||
It supports advanced features such as \code{watchlist}, customized objective function (\code{feval}),
|
||||
therefore it is more flexible than \code{\link{xgboost}} function.
|
||||
The \code{xgb.train} interface supports advanced features such as \code{watchlist},
|
||||
customized objective and evaluation metric functions, therefore it is more flexible
|
||||
than the \code{\link{xgboost}} interface.
|
||||
|
||||
Parallelization is automatically enabled if \code{OpenMP} is present.
|
||||
Parallelization is automatically enabled if \code{OpenMP} is present.
|
||||
Number of threads can also be manually specified via \code{nthread} parameter.
|
||||
|
||||
\code{eval_metric} parameter (not listed above) is set automatically by Xgboost but can be overriden by parameter. Below is provided the list of different metric optimized by Xgboost to help you to understand how it works inside or to use them with the \code{watchlist} parameter.
|
||||
The evaluation metric is chosen automatically by Xgboost (according to the objective)
|
||||
when the \code{eval_metric} parameter is not provided.
|
||||
User may set one or several \code{eval_metric} parameters.
|
||||
Note that when using a customized metric, only this single metric can be used.
|
||||
The folloiwing is the list of built-in metrics for which Xgboost provides optimized implementation:
|
||||
\itemize{
|
||||
\item \code{rmse} root mean square error. \url{http://en.wikipedia.org/wiki/Root_mean_square_error}
|
||||
\item \code{logloss} negative log-likelihood. \url{http://en.wikipedia.org/wiki/Log-likelihood}
|
||||
\item \code{error} Binary classification error rate. It is calculated as \code{(wrong cases) / (all cases)}. For the predictions, the evaluation will regard the instances with prediction value larger than 0.5 as positive instances, and the others as negative instances.
|
||||
\item \code{merror} Multiclass classification error rate. It is calculated as \code{(wrong cases) / (all cases)}.
|
||||
\item \code{mlogloss} multiclass logloss. \url{https://www.kaggle.com/wiki/MultiClassLogLoss}
|
||||
\item \code{error} Binary classification error rate. It is calculated as \code{(# wrong cases) / (# all cases)}.
|
||||
By default, it uses the 0.5 threshold for predicted values to define negative and positive instances.
|
||||
Different threshold (e.g., 0.) could be specified as "error@0."
|
||||
\item \code{merror} Multiclass classification error rate. It is calculated as \code{(# wrong cases) / (# all cases)}.
|
||||
\item \code{auc} Area under the curve. \url{http://en.wikipedia.org/wiki/Receiver_operating_characteristic#'Area_under_curve} for ranking evaluation.
|
||||
\item \code{ndcg} Normalized Discounted Cumulative Gain (for ranking task). \url{http://en.wikipedia.org/wiki/NDCG}
|
||||
}
|
||||
|
||||
Full list of parameters is available in the Wiki \url{https://github.com/dmlc/xgboost/wiki/Parameters}.
|
||||
|
||||
This function only accepts an \code{\link{xgb.DMatrix}} object as the input.
|
||||
The following callbacks are automatically created when certain parameters are set:
|
||||
\itemize{
|
||||
\item \code{cb.print.evaluation} is turned on when \code{verbose > 0};
|
||||
and the \code{print_every_n} parameter is passed to it.
|
||||
\item \code{cb.evaluation.log} is on when \code{verbose > 0} and \code{watchlist} is present.
|
||||
\item \code{cb.early.stop}: when \code{early_stopping_rounds} is set.
|
||||
\item \code{cb.save.model}: when \code{save_period > 0} is set.
|
||||
}
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
|
||||
dtrain <- xgb.DMatrix(agaricus.train$data, label = agaricus.train$label)
|
||||
dtest <- dtrain
|
||||
dtest <- xgb.DMatrix(agaricus.test$data, label = agaricus.test$label)
|
||||
watchlist <- list(eval = dtest, train = dtrain)
|
||||
param <- list(max.depth = 2, eta = 1, silent = 1)
|
||||
|
||||
## A simple xgb.train example:
|
||||
param <- list(max_depth = 2, eta = 1, silent = 1,
|
||||
objective = "binary:logistic", eval_metric = "auc")
|
||||
bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist)
|
||||
|
||||
## An xgb.train example where custom objective and evaluation metric are used:
|
||||
logregobj <- function(preds, dtrain) {
|
||||
labels <- getinfo(dtrain, "label")
|
||||
preds <- 1/(1 + exp(-preds))
|
||||
@@ -135,6 +217,29 @@ evalerror <- function(preds, dtrain) {
|
||||
err <- as.numeric(sum(labels != (preds > 0)))/length(labels)
|
||||
return(list(metric = "error", value = err))
|
||||
}
|
||||
bst <- xgb.train(param, dtrain, nthread = 2, nround = 2, watchlist, logregobj, evalerror)
|
||||
bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist)
|
||||
|
||||
## An xgb.train example of using variable learning rates at each iteration:
|
||||
my_etas <- list(eta = c(0.5, 0.1))
|
||||
bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist,
|
||||
callbacks = list(cb.reset.parameters(my_etas)))
|
||||
|
||||
## Explicit use of the cb.evaluation.log callback allows to run
|
||||
## xgb.train silently but still store the evaluation results:
|
||||
bst <- xgb.train(param, dtrain, nthread = 2, nrounds = 2, watchlist,
|
||||
verbose = 0, callbacks = list(cb.evaluation.log()))
|
||||
print(bst$evaluation_log)
|
||||
|
||||
## An 'xgboost' interface example:
|
||||
bst <- xgboost(data = agaricus.train$data, label = agaricus.train$label,
|
||||
max_depth = 2, eta = 1, nthread = 2, nrounds = 2,
|
||||
objective = "binary:logistic")
|
||||
pred <- predict(bst, agaricus.test$data)
|
||||
|
||||
}
|
||||
\seealso{
|
||||
\code{\link{callbacks}},
|
||||
\code{\link{predict.xgb.Booster}},
|
||||
\code{\link{xgb.cv}}
|
||||
}
|
||||
|
||||
|
||||
17
R-package/man/xgboost-deprecated.Rd
Normal file
17
R-package/man/xgboost-deprecated.Rd
Normal file
@@ -0,0 +1,17 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/utils.R
|
||||
\name{xgboost-deprecated}
|
||||
\alias{xgboost-deprecated}
|
||||
\title{Deprecation notices.}
|
||||
\description{
|
||||
At this time, some of the parameter names were changed in order to make the code style more uniform.
|
||||
The deprecated parameters would be removed in the next release.
|
||||
}
|
||||
\details{
|
||||
To see all the current deprecated and new parameters, check the \code{xgboost:::depr_par_lut} table.
|
||||
|
||||
A deprecation warning is shown when any of the deprecated parameters is used in a call.
|
||||
An additional warning is shown when there was a partial match to a deprecated parameter
|
||||
(as R is able to partially match parameter names).
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
% Generated by roxygen2 (4.1.1): do not edit by hand
|
||||
% Please edit documentation in R/xgboost.R
|
||||
\name{xgboost}
|
||||
\alias{xgboost}
|
||||
\title{eXtreme Gradient Boosting (Tree) library}
|
||||
\usage{
|
||||
xgboost(data = NULL, label = NULL, missing = NULL, params = list(),
|
||||
nrounds, verbose = 1, printEveryN=1L, early_stop_round = NULL, early.stop.round = NULL,
|
||||
maximize = NULL, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{data}{takes \code{matrix}, \code{dgCMatrix}, local data file or
|
||||
\code{xgb.DMatrix}.}
|
||||
|
||||
\item{label}{the response variable. User should not set this field,
|
||||
if data is local data file or \code{xgb.DMatrix}.}
|
||||
|
||||
\item{missing}{Missing is only used when input is dense matrix, pick a float
|
||||
value that represents missing value. Sometimes a data use 0 or other extreme value to represents missing values.}
|
||||
|
||||
\item{params}{the list of parameters.
|
||||
|
||||
Commonly used ones are:
|
||||
\itemize{
|
||||
\item \code{objective} objective function, common ones are
|
||||
\itemize{
|
||||
\item \code{reg:linear} linear regression
|
||||
\item \code{binary:logistic} logistic regression for classification
|
||||
}
|
||||
\item \code{eta} step size of each boosting step
|
||||
\item \code{max.depth} maximum depth of the tree
|
||||
\item \code{nthread} number of thread used in training, if not set, all threads are used
|
||||
}
|
||||
|
||||
Look at \code{\link{xgb.train}} for a more complete list of parameters or \url{https://github.com/dmlc/xgboost/wiki/Parameters} for the full list.
|
||||
|
||||
See also \code{demo/} for walkthrough example in R.}
|
||||
|
||||
\item{nrounds}{the max number of iterations}
|
||||
|
||||
\item{verbose}{If 0, xgboost will stay silent. If 1, xgboost will print
|
||||
information of performance. If 2, xgboost will print information of both
|
||||
performance and construction progress information}
|
||||
|
||||
\item{printEveryN}{Print every N progress messages when \code{verbose>0}. Default is 1 which means all messages are printed.}
|
||||
|
||||
\item{early_stop_round}{If \code{NULL}, the early stopping function is not triggered.
|
||||
If set to an integer \code{k}, training with a validation set will stop if the performance
|
||||
keeps getting worse consecutively for \code{k} rounds.}
|
||||
|
||||
\item{early.stop.round}{An alternative of \code{early_stop_round}.}
|
||||
|
||||
\item{maximize}{If \code{feval} and \code{early_stop_round} are set, then \code{maximize} must be set as well.
|
||||
\code{maximize=TRUE} means the larger the evaluation score the better.}
|
||||
|
||||
\item{...}{other parameters to pass to \code{params}.}
|
||||
}
|
||||
\description{
|
||||
A simple interface for training xgboost model. Look at \code{\link{xgb.train}} function for a more advanced interface.
|
||||
}
|
||||
\details{
|
||||
This is the modeling function for Xgboost.
|
||||
|
||||
Parallelization is automatically enabled if \code{OpenMP} is present.
|
||||
|
||||
Number of threads can also be manually specified via \code{nthread} parameter.
|
||||
}
|
||||
\examples{
|
||||
data(agaricus.train, package='xgboost')
|
||||
data(agaricus.test, package='xgboost')
|
||||
train <- agaricus.train
|
||||
test <- agaricus.test
|
||||
bst <- xgboost(data = train$data, label = train$label, max.depth = 2,
|
||||
eta = 1, nthread = 2, nround = 2, objective = "binary:logistic")
|
||||
pred <- predict(bst, test$data)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
# package root
|
||||
PKGROOT=../../
|
||||
ENABLE_STD_THREAD=1
|
||||
# _*_ mode: Makefile; _*_
|
||||
PKG_CPPFLAGS= -DXGBOOST_CUSTOMIZE_MSG_ -DXGBOOST_CUSTOMIZE_PRNG_ -DXGBOOST_STRICT_CXX98_ -DRABIT_CUSTOMIZE_MSG_ -DRABIT_STRICT_CXX98_ -I$(PKGROOT)
|
||||
|
||||
CXX_STD = CXX11
|
||||
|
||||
XGB_RFLAGS = -DXGBOOST_STRICT_R_MODE=1 -DDMLC_LOG_BEFORE_THROW=0\
|
||||
-DDMLC_ENABLE_STD_THREAD=$(ENABLE_STD_THREAD) -DDMLC_DISABLE_STDIN=1\
|
||||
-DDMLC_LOG_CUSTOMIZE=1 -DXGBOOST_CUSTOMIZE_LOGGER=1\
|
||||
-DRABIT_CUSTOMIZE_MSG_ -DRABIT_STRICT_CXX98_
|
||||
|
||||
PKG_CPPFLAGS= -I$(PKGROOT)/include -I$(PKGROOT)/dmlc-core/include -I$(PKGROOT)/rabit/include -I$(PKGROOT) $(XGB_RFLAGS)
|
||||
PKG_CXXFLAGS= $(SHLIB_OPENMP_CFLAGS) $(SHLIB_PTHREAD_FLAGS)
|
||||
PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) $(SHLIB_PTHREAD_FLAGS)
|
||||
OBJECTS= xgboost_R.o xgboost_assert.o $(PKGROOT)/wrapper/xgboost_wrapper.o $(PKGROOT)/src/io/io.o $(PKGROOT)/src/gbm/gbm.o $(PKGROOT)/src/tree/updater.o $(PKGROOT)/subtree/rabit/src/engine_empty.o $(PKGROOT)/src/io/dmlc_simple.o
|
||||
|
||||
OBJECTS= ./xgboost_R.o ./xgboost_custom.o ./xgboost_assert.o\
|
||||
$(PKGROOT)/amalgamation/xgboost-all0.o $(PKGROOT)/amalgamation/dmlc-minimum0.o\
|
||||
$(PKGROOT)/rabit/src/engine_empty.o $(PKGROOT)/rabit/src/c_api.o
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# package root
|
||||
PKGROOT=./
|
||||
ENABLE_STD_THREAD=0
|
||||
# _*_ mode: Makefile; _*_
|
||||
|
||||
# This file is only used for windows compilation from github
|
||||
@@ -9,11 +10,23 @@ all: $(SHLIB)
|
||||
$(SHLIB): xgblib
|
||||
xgblib:
|
||||
cp -r ../../src .
|
||||
cp -r ../../wrapper .
|
||||
cp -r ../../subtree .
|
||||
cp -r ../../rabit .
|
||||
cp -r ../../dmlc-core .
|
||||
cp -r ../../include .
|
||||
cp -r ../../amalgamation .
|
||||
|
||||
PKG_CPPFLAGS= -DXGBOOST_CUSTOMIZE_MSG_ -DXGBOOST_CUSTOMIZE_PRNG_ -DXGBOOST_STRICT_CXX98_ -DRABIT_CUSTOMIZE_MSG_ -DRABIT_STRICT_CXX98_ -I$(PKGROOT) -I../..
|
||||
CXX_STD = CXX11
|
||||
|
||||
XGB_RFLAGS = -DXGBOOST_STRICT_R_MODE=1 -DDMLC_LOG_BEFORE_THROW=0\
|
||||
-DDMLC_ENABLE_STD_THREAD=$(ENABLE_STD_THREAD) -DDMLC_DISABLE_STDIN=1\
|
||||
-DDMLC_LOG_CUSTOMIZE=1 -DXGBOOST_CUSTOMIZE_LOGGER=1\
|
||||
-DRABIT_CUSTOMIZE_MSG_ -DRABIT_STRICT_CXX98_
|
||||
|
||||
PKG_CPPFLAGS= -I$(PKGROOT)/include -I$(PKGROOT)/dmlc-core/include -I$(PKGROOT)/rabit/include -I$(PKGROOT) $(XGB_RFLAGS)
|
||||
PKG_CXXFLAGS= $(SHLIB_OPENMP_CFLAGS) $(SHLIB_PTHREAD_FLAGS)
|
||||
PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) $(SHLIB_PTHREAD_FLAGS)
|
||||
OBJECTS= xgboost_R.o xgboost_assert.o $(PKGROOT)/wrapper/xgboost_wrapper.o $(PKGROOT)/src/io/io.o $(PKGROOT)/src/gbm/gbm.o $(PKGROOT)/src/tree/updater.o $(PKGROOT)/subtree/rabit/src/engine_empty.o $(PKGROOT)/src/io/dmlc_simple.o
|
||||
OBJECTS= ./xgboost_R.o ./xgboost_custom.o ./xgboost_assert.o\
|
||||
$(PKGROOT)/amalgamation/xgboost-all0.o $(PKGROOT)/amalgamation/dmlc-minimum0.o\
|
||||
$(PKGROOT)/rabit/src/engine_empty.o $(PKGROOT)/rabit/src/c_api.o
|
||||
|
||||
$(OBJECTS) : xgblib
|
||||
|
||||
419
R-package/src/xgboost_R.cc
Normal file
419
R-package/src/xgboost_R.cc
Normal file
@@ -0,0 +1,419 @@
|
||||
// Copyright (c) 2014 by Contributors
|
||||
#include <dmlc/logging.h>
|
||||
#include <dmlc/omp.h>
|
||||
#include <xgboost/c_api.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include "./xgboost_R.h"
|
||||
|
||||
/*!
|
||||
* \brief macro to annotate begin of api
|
||||
*/
|
||||
#define R_API_BEGIN() \
|
||||
GetRNGstate(); \
|
||||
try {
|
||||
/*!
|
||||
* \brief macro to annotate end of api
|
||||
*/
|
||||
#define R_API_END() \
|
||||
} catch(dmlc::Error& e) { \
|
||||
PutRNGstate(); \
|
||||
error(e.what()); \
|
||||
} \
|
||||
PutRNGstate();
|
||||
|
||||
/*!
|
||||
* \brief macro to check the call.
|
||||
*/
|
||||
#define CHECK_CALL(x) \
|
||||
if ((x) != 0) { \
|
||||
error(XGBGetLastError()); \
|
||||
}
|
||||
|
||||
|
||||
using namespace dmlc;
|
||||
|
||||
SEXP XGCheckNullPtr_R(SEXP handle) {
|
||||
return ScalarLogical(R_ExternalPtrAddr(handle) == NULL);
|
||||
}
|
||||
|
||||
void _DMatrixFinalizer(SEXP ext) {
|
||||
R_API_BEGIN();
|
||||
if (R_ExternalPtrAddr(ext) == NULL) return;
|
||||
CHECK_CALL(XGDMatrixFree(R_ExternalPtrAddr(ext)));
|
||||
R_ClearExternalPtr(ext);
|
||||
R_API_END();
|
||||
}
|
||||
|
||||
SEXP XGDMatrixCreateFromFile_R(SEXP fname, SEXP silent) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
DMatrixHandle handle;
|
||||
CHECK_CALL(XGDMatrixCreateFromFile(CHAR(asChar(fname)), asInteger(silent), &handle));
|
||||
ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixCreateFromMat_R(SEXP mat,
|
||||
SEXP missing) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
SEXP dim = getAttrib(mat, R_DimSymbol);
|
||||
size_t nrow = static_cast<size_t>(INTEGER(dim)[0]);
|
||||
size_t ncol = static_cast<size_t>(INTEGER(dim)[1]);
|
||||
double *din = REAL(mat);
|
||||
std::vector<float> data(nrow * ncol);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (omp_ulong i = 0; i < nrow; ++i) {
|
||||
for (size_t j = 0; j < ncol; ++j) {
|
||||
data[i * ncol +j] = din[i + nrow * j];
|
||||
}
|
||||
}
|
||||
DMatrixHandle handle;
|
||||
CHECK_CALL(XGDMatrixCreateFromMat(BeginPtr(data), nrow, ncol, asReal(missing), &handle));
|
||||
ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixCreateFromCSC_R(SEXP indptr,
|
||||
SEXP indices,
|
||||
SEXP data) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
const int *p_indptr = INTEGER(indptr);
|
||||
const int *p_indices = INTEGER(indices);
|
||||
const double *p_data = REAL(data);
|
||||
int nindptr = length(indptr);
|
||||
int ndata = length(data);
|
||||
std::vector<bst_ulong> col_ptr_(nindptr);
|
||||
std::vector<unsigned> indices_(ndata);
|
||||
std::vector<float> data_(ndata);
|
||||
|
||||
for (int i = 0; i < nindptr; ++i) {
|
||||
col_ptr_[i] = static_cast<bst_ulong>(p_indptr[i]);
|
||||
}
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < ndata; ++i) {
|
||||
indices_[i] = static_cast<unsigned>(p_indices[i]);
|
||||
data_[i] = static_cast<float>(p_data[i]);
|
||||
}
|
||||
DMatrixHandle handle;
|
||||
CHECK_CALL(XGDMatrixCreateFromCSC(BeginPtr(col_ptr_), BeginPtr(indices_),
|
||||
BeginPtr(data_), nindptr, ndata,
|
||||
&handle));
|
||||
ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixSliceDMatrix_R(SEXP handle, SEXP idxset) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
int len = length(idxset);
|
||||
std::vector<int> idxvec(len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
idxvec[i] = INTEGER(idxset)[i] - 1;
|
||||
}
|
||||
DMatrixHandle res;
|
||||
CHECK_CALL(XGDMatrixSliceDMatrix(R_ExternalPtrAddr(handle),
|
||||
BeginPtr(idxvec), len,
|
||||
&res));
|
||||
ret = PROTECT(R_MakeExternalPtr(res, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixSaveBinary_R(SEXP handle, SEXP fname, SEXP silent) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGDMatrixSaveBinary(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(fname)),
|
||||
asInteger(silent)));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixSetInfo_R(SEXP handle, SEXP field, SEXP array) {
|
||||
R_API_BEGIN();
|
||||
int len = length(array);
|
||||
const char *name = CHAR(asChar(field));
|
||||
if (!strcmp("group", name)) {
|
||||
std::vector<unsigned> vec(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec[i] = static_cast<unsigned>(INTEGER(array)[i]);
|
||||
}
|
||||
CHECK_CALL(XGDMatrixSetGroup(R_ExternalPtrAddr(handle), BeginPtr(vec), len));
|
||||
} else {
|
||||
std::vector<float> vec(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec[i] = REAL(array)[i];
|
||||
}
|
||||
CHECK_CALL(XGDMatrixSetFloatInfo(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(field)),
|
||||
BeginPtr(vec), len));
|
||||
}
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixGetInfo_R(SEXP handle, SEXP field) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
bst_ulong olen;
|
||||
const float *res;
|
||||
CHECK_CALL(XGDMatrixGetFloatInfo(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(field)),
|
||||
&olen,
|
||||
&res));
|
||||
ret = PROTECT(allocVector(REALSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
REAL(ret)[i] = res[i];
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGDMatrixNumRow_R(SEXP handle) {
|
||||
bst_ulong nrow;
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGDMatrixNumRow(R_ExternalPtrAddr(handle), &nrow));
|
||||
R_API_END();
|
||||
return ScalarInteger(static_cast<int>(nrow));
|
||||
}
|
||||
|
||||
SEXP XGDMatrixNumCol_R(SEXP handle) {
|
||||
bst_ulong ncol;
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGDMatrixNumCol(R_ExternalPtrAddr(handle), &ncol));
|
||||
R_API_END();
|
||||
return ScalarInteger(static_cast<int>(ncol));
|
||||
}
|
||||
|
||||
// functions related to booster
|
||||
void _BoosterFinalizer(SEXP ext) {
|
||||
if (R_ExternalPtrAddr(ext) == NULL) return;
|
||||
CHECK_CALL(XGBoosterFree(R_ExternalPtrAddr(ext)));
|
||||
R_ClearExternalPtr(ext);
|
||||
}
|
||||
|
||||
SEXP XGBoosterCreate_R(SEXP dmats) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
int len = length(dmats);
|
||||
std::vector<void*> dvec;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
dvec.push_back(R_ExternalPtrAddr(VECTOR_ELT(dmats, i)));
|
||||
}
|
||||
BoosterHandle handle;
|
||||
CHECK_CALL(XGBoosterCreate(BeginPtr(dvec), dvec.size(), &handle));
|
||||
ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _BoosterFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGBoosterSetParam_R(SEXP handle, SEXP name, SEXP val) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGBoosterSetParam(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(name)),
|
||||
CHAR(asChar(val))));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterUpdateOneIter_R(SEXP handle, SEXP iter, SEXP dtrain) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGBoosterUpdateOneIter(R_ExternalPtrAddr(handle),
|
||||
asInteger(iter),
|
||||
R_ExternalPtrAddr(dtrain)));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterBoostOneIter_R(SEXP handle, SEXP dtrain, SEXP grad, SEXP hess) {
|
||||
R_API_BEGIN();
|
||||
CHECK_EQ(length(grad), length(hess))
|
||||
<< "gradient and hess must have same length";
|
||||
int len = length(grad);
|
||||
std::vector<float> tgrad(len), thess(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int j = 0; j < len; ++j) {
|
||||
tgrad[j] = REAL(grad)[j];
|
||||
thess[j] = REAL(hess)[j];
|
||||
}
|
||||
CHECK_CALL(XGBoosterBoostOneIter(R_ExternalPtrAddr(handle),
|
||||
R_ExternalPtrAddr(dtrain),
|
||||
BeginPtr(tgrad), BeginPtr(thess),
|
||||
len));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterEvalOneIter_R(SEXP handle, SEXP iter, SEXP dmats, SEXP evnames) {
|
||||
const char *ret;
|
||||
R_API_BEGIN();
|
||||
CHECK_EQ(length(dmats), length(evnames))
|
||||
<< "dmats and evnams must have same length";
|
||||
int len = length(dmats);
|
||||
std::vector<void*> vec_dmats;
|
||||
std::vector<std::string> vec_names;
|
||||
std::vector<const char*> vec_sptr;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec_dmats.push_back(R_ExternalPtrAddr(VECTOR_ELT(dmats, i)));
|
||||
vec_names.push_back(std::string(CHAR(asChar(VECTOR_ELT(evnames, i)))));
|
||||
}
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec_sptr.push_back(vec_names[i].c_str());
|
||||
}
|
||||
CHECK_CALL(XGBoosterEvalOneIter(R_ExternalPtrAddr(handle),
|
||||
asInteger(iter),
|
||||
BeginPtr(vec_dmats),
|
||||
BeginPtr(vec_sptr),
|
||||
len, &ret));
|
||||
R_API_END();
|
||||
return mkString(ret);
|
||||
}
|
||||
|
||||
SEXP XGBoosterPredict_R(SEXP handle, SEXP dmat, SEXP option_mask, SEXP ntree_limit) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
bst_ulong olen;
|
||||
const float *res;
|
||||
CHECK_CALL(XGBoosterPredict(R_ExternalPtrAddr(handle),
|
||||
R_ExternalPtrAddr(dmat),
|
||||
asInteger(option_mask),
|
||||
asInteger(ntree_limit),
|
||||
&olen, &res));
|
||||
ret = PROTECT(allocVector(REALSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
REAL(ret)[i] = res[i];
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGBoosterLoadModel_R(SEXP handle, SEXP fname) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGBoosterLoadModel(R_ExternalPtrAddr(handle), CHAR(asChar(fname))));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterSaveModel_R(SEXP handle, SEXP fname) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGBoosterSaveModel(R_ExternalPtrAddr(handle), CHAR(asChar(fname))));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterLoadModelFromRaw_R(SEXP handle, SEXP raw) {
|
||||
R_API_BEGIN();
|
||||
CHECK_CALL(XGBoosterLoadModelFromBuffer(R_ExternalPtrAddr(handle),
|
||||
RAW(raw),
|
||||
length(raw)));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterModelToRaw_R(SEXP handle) {
|
||||
SEXP ret;
|
||||
R_API_BEGIN();
|
||||
bst_ulong olen;
|
||||
const char *raw;
|
||||
CHECK_CALL(XGBoosterGetModelRaw(R_ExternalPtrAddr(handle), &olen, &raw));
|
||||
ret = PROTECT(allocVector(RAWSXP, olen));
|
||||
if (olen != 0) {
|
||||
memcpy(RAW(ret), raw, olen);
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEXP XGBoosterDumpModel_R(SEXP handle, SEXP fmap, SEXP with_stats) {
|
||||
SEXP out;
|
||||
R_API_BEGIN();
|
||||
bst_ulong olen;
|
||||
const char **res;
|
||||
CHECK_CALL(XGBoosterDumpModel(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(fmap)),
|
||||
asInteger(with_stats),
|
||||
&olen, &res));
|
||||
out = PROTECT(allocVector(STRSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
std::stringstream stream;
|
||||
stream << "booster[" << i <<"]\n" << res[i];
|
||||
SET_STRING_ELT(out, i, mkChar(stream.str().c_str()));
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return out;
|
||||
}
|
||||
|
||||
SEXP XGBoosterGetAttr_R(SEXP handle, SEXP name) {
|
||||
SEXP out;
|
||||
R_API_BEGIN();
|
||||
int success;
|
||||
const char *val;
|
||||
CHECK_CALL(XGBoosterGetAttr(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(name)),
|
||||
&val,
|
||||
&success));
|
||||
if (success) {
|
||||
out = PROTECT(allocVector(STRSXP, 1));
|
||||
SET_STRING_ELT(out, 0, mkChar(val));
|
||||
} else {
|
||||
out = PROTECT(R_NilValue);
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return out;
|
||||
}
|
||||
|
||||
SEXP XGBoosterSetAttr_R(SEXP handle, SEXP name, SEXP val) {
|
||||
R_API_BEGIN();
|
||||
const char *v = isNull(val) ? nullptr : CHAR(asChar(val));
|
||||
CHECK_CALL(XGBoosterSetAttr(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(name)), v));
|
||||
R_API_END();
|
||||
return R_NilValue;
|
||||
}
|
||||
|
||||
SEXP XGBoosterGetAttrNames_R(SEXP handle) {
|
||||
SEXP out;
|
||||
R_API_BEGIN();
|
||||
bst_ulong len;
|
||||
const char **res;
|
||||
CHECK_CALL(XGBoosterGetAttrNames(R_ExternalPtrAddr(handle),
|
||||
&len, &res));
|
||||
if (len > 0) {
|
||||
out = PROTECT(allocVector(STRSXP, len));
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
SET_STRING_ELT(out, i, mkChar(res[i]));
|
||||
}
|
||||
} else {
|
||||
out = PROTECT(R_NilValue);
|
||||
}
|
||||
UNPROTECT(1);
|
||||
R_API_END();
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1,322 +0,0 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include "wrapper/xgboost_wrapper.h"
|
||||
#include "src/utils/utils.h"
|
||||
#include "src/utils/omp.h"
|
||||
#include "xgboost_R.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xgboost;
|
||||
|
||||
extern "C" {
|
||||
void XGBoostAssert_R(int exp, const char *fmt, ...);
|
||||
void XGBoostCheck_R(int exp, const char *fmt, ...);
|
||||
int XGBoostSPrintf_R(char *buf, size_t size, const char *fmt, ...);
|
||||
}
|
||||
|
||||
// implements error handling
|
||||
namespace xgboost {
|
||||
namespace utils {
|
||||
extern "C" {
|
||||
void (*Printf)(const char *fmt, ...) = Rprintf;
|
||||
int (*SPrintf)(char *buf, size_t size, const char *fmt, ...) = XGBoostSPrintf_R;
|
||||
void (*Assert)(int exp, const char *fmt, ...) = XGBoostAssert_R;
|
||||
void (*Check)(int exp, const char *fmt, ...) = XGBoostCheck_R;
|
||||
void (*Error)(const char *fmt, ...) = error;
|
||||
}
|
||||
bool CheckNAN(double v) {
|
||||
return ISNAN(v);
|
||||
}
|
||||
bool LogGamma(double v) {
|
||||
return lgammafn(v);
|
||||
}
|
||||
} // namespace utils
|
||||
|
||||
namespace random {
|
||||
void Seed(unsigned seed) {
|
||||
warning("parameter seed is ignored, please set random seed using set.seed");
|
||||
}
|
||||
double Uniform(void) {
|
||||
return unif_rand();
|
||||
}
|
||||
double Normal(void) {
|
||||
return norm_rand();
|
||||
}
|
||||
} // namespace random
|
||||
} // namespace xgboost
|
||||
|
||||
// call before wrapper starts
|
||||
inline void _WrapperBegin(void) {
|
||||
GetRNGstate();
|
||||
}
|
||||
// call after wrapper starts
|
||||
inline void _WrapperEnd(void) {
|
||||
PutRNGstate();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
SEXP XGCheckNullPtr_R(SEXP handle) {
|
||||
return ScalarLogical(R_ExternalPtrAddr(handle) == NULL);
|
||||
}
|
||||
void _DMatrixFinalizer(SEXP ext) {
|
||||
if (R_ExternalPtrAddr(ext) == NULL) return;
|
||||
XGDMatrixFree(R_ExternalPtrAddr(ext));
|
||||
R_ClearExternalPtr(ext);
|
||||
}
|
||||
SEXP XGDMatrixCreateFromFile_R(SEXP fname, SEXP silent) {
|
||||
_WrapperBegin();
|
||||
void *handle = XGDMatrixCreateFromFile(CHAR(asChar(fname)), asInteger(silent));
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
SEXP XGDMatrixCreateFromMat_R(SEXP mat,
|
||||
SEXP missing) {
|
||||
_WrapperBegin();
|
||||
SEXP dim = getAttrib(mat, R_DimSymbol);
|
||||
size_t nrow = static_cast<size_t>(INTEGER(dim)[0]);
|
||||
size_t ncol = static_cast<size_t>(INTEGER(dim)[1]);
|
||||
double *din = REAL(mat);
|
||||
std::vector<float> data(nrow * ncol);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (bst_omp_uint i = 0; i < nrow; ++i) {
|
||||
for (size_t j = 0; j < ncol; ++j) {
|
||||
data[i * ncol +j] = din[i + nrow * j];
|
||||
}
|
||||
}
|
||||
void *handle = XGDMatrixCreateFromMat(BeginPtr(data), nrow, ncol, asReal(missing));
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
SEXP XGDMatrixCreateFromCSC_R(SEXP indptr,
|
||||
SEXP indices,
|
||||
SEXP data) {
|
||||
_WrapperBegin();
|
||||
const int *p_indptr = INTEGER(indptr);
|
||||
const int *p_indices = INTEGER(indices);
|
||||
const double *p_data = REAL(data);
|
||||
int nindptr = length(indptr);
|
||||
int ndata = length(data);
|
||||
std::vector<bst_ulong> col_ptr_(nindptr);
|
||||
std::vector<unsigned> indices_(ndata);
|
||||
std::vector<float> data_(ndata);
|
||||
|
||||
for (int i = 0; i < nindptr; ++i) {
|
||||
col_ptr_[i] = static_cast<bst_ulong>(p_indptr[i]);
|
||||
}
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < ndata; ++i) {
|
||||
indices_[i] = static_cast<unsigned>(p_indices[i]);
|
||||
data_[i] = static_cast<float>(p_data[i]);
|
||||
}
|
||||
void *handle = XGDMatrixCreateFromCSC(BeginPtr(col_ptr_), BeginPtr(indices_),
|
||||
BeginPtr(data_), nindptr, ndata);
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
SEXP XGDMatrixSliceDMatrix_R(SEXP handle, SEXP idxset) {
|
||||
_WrapperBegin();
|
||||
int len = length(idxset);
|
||||
std::vector<int> idxvec(len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
idxvec[i] = INTEGER(idxset)[i] - 1;
|
||||
}
|
||||
void *res = XGDMatrixSliceDMatrix(R_ExternalPtrAddr(handle), BeginPtr(idxvec), len);
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(R_MakeExternalPtr(res, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _DMatrixFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
void XGDMatrixSaveBinary_R(SEXP handle, SEXP fname, SEXP silent) {
|
||||
_WrapperBegin();
|
||||
XGDMatrixSaveBinary(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(fname)), asInteger(silent));
|
||||
_WrapperEnd();
|
||||
}
|
||||
void XGDMatrixSetInfo_R(SEXP handle, SEXP field, SEXP array) {
|
||||
_WrapperBegin();
|
||||
int len = length(array);
|
||||
const char *name = CHAR(asChar(field));
|
||||
if (!strcmp("group", name)) {
|
||||
std::vector<unsigned> vec(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec[i] = static_cast<unsigned>(INTEGER(array)[i]);
|
||||
}
|
||||
XGDMatrixSetGroup(R_ExternalPtrAddr(handle), BeginPtr(vec), len);
|
||||
} else {
|
||||
std::vector<float> vec(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec[i] = REAL(array)[i];
|
||||
}
|
||||
XGDMatrixSetFloatInfo(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(field)),
|
||||
BeginPtr(vec), len);
|
||||
}
|
||||
_WrapperEnd();
|
||||
}
|
||||
SEXP XGDMatrixGetInfo_R(SEXP handle, SEXP field) {
|
||||
_WrapperBegin();
|
||||
bst_ulong olen;
|
||||
const float *res = XGDMatrixGetFloatInfo(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(field)), &olen);
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(allocVector(REALSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
REAL(ret)[i] = res[i];
|
||||
}
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
SEXP XGDMatrixNumRow_R(SEXP handle) {
|
||||
bst_ulong nrow = XGDMatrixNumRow(R_ExternalPtrAddr(handle));
|
||||
return ScalarInteger(static_cast<int>(nrow));
|
||||
}
|
||||
// functions related to booster
|
||||
void _BoosterFinalizer(SEXP ext) {
|
||||
if (R_ExternalPtrAddr(ext) == NULL) return;
|
||||
XGBoosterFree(R_ExternalPtrAddr(ext));
|
||||
R_ClearExternalPtr(ext);
|
||||
}
|
||||
SEXP XGBoosterCreate_R(SEXP dmats) {
|
||||
_WrapperBegin();
|
||||
int len = length(dmats);
|
||||
std::vector<void*> dvec;
|
||||
for (int i = 0; i < len; ++i){
|
||||
dvec.push_back(R_ExternalPtrAddr(VECTOR_ELT(dmats, i)));
|
||||
}
|
||||
void *handle = XGBoosterCreate(BeginPtr(dvec), dvec.size());
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(R_MakeExternalPtr(handle, R_NilValue, R_NilValue));
|
||||
R_RegisterCFinalizerEx(ret, _BoosterFinalizer, TRUE);
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
void XGBoosterSetParam_R(SEXP handle, SEXP name, SEXP val) {
|
||||
_WrapperBegin();
|
||||
XGBoosterSetParam(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(name)),
|
||||
CHAR(asChar(val)));
|
||||
_WrapperEnd();
|
||||
}
|
||||
void XGBoosterUpdateOneIter_R(SEXP handle, SEXP iter, SEXP dtrain) {
|
||||
_WrapperBegin();
|
||||
XGBoosterUpdateOneIter(R_ExternalPtrAddr(handle),
|
||||
asInteger(iter),
|
||||
R_ExternalPtrAddr(dtrain));
|
||||
_WrapperEnd();
|
||||
}
|
||||
void XGBoosterBoostOneIter_R(SEXP handle, SEXP dtrain, SEXP grad, SEXP hess) {
|
||||
_WrapperBegin();
|
||||
utils::Check(length(grad) == length(hess), "gradient and hess must have same length");
|
||||
int len = length(grad);
|
||||
std::vector<float> tgrad(len), thess(len);
|
||||
#pragma omp parallel for schedule(static)
|
||||
for (int j = 0; j < len; ++j) {
|
||||
tgrad[j] = REAL(grad)[j];
|
||||
thess[j] = REAL(hess)[j];
|
||||
}
|
||||
XGBoosterBoostOneIter(R_ExternalPtrAddr(handle),
|
||||
R_ExternalPtrAddr(dtrain),
|
||||
BeginPtr(tgrad), BeginPtr(thess), len);
|
||||
_WrapperEnd();
|
||||
}
|
||||
SEXP XGBoosterEvalOneIter_R(SEXP handle, SEXP iter, SEXP dmats, SEXP evnames) {
|
||||
_WrapperBegin();
|
||||
utils::Check(length(dmats) == length(evnames), "dmats and evnams must have same length");
|
||||
int len = length(dmats);
|
||||
std::vector<void*> vec_dmats;
|
||||
std::vector<std::string> vec_names;
|
||||
std::vector<const char*> vec_sptr;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec_dmats.push_back(R_ExternalPtrAddr(VECTOR_ELT(dmats, i)));
|
||||
vec_names.push_back(std::string(CHAR(asChar(VECTOR_ELT(evnames, i)))));
|
||||
}
|
||||
for (int i = 0; i < len; ++i) {
|
||||
vec_sptr.push_back(vec_names[i].c_str());
|
||||
}
|
||||
const char *ret =
|
||||
XGBoosterEvalOneIter(R_ExternalPtrAddr(handle),
|
||||
asInteger(iter),
|
||||
BeginPtr(vec_dmats), BeginPtr(vec_sptr), len);
|
||||
_WrapperEnd();
|
||||
return mkString(ret);
|
||||
}
|
||||
SEXP XGBoosterPredict_R(SEXP handle, SEXP dmat, SEXP option_mask, SEXP ntree_limit) {
|
||||
_WrapperBegin();
|
||||
bst_ulong olen;
|
||||
const float *res = XGBoosterPredict(R_ExternalPtrAddr(handle),
|
||||
R_ExternalPtrAddr(dmat),
|
||||
asInteger(option_mask),
|
||||
asInteger(ntree_limit),
|
||||
&olen);
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(allocVector(REALSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
REAL(ret)[i] = res[i];
|
||||
}
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
void XGBoosterLoadModel_R(SEXP handle, SEXP fname) {
|
||||
_WrapperBegin();
|
||||
XGBoosterLoadModel(R_ExternalPtrAddr(handle), CHAR(asChar(fname)));
|
||||
_WrapperEnd();
|
||||
}
|
||||
void XGBoosterSaveModel_R(SEXP handle, SEXP fname) {
|
||||
_WrapperBegin();
|
||||
XGBoosterSaveModel(R_ExternalPtrAddr(handle), CHAR(asChar(fname)));
|
||||
_WrapperEnd();
|
||||
}
|
||||
void XGBoosterLoadModelFromRaw_R(SEXP handle, SEXP raw) {
|
||||
_WrapperBegin();
|
||||
XGBoosterLoadModelFromBuffer(R_ExternalPtrAddr(handle),
|
||||
RAW(raw),
|
||||
length(raw));
|
||||
_WrapperEnd();
|
||||
}
|
||||
SEXP XGBoosterModelToRaw_R(SEXP handle) {
|
||||
bst_ulong olen;
|
||||
_WrapperBegin();
|
||||
const char *raw = XGBoosterGetModelRaw(R_ExternalPtrAddr(handle), &olen);
|
||||
_WrapperEnd();
|
||||
SEXP ret = PROTECT(allocVector(RAWSXP, olen));
|
||||
if (olen != 0) {
|
||||
memcpy(RAW(ret), raw, olen);
|
||||
}
|
||||
UNPROTECT(1);
|
||||
return ret;
|
||||
}
|
||||
SEXP XGBoosterDumpModel_R(SEXP handle, SEXP fmap, SEXP with_stats) {
|
||||
_WrapperBegin();
|
||||
bst_ulong olen;
|
||||
const char **res =
|
||||
XGBoosterDumpModel(R_ExternalPtrAddr(handle),
|
||||
CHAR(asChar(fmap)),
|
||||
asInteger(with_stats),
|
||||
&olen);
|
||||
_WrapperEnd();
|
||||
SEXP out = PROTECT(allocVector(STRSXP, olen));
|
||||
for (size_t i = 0; i < olen; ++i) {
|
||||
stringstream stream;
|
||||
stream << "booster["<<i<<"]\n" << res[i];
|
||||
SET_STRING_ELT(out, i, mkChar(stream.str().c_str()));
|
||||
}
|
||||
UNPROTECT(1);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -1,156 +1,212 @@
|
||||
#ifndef XGBOOST_WRAPPER_R_H_
|
||||
#define XGBOOST_WRAPPER_R_H_
|
||||
/*!
|
||||
* Copyright 2014 (c) by Contributors
|
||||
* \file xgboost_wrapper_R.h
|
||||
* \author Tianqi Chen
|
||||
* \brief R wrapper of xgboost
|
||||
*/
|
||||
extern "C" {
|
||||
#ifndef XGBOOST_R_H_ // NOLINT(*)
|
||||
#define XGBOOST_R_H_ // NOLINT(*)
|
||||
|
||||
|
||||
#include <Rinternals.h>
|
||||
#include <R_ext/Random.h>
|
||||
#include <Rmath.h>
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/*!
|
||||
* \brief check whether a handle is NULL
|
||||
* \param handle
|
||||
* \return whether it is null ptr
|
||||
#include <xgboost/c_api.h>
|
||||
|
||||
/*!
|
||||
* \brief check whether a handle is NULL
|
||||
* \param handle
|
||||
* \return whether it is null ptr
|
||||
*/
|
||||
XGB_DLL SEXP XGCheckNullPtr_R(SEXP handle);
|
||||
|
||||
/*!
|
||||
* \brief load a data matrix
|
||||
* \param fname name of the content
|
||||
* \param silent whether print messages
|
||||
* \return a loaded data matrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixCreateFromFile_R(SEXP fname, SEXP silent);
|
||||
|
||||
/*!
|
||||
* \brief create matrix content from dense matrix
|
||||
* This assumes the matrix is stored in column major format
|
||||
* \param data R Matrix object
|
||||
* \param missing which value to represent missing value
|
||||
* \return created dmatrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixCreateFromMat_R(SEXP mat,
|
||||
SEXP missing);
|
||||
/*!
|
||||
* \brief create a matrix content from CSC format
|
||||
* \param indptr pointer to column headers
|
||||
* \param indices row indices
|
||||
* \param data content of the data
|
||||
* \return created dmatrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixCreateFromCSC_R(SEXP indptr,
|
||||
SEXP indices,
|
||||
SEXP data);
|
||||
|
||||
/*!
|
||||
* \brief create a new dmatrix from sliced content of existing matrix
|
||||
* \param handle instance of data matrix to be sliced
|
||||
* \param idxset index set
|
||||
* \return a sliced new matrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixSliceDMatrix_R(SEXP handle, SEXP idxset);
|
||||
|
||||
/*!
|
||||
* \brief load a data matrix into binary file
|
||||
* \param handle a instance of data matrix
|
||||
* \param fname file name
|
||||
* \param silent print statistics when saving
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixSaveBinary_R(SEXP handle, SEXP fname, SEXP silent);
|
||||
|
||||
/*!
|
||||
* \brief set information to dmatrix
|
||||
* \param handle a instance of data matrix
|
||||
* \param field field name, can be label, weight
|
||||
* \param array pointer to float vector
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixSetInfo_R(SEXP handle, SEXP field, SEXP array);
|
||||
|
||||
/*!
|
||||
* \brief get info vector from matrix
|
||||
* \param handle a instance of data matrix
|
||||
* \param field field name
|
||||
* \return info vector
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixGetInfo_R(SEXP handle, SEXP field);
|
||||
|
||||
/*!
|
||||
* \brief return number of rows
|
||||
* \param handle an instance of data matrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixNumRow_R(SEXP handle);
|
||||
|
||||
/*!
|
||||
* \brief return number of columns
|
||||
* \param handle an instance of data matrix
|
||||
*/
|
||||
XGB_DLL SEXP XGDMatrixNumCol_R(SEXP handle);
|
||||
|
||||
/*!
|
||||
* \brief create xgboost learner
|
||||
* \param dmats a list of dmatrix handles that will be cached
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterCreate_R(SEXP dmats);
|
||||
|
||||
/*!
|
||||
* \brief set parameters
|
||||
* \param handle handle
|
||||
* \param name parameter name
|
||||
* \param val value of parameter
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterSetParam_R(SEXP handle, SEXP name, SEXP val);
|
||||
|
||||
/*!
|
||||
* \brief update the model in one round using dtrain
|
||||
* \param handle handle
|
||||
* \param iter current iteration rounds
|
||||
* \param dtrain training data
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterUpdateOneIter_R(SEXP ext, SEXP iter, SEXP dtrain);
|
||||
|
||||
/*!
|
||||
* \brief update the model, by directly specify gradient and second order gradient,
|
||||
* this can be used to replace UpdateOneIter, to support customized loss function
|
||||
* \param handle handle
|
||||
* \param dtrain training data
|
||||
* \param grad gradient statistics
|
||||
* \param hess second order gradient statistics
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterBoostOneIter_R(SEXP handle, SEXP dtrain, SEXP grad, SEXP hess);
|
||||
|
||||
/*!
|
||||
* \brief get evaluation statistics for xgboost
|
||||
* \param handle handle
|
||||
* \param iter current iteration rounds
|
||||
* \param dmats list of handles to dmatrices
|
||||
* \param evname name of evaluation
|
||||
* \return the string containing evaluation stats
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterEvalOneIter_R(SEXP handle, SEXP iter, SEXP dmats, SEXP evnames);
|
||||
|
||||
/*!
|
||||
* \brief make prediction based on dmat
|
||||
* \param handle handle
|
||||
* \param dmat data matrix
|
||||
* \param option_mask output_margin:1 predict_leaf:2
|
||||
* \param ntree_limit limit number of trees used in prediction
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterPredict_R(SEXP handle, SEXP dmat, SEXP option_mask, SEXP ntree_limit);
|
||||
/*!
|
||||
* \brief load model from existing file
|
||||
* \param handle handle
|
||||
* \param fname file name
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterLoadModel_R(SEXP handle, SEXP fname);
|
||||
|
||||
/*!
|
||||
* \brief save model into existing file
|
||||
* \param handle handle
|
||||
* \param fname file name
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterSaveModel_R(SEXP handle, SEXP fname);
|
||||
|
||||
/*!
|
||||
* \brief load model from raw array
|
||||
* \param handle handle
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterLoadModelFromRaw_R(SEXP handle, SEXP raw);
|
||||
|
||||
/*!
|
||||
* \brief save model into R's raw array
|
||||
* \param handle handle
|
||||
* \return raw array
|
||||
*/
|
||||
SEXP XGCheckNullPtr_R(SEXP handle);
|
||||
/*!
|
||||
* \brief load a data matrix
|
||||
* \param fname name of the content
|
||||
* \param silent whether print messages
|
||||
* \return a loaded data matrix
|
||||
*/
|
||||
SEXP XGDMatrixCreateFromFile_R(SEXP fname, SEXP silent);
|
||||
/*!
|
||||
* \brief create matrix content from dense matrix
|
||||
* This assumes the matrix is stored in column major format
|
||||
* \param data R Matrix object
|
||||
* \param missing which value to represent missing value
|
||||
* \return created dmatrix
|
||||
*/
|
||||
SEXP XGDMatrixCreateFromMat_R(SEXP mat,
|
||||
SEXP missing);
|
||||
/*!
|
||||
* \brief create a matrix content from CSC format
|
||||
* \param indptr pointer to column headers
|
||||
* \param indices row indices
|
||||
* \param data content of the data
|
||||
* \return created dmatrix
|
||||
*/
|
||||
SEXP XGDMatrixCreateFromCSC_R(SEXP indptr,
|
||||
SEXP indices,
|
||||
SEXP data);
|
||||
/*!
|
||||
* \brief create a new dmatrix from sliced content of existing matrix
|
||||
* \param handle instance of data matrix to be sliced
|
||||
* \param idxset index set
|
||||
* \return a sliced new matrix
|
||||
*/
|
||||
SEXP XGDMatrixSliceDMatrix_R(SEXP handle, SEXP idxset);
|
||||
/*!
|
||||
* \brief load a data matrix into binary file
|
||||
* \param handle a instance of data matrix
|
||||
* \param fname file name
|
||||
* \param silent print statistics when saving
|
||||
*/
|
||||
void XGDMatrixSaveBinary_R(SEXP handle, SEXP fname, SEXP silent);
|
||||
/*!
|
||||
* \brief set information to dmatrix
|
||||
* \param handle a instance of data matrix
|
||||
* \param field field name, can be label, weight
|
||||
* \param array pointer to float vector
|
||||
*/
|
||||
void XGDMatrixSetInfo_R(SEXP handle, SEXP field, SEXP array);
|
||||
/*!
|
||||
* \brief get info vector from matrix
|
||||
* \param handle a instance of data matrix
|
||||
* \param field field name
|
||||
* \return info vector
|
||||
*/
|
||||
SEXP XGDMatrixGetInfo_R(SEXP handle, SEXP field);
|
||||
/*!
|
||||
* \brief return number of rows
|
||||
* \param handle a instance of data matrix
|
||||
*/
|
||||
SEXP XGDMatrixNumRow_R(SEXP handle);
|
||||
/*!
|
||||
* \brief create xgboost learner
|
||||
* \param dmats a list of dmatrix handles that will be cached
|
||||
*/
|
||||
SEXP XGBoosterCreate_R(SEXP dmats);
|
||||
/*!
|
||||
* \brief set parameters
|
||||
* \param handle handle
|
||||
* \param name parameter name
|
||||
* \param val value of parameter
|
||||
*/
|
||||
void XGBoosterSetParam_R(SEXP handle, SEXP name, SEXP val);
|
||||
/*!
|
||||
* \brief update the model in one round using dtrain
|
||||
* \param handle handle
|
||||
* \param iter current iteration rounds
|
||||
* \param dtrain training data
|
||||
*/
|
||||
void XGBoosterUpdateOneIter_R(SEXP ext, SEXP iter, SEXP dtrain);
|
||||
/*!
|
||||
* \brief update the model, by directly specify gradient and second order gradient,
|
||||
* this can be used to replace UpdateOneIter, to support customized loss function
|
||||
* \param handle handle
|
||||
* \param dtrain training data
|
||||
* \param grad gradient statistics
|
||||
* \param hess second order gradient statistics
|
||||
*/
|
||||
void XGBoosterBoostOneIter_R(SEXP handle, SEXP dtrain, SEXP grad, SEXP hess);
|
||||
/*!
|
||||
* \brief get evaluation statistics for xgboost
|
||||
* \param handle handle
|
||||
* \param iter current iteration rounds
|
||||
* \param dmats list of handles to dmatrices
|
||||
* \param evname name of evaluation
|
||||
* \return the string containing evaluation stati
|
||||
*/
|
||||
SEXP XGBoosterEvalOneIter_R(SEXP handle, SEXP iter, SEXP dmats, SEXP evnames);
|
||||
/*!
|
||||
* \brief make prediction based on dmat
|
||||
* \param handle handle
|
||||
* \param dmat data matrix
|
||||
* \param option_mask output_margin:1 predict_leaf:2
|
||||
* \param ntree_limit limit number of trees used in prediction
|
||||
*/
|
||||
SEXP XGBoosterPredict_R(SEXP handle, SEXP dmat, SEXP option_mask, SEXP ntree_limit);
|
||||
/*!
|
||||
* \brief load model from existing file
|
||||
* \param handle handle
|
||||
* \param fname file name
|
||||
*/
|
||||
void XGBoosterLoadModel_R(SEXP handle, SEXP fname);
|
||||
/*!
|
||||
* \brief save model into existing file
|
||||
* \param handle handle
|
||||
* \param fname file name
|
||||
*/
|
||||
void XGBoosterSaveModel_R(SEXP handle, SEXP fname);
|
||||
/*!
|
||||
* \brief load model from raw array
|
||||
* \param handle handle
|
||||
*/
|
||||
void XGBoosterLoadModelFromRaw_R(SEXP handle, SEXP raw);
|
||||
/*!
|
||||
* \brief save model into R's raw array
|
||||
* \param handle handle
|
||||
* \return raw array
|
||||
*/
|
||||
SEXP XGBoosterModelToRaw_R(SEXP handle);
|
||||
/*!
|
||||
* \brief dump model into a string
|
||||
* \param handle handle
|
||||
* \param fmap name to fmap can be empty string
|
||||
* \param with_stats whether dump statistics of splits
|
||||
*/
|
||||
SEXP XGBoosterDumpModel_R(SEXP handle, SEXP fmap, SEXP with_stats);
|
||||
}
|
||||
#endif // XGBOOST_WRAPPER_R_H_
|
||||
XGB_DLL SEXP XGBoosterModelToRaw_R(SEXP handle);
|
||||
|
||||
/*!
|
||||
* \brief dump model into a string
|
||||
* \param handle handle
|
||||
* \param fmap name to fmap can be empty string
|
||||
* \param with_stats whether dump statistics of splits
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterDumpModel_R(SEXP handle, SEXP fmap, SEXP with_stats);
|
||||
|
||||
/*!
|
||||
* \brief get learner attribute value
|
||||
* \param handle handle
|
||||
* \param name attribute name
|
||||
* \return character containing attribute value
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterGetAttr_R(SEXP handle, SEXP name);
|
||||
|
||||
/*!
|
||||
* \brief set learner attribute value
|
||||
* \param handle handle
|
||||
* \param name attribute name
|
||||
* \param val attribute value; NULL value would delete an attribute
|
||||
* \return R_NilValue
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterSetAttr_R(SEXP handle, SEXP name, SEXP val);
|
||||
|
||||
/*!
|
||||
* \brief get the names of learner attributes
|
||||
* \return string vector containing attribute names
|
||||
*/
|
||||
XGB_DLL SEXP XGBoosterGetAttrNames_R(SEXP handle);
|
||||
|
||||
#endif // XGBOOST_WRAPPER_R_H_ // NOLINT(*)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Copyright (c) 2014 by Contributors
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <Rinternals.h>
|
||||
@@ -6,28 +7,20 @@
|
||||
void XGBoostAssert_R(int exp, const char *fmt, ...) {
|
||||
char buf[1024];
|
||||
if (exp == 0) {
|
||||
va_list args;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
error("AssertError:%s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
void XGBoostCheck_R(int exp, const char *fmt, ...) {
|
||||
char buf[1024];
|
||||
if (exp == 0) {
|
||||
va_list args;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
error("%s\n", buf);
|
||||
}
|
||||
}
|
||||
int XGBoostSPrintf_R(char *buf, size_t size, const char *fmt, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
65
R-package/src/xgboost_custom.cc
Normal file
65
R-package/src/xgboost_custom.cc
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2015 by Contributors
|
||||
// This file contains the customization implementations of R module
|
||||
// to change behavior of libxgboost
|
||||
|
||||
#include <xgboost/logging.h>
|
||||
#include "src/common/random.h"
|
||||
#include "./xgboost_R.h"
|
||||
|
||||
// redirect the messages to R's console.
|
||||
namespace dmlc {
|
||||
void CustomLogMessage::Log(const std::string& msg) {
|
||||
Rprintf("%s\n", msg.c_str());
|
||||
}
|
||||
} // namespace dmlc
|
||||
|
||||
// implements rabit error handling.
|
||||
extern "C" {
|
||||
void XGBoostAssert_R(int exp, const char *fmt, ...);
|
||||
void XGBoostCheck_R(int exp, const char *fmt, ...);
|
||||
}
|
||||
|
||||
namespace rabit {
|
||||
namespace utils {
|
||||
extern "C" {
|
||||
void (*Printf)(const char *fmt, ...) = Rprintf;
|
||||
void (*Assert)(int exp, const char *fmt, ...) = XGBoostAssert_R;
|
||||
void (*Check)(int exp, const char *fmt, ...) = XGBoostCheck_R;
|
||||
void (*Error)(const char *fmt, ...) = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace xgboost {
|
||||
ConsoleLogger::~ConsoleLogger() {
|
||||
dmlc::CustomLogMessage::Log(log_stream_.str());
|
||||
}
|
||||
TrackerLogger::~TrackerLogger() {
|
||||
dmlc::CustomLogMessage::Log(log_stream_.str());
|
||||
}
|
||||
} // namespace xgboost
|
||||
|
||||
namespace xgboost {
|
||||
namespace common {
|
||||
|
||||
// redirect the nath functions.
|
||||
bool CheckNAN(double v) {
|
||||
return ISNAN(v);
|
||||
}
|
||||
double LogGamma(double v) {
|
||||
return lgammafn(v);
|
||||
}
|
||||
|
||||
// customize random engine.
|
||||
void CustomGlobalRandomEngine::seed(CustomGlobalRandomEngine::result_type val) {
|
||||
// ignore the seed
|
||||
}
|
||||
|
||||
// use R's PRNG to replacd
|
||||
CustomGlobalRandomEngine::result_type
|
||||
CustomGlobalRandomEngine::operator()() {
|
||||
return static_cast<result_type>(
|
||||
std::floor(unif_rand() * CustomGlobalRandomEngine::max()));
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace xgboost
|
||||
4
R-package/tests/testthat.R
Normal file
4
R-package/tests/testthat.R
Normal file
@@ -0,0 +1,4 @@
|
||||
library(testthat)
|
||||
library(xgboost)
|
||||
|
||||
test_check("xgboost")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user