Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76c44072d1 | ||
|
|
ccde443590 | ||
|
|
cf710bfa59 | ||
|
|
be2c3d299e | ||
|
|
2eba59000a | ||
|
|
a958fe8d52 | ||
|
|
96667b8bad | ||
|
|
95f4052aae | ||
|
|
e9e3e0281d | ||
|
|
c23d8c8b88 | ||
|
|
e59f4d5a18 | ||
|
|
e267f4c5f9 | ||
|
|
505e65ac08 | ||
|
|
13fc48623e | ||
|
|
591a43ac0e | ||
|
|
5375ac5c23 | ||
|
|
6930758294 | ||
|
|
e09d6ab9de | ||
|
|
db4a100f6b | ||
|
|
495e37e0dc | ||
|
|
b56b34944e | ||
|
|
d4530b7a47 | ||
|
|
334cf5de9b | ||
|
|
004e8d811e | ||
|
|
4baefd857e | ||
|
|
b52f01d61d | ||
|
|
35f9ef684a | ||
|
|
6f34096613 | ||
|
|
31c5d7843f | ||
|
|
f60dbe299e | ||
|
|
a77debc0c5 | ||
|
|
dc2b9c86e6 | ||
|
|
73bc8c0de4 | ||
|
|
ad8eb21fcd | ||
|
|
416050d5c0 | ||
|
|
d5f6fba82d | ||
|
|
23f4c41035 | ||
|
|
7ea988a76b | ||
|
|
d3c0ed14f3 | ||
|
|
2fcd875675 | ||
|
|
615074efb6 | ||
|
|
945b336fc6 | ||
|
|
8e8b8a8ee3 | ||
|
|
42267807f5 | ||
|
|
df23464a20 | ||
|
|
2ea8d9c511 | ||
|
|
3206235a5e | ||
|
|
956fc09da0 | ||
|
|
da482500c7 | ||
|
|
b19f2bfda8 | ||
|
|
21b21e69de | ||
|
|
b90d1dc92b | ||
|
|
3429ab3447 | ||
|
|
ebcce4a2bf | ||
|
|
1839e6efe9 | ||
|
|
9bc6e83afe | ||
|
|
fd2774e133 | ||
|
|
72d3a6a3cc | ||
|
|
5febbecd88 | ||
|
|
b3c3ecd9c9 | ||
|
|
c28a1be34c | ||
|
|
ae70b9b152 | ||
|
|
e0a0343ae6 | ||
|
|
0e0d3efd6a | ||
|
|
a3bd5000ba | ||
|
|
dd71c0e070 | ||
|
|
d9ea324057 | ||
|
|
0d29610c40 | ||
|
|
0af2c92d3b | ||
|
|
f9cdce077b | ||
|
|
59183b9ed8 | ||
|
|
6ff272eec6 | ||
|
|
c8073e13e4 | ||
|
|
698fa87bc3 | ||
|
|
8f56671901 | ||
|
|
9ea9a7a01e | ||
|
|
d59940f1d5 | ||
|
|
6aa190e10c | ||
|
|
54c486bcf1 | ||
|
|
88ff293de5 | ||
|
|
50af92e29e | ||
|
|
bbe4957cd2 | ||
|
|
789ad18d36 | ||
|
|
2b34d5a25e | ||
|
|
bd574e4967 | ||
|
|
e8d81c1da5 | ||
|
|
c84bbc91d1 | ||
|
|
61e3d1562c | ||
|
|
97db8c29f2 | ||
|
|
f2552f8ef2 | ||
|
|
2563b6d2d6 | ||
|
|
e90ffece67 | ||
|
|
85f92681f9 | ||
|
|
5e0d52cb8c | ||
|
|
c9d156d99e | ||
|
|
ecf6e8f49f | ||
|
|
93778aa4aa | ||
|
|
f8cacc7308 | ||
|
|
c0e1e9fe7a | ||
|
|
fa5afe2141 | ||
|
|
f7789ecf14 | ||
|
|
a57fbe091a | ||
|
|
9f82b53366 | ||
|
|
248b2cf74d | ||
|
|
5fb9376af4 | ||
|
|
9c2bb12cd1 | ||
|
|
ebde99bde8 | ||
|
|
ef7be5398d | ||
|
|
2ef61bf982 | ||
|
|
d4d141347a | ||
|
|
e18ba04751 | ||
|
|
3388d1a8b5 | ||
|
|
65917bb831 | ||
|
|
140499ac9e | ||
|
|
ccd037292d | ||
|
|
59939d0b14 | ||
|
|
9a2c00554d | ||
|
|
ee30c1728b | ||
|
|
8f75b0ef75 | ||
|
|
3128e718e2 | ||
|
|
657c617215 | ||
|
|
439d4725a0 | ||
|
|
8491bb3651 | ||
|
|
cce96e8f41 | ||
|
|
f02dd68713 | ||
|
|
ec14d32756 | ||
|
|
38577d45b0 | ||
|
|
ab0e7a3ddc | ||
|
|
bbd952a021 | ||
|
|
77e3051b1d | ||
|
|
924e164c14 | ||
|
|
25ff5ef169 | ||
|
|
3ea29eccae | ||
|
|
0f8a3d21a5 | ||
|
|
7487c2f668 | ||
|
|
88787b8573 | ||
|
|
17559a90f9 | ||
|
|
24696071a8 | ||
|
|
cca67af8d7 | ||
|
|
2beb92745f | ||
|
|
d6b582dc70 | ||
|
|
218320daf2 | ||
|
|
f83942d3e9 | ||
|
|
60d79eb2e7 | ||
|
|
1136c71e64 | ||
|
|
1bbbb0cf7f | ||
|
|
1756fde0c6 | ||
|
|
7f30fc1468 | ||
|
|
d5607fbb55 | ||
|
|
05d984d83d | ||
|
|
1110ae7421 | ||
|
|
2aa1031d24 | ||
|
|
1440dc9c8f | ||
|
|
27bd5496a8 | ||
|
|
81b32525e0 | ||
|
|
6fa0948461 | ||
|
|
61123f86aa | ||
|
|
110b97fea2 | ||
|
|
b2eb4e956b | ||
|
|
56ae0e32e3 | ||
|
|
e350c38483 | ||
|
|
e59ed018e6 | ||
|
|
3123d11655 | ||
|
|
ca74cba9ec | ||
|
|
a84d4f3e68 | ||
|
|
76cd1561a0 | ||
|
|
5b4f77488c | ||
|
|
b0676fc682 | ||
|
|
97418b113e | ||
|
|
d56394d2ef | ||
|
|
6a91438634 | ||
|
|
da3b3c8136 | ||
|
|
fcf06a7164 | ||
|
|
8f9efa2725 | ||
|
|
6e48a938c6 | ||
|
|
19b28b978d | ||
|
|
8f16ef8e75 | ||
|
|
d2377b26bd | ||
|
|
70f3f31206 | ||
|
|
f62c5dc3c1 | ||
|
|
2d67377a96 | ||
|
|
d982be9dca | ||
|
|
98114cabce | ||
|
|
2910bdedf4 | ||
|
|
128e94be1a | ||
|
|
eade6ddf7c | ||
|
|
9b45210fa7 | ||
|
|
ddd61b43be | ||
|
|
98e851d80f | ||
|
|
3d223232e3 | ||
|
|
b689b4525a | ||
|
|
a3ca03cfc1 | ||
|
|
2aa1978cb6 | ||
|
|
e3b7abfb47 | ||
|
|
2adf905dcf | ||
|
|
cfbeeef9c1 | ||
|
|
8ae1d37828 | ||
|
|
0fc64d1c2a | ||
|
|
1eca127f69 | ||
|
|
c7b29774c2 | ||
|
|
a8f69878eb | ||
|
|
51b6d86c17 | ||
|
|
082a57ba0b | ||
|
|
f3c98d0c4b | ||
|
|
1748e4517a | ||
|
|
328e41244c | ||
|
|
155b593984 | ||
|
|
76cbc754c9 | ||
|
|
97ca3bf739 | ||
|
|
752f336cb3 | ||
|
|
fffad41e53 | ||
|
|
10382f6365 | ||
|
|
7b2fe1bf5d | ||
|
|
88c982012a | ||
|
|
b6f98bf37a | ||
|
|
3a4d0f28d9 | ||
|
|
e58daa6d52 | ||
|
|
a5b37e0395 | ||
|
|
e75488b578 | ||
|
|
1160a38323 | ||
|
|
4401d549f1 | ||
|
|
fd120a8f5c | ||
|
|
00add6dd1d | ||
|
|
cd009f2541 | ||
|
|
582be45810 | ||
|
|
3c93216850 | ||
|
|
787f76e952 | ||
|
|
91c170e463 | ||
|
|
0c44347e82 | ||
|
|
603704287d | ||
|
|
c933625f94 | ||
|
|
cebf39ea47 | ||
|
|
f22139c659 | ||
|
|
06ce8c9f3a | ||
|
|
98a60b3610 | ||
|
|
2dc6c9c683 | ||
|
|
3e53fcf465 | ||
|
|
cb0fa75252 | ||
|
|
51a63d80d0 | ||
|
|
1e356c5bd2 | ||
|
|
c5ada79be5 | ||
|
|
dd924becd8 | ||
|
|
7fa301a8ce | ||
|
|
3d1e0badd3 | ||
|
|
7e605306ad | ||
|
|
5e5acdc121 | ||
|
|
7302a4e1b5 | ||
|
|
21dd4b5904 | ||
|
|
61e5410789 | ||
|
|
0febb1a443 | ||
|
|
36a04f17df | ||
|
|
3dd477c4b2 | ||
|
|
779d6a34de | ||
|
|
4535ab7e5c | ||
|
|
75c36a0667 | ||
|
|
790c76e814 | ||
|
|
a81ea03022 | ||
|
|
a198759df6 | ||
|
|
a607444038 | ||
|
|
ee6a0c7f4a | ||
|
|
57fef8bc54 |
214
.clang-format
214
.clang-format
@@ -1,214 +0,0 @@
|
|||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
# BasedOnStyle: Google
|
|
||||||
AccessModifierOffset: -1
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignArrayOfStructures: None
|
|
||||||
AlignConsecutiveMacros: None
|
|
||||||
AlignConsecutiveAssignments: None
|
|
||||||
AlignConsecutiveBitFields: None
|
|
||||||
AlignConsecutiveDeclarations: None
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: Align
|
|
||||||
AlignTrailingComments: true
|
|
||||||
AllowAllArgumentsOnNextLine: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
|
||||||
AllowShortEnumsOnASingleLine: true
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortLambdasOnASingleLine: Inline
|
|
||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: true
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
AttributeMacros:
|
|
||||||
- __capability
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: Never
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeLambdaBody: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeConceptDeclarations: true
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInheritanceComma: false
|
|
||||||
BreakInheritanceList: BeforeColon
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializersBeforeComma: false
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakStringLiterals: true
|
|
||||||
ColumnLimit: 100
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
QualifierAlignment: Leave
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DeriveLineEnding: true
|
|
||||||
DerivePointerAlignment: true
|
|
||||||
DisableFormat: false
|
|
||||||
EmptyLineAfterAccessModifier: Never
|
|
||||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
PackConstructorInitializers: NextLine
|
|
||||||
BasedOnStyle: ''
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
AllowAllConstructorInitializersOnNextLine: true
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IfMacros:
|
|
||||||
- KJ_IF_MAYBE
|
|
||||||
IncludeBlocks: Regroup
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^<ext/.*\.h>'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '^<.*\.h>'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '^<.*'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
|
||||||
IncludeIsMainSourceRegex: ''
|
|
||||||
IndentAccessModifiers: false
|
|
||||||
IndentCaseLabels: true
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
IndentGotoLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentExternBlock: AfterExternBlock
|
|
||||||
IndentRequires: false
|
|
||||||
IndentWidth: 2
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
InsertTrailingCommas: None
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
LambdaBodyIndentation: Signature
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Never
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCBreakBeforeNestedBlockParam: true
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 1
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 200
|
|
||||||
PenaltyIndentedWhitespace: 0
|
|
||||||
PointerAlignment: Left
|
|
||||||
PPIndentWidth: -1
|
|
||||||
RawStringFormats:
|
|
||||||
- Language: Cpp
|
|
||||||
Delimiters:
|
|
||||||
- cc
|
|
||||||
- CC
|
|
||||||
- cpp
|
|
||||||
- Cpp
|
|
||||||
- CPP
|
|
||||||
- 'c++'
|
|
||||||
- 'C++'
|
|
||||||
CanonicalDelimiter: ''
|
|
||||||
BasedOnStyle: google
|
|
||||||
- Language: TextProto
|
|
||||||
Delimiters:
|
|
||||||
- pb
|
|
||||||
- PB
|
|
||||||
- proto
|
|
||||||
- PROTO
|
|
||||||
EnclosingFunctions:
|
|
||||||
- EqualsProto
|
|
||||||
- EquivToProto
|
|
||||||
- PARSE_PARTIAL_TEXT_PROTO
|
|
||||||
- PARSE_TEST_PROTO
|
|
||||||
- PARSE_TEXT_PROTO
|
|
||||||
- ParseTextOrDie
|
|
||||||
- ParseTextProtoOrDie
|
|
||||||
- ParseTestProto
|
|
||||||
- ParsePartialTestProto
|
|
||||||
CanonicalDelimiter: pb
|
|
||||||
BasedOnStyle: google
|
|
||||||
ReferenceAlignment: Pointer
|
|
||||||
ReflowComments: true
|
|
||||||
ShortNamespaceLines: 1
|
|
||||||
SortIncludes: CaseSensitive
|
|
||||||
SortJavaStaticImport: Before
|
|
||||||
SortUsingDeclarations: true
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: true
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCaseColon: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceAroundPointerQualifiers: Default
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 2
|
|
||||||
SpacesInAngles: Never
|
|
||||||
SpacesInConditionalStatement: false
|
|
||||||
SpacesInContainerLiterals: true
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInLineCommentPrefix:
|
|
||||||
Minimum: 1
|
|
||||||
Maximum: -1
|
|
||||||
SpacesInParentheses: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
BitFieldColonSpacing: Both
|
|
||||||
Standard: Auto
|
|
||||||
StatementAttributeLikeMacros:
|
|
||||||
- Q_EMIT
|
|
||||||
StatementMacros:
|
|
||||||
- Q_UNUSED
|
|
||||||
- QT_REQUIRE_VERSION
|
|
||||||
TabWidth: 8
|
|
||||||
UseCRLF: false
|
|
||||||
UseTab: Never
|
|
||||||
WhitespaceSensitiveMacros:
|
|
||||||
- STRINGIZE
|
|
||||||
- PP_STRINGIZE
|
|
||||||
- BOOST_PP_STRINGIZE
|
|
||||||
- NS_SWIFT_NAME
|
|
||||||
- CF_SWIFT_NAME
|
|
||||||
...
|
|
||||||
21
.clang-tidy
21
.clang-tidy
@@ -1,21 +0,0 @@
|
|||||||
Checks: 'modernize-*,-modernize-use-nodiscard,-modernize-concat-nested-namespaces,-modernize-make-*,-modernize-use-auto,-modernize-raw-string-literal,-modernize-avoid-c-arrays,-modernize-use-trailing-return-type,google-*,-google-default-arguments,-clang-diagnostic-#pragma-messages,readability-identifier-naming'
|
|
||||||
CheckOptions:
|
|
||||||
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.TypeAliasCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.TypedefCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.MemberCase, value: lower_case }
|
|
||||||
- { key: readability-identifier-naming.PrivateMemberSuffix, value: '_' }
|
|
||||||
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: '_' }
|
|
||||||
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.EnumConstant, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.EnumConstantPrefix, value: k }
|
|
||||||
- { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.GlobalConstantPrefix, value: k }
|
|
||||||
- { key: readability-identifier-naming.StaticConstantCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.StaticConstantPrefix, value: k }
|
|
||||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: k }
|
|
||||||
- { key: readability-identifier-naming.FunctionCase, value: CamelCase }
|
|
||||||
- { key: readability-identifier-naming.NamespaceCase, value: lower_case }
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset=utf-8
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.py]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
18
.gitattributes
vendored
18
.gitattributes
vendored
@@ -1,18 +0,0 @@
|
|||||||
* text=auto
|
|
||||||
|
|
||||||
*.c text eol=lf
|
|
||||||
*.h text eol=lf
|
|
||||||
*.cc text eol=lf
|
|
||||||
*.cuh text eol=lf
|
|
||||||
*.cu text eol=lf
|
|
||||||
*.py text eol=lf
|
|
||||||
*.txt text eol=lf
|
|
||||||
*.R text eol=lf
|
|
||||||
*.scala text eol=lf
|
|
||||||
*.java text eol=lf
|
|
||||||
|
|
||||||
*.sh text eol=lf
|
|
||||||
|
|
||||||
*.rst text eol=lf
|
|
||||||
*.md text eol=lf
|
|
||||||
*.csv text eol=lf
|
|
||||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +0,0 @@
|
|||||||
open_collective: xgboost
|
|
||||||
custom: https://xgboost.ai/sponsors
|
|
||||||
7
.github/ISSUE_TEMPLATE.md
vendored
7
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,7 +0,0 @@
|
|||||||
Thanks for participating in the XGBoost community! We use https://discuss.xgboost.ai for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :)
|
|
||||||
|
|
||||||
Issues that are inactive for a period of time may get closed. We adopt this policy so that we won't lose track of actionable issues that may fall at the bottom of the pile. Feel free to reopen a new one if you feel there is an additional problem that needs attention when an old one gets closed.
|
|
||||||
|
|
||||||
For bug reports, to help the developer act on the issues, please include a description of your environment, preferably a minimum script to reproduce the problem.
|
|
||||||
|
|
||||||
For feature proposals, list clear, small actionable items so we can track the progress of the change.
|
|
||||||
35
.github/dependabot.yml
vendored
35
.github/dependabot.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages/xgboost4j"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages/xgboost4j-gpu"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages/xgboost4j-example"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages/xgboost4j-spark"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "maven"
|
|
||||||
directory: "/jvm-packages/xgboost4j-spark-gpu"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
32
.github/lock.yml
vendored
32
.github/lock.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
# Configuration for lock-threads - https://github.com/dessant/lock-threads
|
|
||||||
|
|
||||||
# Number of days of inactivity before a closed issue or pull request is locked
|
|
||||||
daysUntilLock: 90
|
|
||||||
|
|
||||||
# Issues and pull requests with these labels will not be locked. Set to `[]` to disable
|
|
||||||
exemptLabels:
|
|
||||||
- feature-request
|
|
||||||
|
|
||||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
|
||||||
lockLabel: false
|
|
||||||
|
|
||||||
# Comment to post before locking. Set to `false` to disable
|
|
||||||
lockComment: false
|
|
||||||
|
|
||||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
|
||||||
setLockReason: true
|
|
||||||
|
|
||||||
# Limit to only `issues` or `pulls`
|
|
||||||
# only: issues
|
|
||||||
|
|
||||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
|
||||||
# issues:
|
|
||||||
# exemptLabels:
|
|
||||||
# - help-wanted
|
|
||||||
# lockLabel: outdated
|
|
||||||
|
|
||||||
# pulls:
|
|
||||||
# daysUntilLock: 30
|
|
||||||
|
|
||||||
# Repository to extend settings from
|
|
||||||
# _extends: repo
|
|
||||||
34
.github/workflows/freebsd.yml
vendored
34
.github/workflows/freebsd.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
name: FreeBSD
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 20
|
|
||||||
name: A job to run test in FreeBSD
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Test in FreeBSD
|
|
||||||
id: test
|
|
||||||
uses: vmactions/freebsd-vm@v1
|
|
||||||
with:
|
|
||||||
usesh: true
|
|
||||||
prepare: |
|
|
||||||
pkg install -y cmake git ninja googletest
|
|
||||||
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja -DGOOGLE_TEST=ON
|
|
||||||
ninja -v
|
|
||||||
./testxgboost
|
|
||||||
43
.github/workflows/i386.yml
vendored
43
.github/workflows/i386.yml
vendored
@@ -1,43 +0,0 @@
|
|||||||
name: XGBoost-i386-test
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-32bit:
|
|
||||||
name: Build 32-bit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
registry:
|
|
||||||
image: registry:2
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3.6.1
|
|
||||||
with:
|
|
||||||
driver-opts: network=host
|
|
||||||
- name: Build and push container
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: tests/ci_build/Dockerfile.i386
|
|
||||||
push: true
|
|
||||||
tags: localhost:5000/xgboost/build-32bit:latest
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
- name: Build XGBoost
|
|
||||||
run: |
|
|
||||||
docker run --rm -v $PWD:/workspace -w /workspace \
|
|
||||||
-e CXXFLAGS='-Wno-error=overloaded-virtual -Wno-error=maybe-uninitialized -Wno-error=redundant-move' \
|
|
||||||
localhost:5000/xgboost/build-32bit:latest \
|
|
||||||
tests/ci_build/build_via_cmake.sh
|
|
||||||
100
.github/workflows/jvm_tests.yml
vendored
100
.github/workflows/jvm_tests.yml
vendored
@@ -1,100 +0,0 @@
|
|||||||
name: XGBoost-JVM-Tests
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-with-jvm:
|
|
||||||
name: Test JVM on OS ${{ matrix.os }}
|
|
||||||
timeout-minutes: 30
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [windows-latest, ubuntu-latest, macos-13]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '8'
|
|
||||||
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: jvm_tests
|
|
||||||
environment-file: tests/ci_build/conda_env/jvm_tests.yml
|
|
||||||
use-mamba: true
|
|
||||||
|
|
||||||
- name: Cache Maven packages
|
|
||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
|
||||||
with:
|
|
||||||
path: ~/.m2
|
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('./jvm-packages/pom.xml') }}
|
|
||||||
restore-keys: ${{ runner.os }}-m2-${{ hashFiles('./jvm-packages/pom.xml') }}
|
|
||||||
|
|
||||||
- name: Test XGBoost4J (Core)
|
|
||||||
run: |
|
|
||||||
cd jvm-packages
|
|
||||||
mvn test -B -pl :xgboost4j_2.12
|
|
||||||
|
|
||||||
- name: Test XGBoost4J (Core, Spark, Examples)
|
|
||||||
run: |
|
|
||||||
rm -rfv build/
|
|
||||||
cd jvm-packages
|
|
||||||
mvn -B test
|
|
||||||
if: matrix.os == 'ubuntu-latest' # Distributed training doesn't work on Windows
|
|
||||||
|
|
||||||
- name: Extract branch name
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "branch=${GITHUB_REF#refs/heads/}" >> "$GITHUB_OUTPUT"
|
|
||||||
id: extract_branch
|
|
||||||
if: |
|
|
||||||
(github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')) &&
|
|
||||||
(matrix.os == 'windows-latest' || matrix.os == 'macos-13')
|
|
||||||
|
|
||||||
- name: Publish artifact xgboost4j.dll to S3
|
|
||||||
run: |
|
|
||||||
cd lib/
|
|
||||||
Rename-Item -Path xgboost4j.dll -NewName xgboost4j_${{ github.sha }}.dll
|
|
||||||
dir
|
|
||||||
python -m awscli s3 cp xgboost4j_${{ github.sha }}.dll s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/libxgboost4j/ --acl public-read --region us-west-2
|
|
||||||
if: |
|
|
||||||
(github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')) &&
|
|
||||||
matrix.os == 'windows-latest'
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_IAM_S3_UPLOADER }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_IAM_S3_UPLOADER }}
|
|
||||||
|
|
||||||
- name: Publish artifact libxgboost4j.dylib to S3
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
cd lib/
|
|
||||||
mv -v libxgboost4j.dylib libxgboost4j_${{ github.sha }}.dylib
|
|
||||||
ls
|
|
||||||
python -m awscli s3 cp libxgboost4j_${{ github.sha }}.dylib s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/libxgboost4j/ --acl public-read --region us-west-2
|
|
||||||
if: |
|
|
||||||
(github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')) &&
|
|
||||||
matrix.os == 'macos-13'
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_IAM_S3_UPLOADER }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_IAM_S3_UPLOADER }}
|
|
||||||
|
|
||||||
- name: Build and Test XGBoost4J with scala 2.13
|
|
||||||
run: |
|
|
||||||
rm -rfv build/
|
|
||||||
cd jvm-packages
|
|
||||||
mvn -B clean install test -Pdefault,scala-2.13
|
|
||||||
if: matrix.os == 'ubuntu-latest' # Distributed training doesn't work on Windows
|
|
||||||
193
.github/workflows/main.yml
vendored
193
.github/workflows/main.yml
vendored
@@ -1,193 +0,0 @@
|
|||||||
# This is a basic workflow to help you get started with Actions
|
|
||||||
|
|
||||||
name: XGBoost-CI
|
|
||||||
|
|
||||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
|
||||||
# events but only for the master branch
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
gtest-cpu:
|
|
||||||
name: Test Google C++ test (CPU)
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [macos-12]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Install system packages
|
|
||||||
run: |
|
|
||||||
brew install ninja libomp
|
|
||||||
- name: Build gtest binary
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DGOOGLE_TEST=ON -DUSE_OPENMP=ON -DUSE_DMLC_GTEST=ON -GNinja -DBUILD_DEPRECATED_CLI=ON -DUSE_SANITIZER=ON -DENABLED_SANITIZERS=address -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
ninja -v
|
|
||||||
- name: Run gtest binary
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
./testxgboost
|
|
||||||
ctest -R TestXGBoostCLI --extra-verbose
|
|
||||||
|
|
||||||
gtest-cpu-nonomp:
|
|
||||||
name: Test Google C++ unittest (CPU Non-OMP)
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Install system packages
|
|
||||||
run: |
|
|
||||||
sudo apt-get install -y --no-install-recommends ninja-build
|
|
||||||
- name: Build and install XGBoost
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON -DUSE_OPENMP=OFF -DBUILD_DEPRECATED_CLI=ON
|
|
||||||
ninja -v
|
|
||||||
- name: Run gtest binary
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
ctest --extra-verbose
|
|
||||||
|
|
||||||
gtest-cpu-sycl:
|
|
||||||
name: Test Google C++ unittest (CPU SYCL)
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
python-version: ["3.10"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: linux_sycl_test
|
|
||||||
environment-file: tests/ci_build/conda_env/linux_sycl_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
- name: Build and install XGBoost
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON -DPLUGIN_SYCL=ON -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX
|
|
||||||
make -j$(nproc)
|
|
||||||
- name: Run gtest binary for SYCL
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
./testxgboost --gtest_filter=Sycl*
|
|
||||||
- name: Run gtest binary for non SYCL
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
./testxgboost --gtest_filter=-Sycl*
|
|
||||||
|
|
||||||
c-api-demo:
|
|
||||||
name: Test installing XGBoost lib + building the C API demo
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -l {0}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: ["ubuntu-latest"]
|
|
||||||
python-version: ["3.10"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: cpp_test
|
|
||||||
environment-file: tests/ci_build/conda_env/cpp_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
|
|
||||||
- name: Build and install XGBoost static library
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DBUILD_STATIC_LIB=ON -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -GNinja
|
|
||||||
ninja -v install
|
|
||||||
cd -
|
|
||||||
- name: Build and run C API demo with static
|
|
||||||
run: |
|
|
||||||
pushd .
|
|
||||||
cd demo/c-api/
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
|
|
||||||
ninja -v
|
|
||||||
ctest
|
|
||||||
cd ..
|
|
||||||
rm -rf ./build
|
|
||||||
popd
|
|
||||||
|
|
||||||
- name: Build and install XGBoost shared library
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
cmake .. -DBUILD_STATIC_LIB=OFF -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX -GNinja -DPLUGIN_FEDERATED=ON -DGOOGLE_TEST=ON
|
|
||||||
ninja -v install
|
|
||||||
./testxgboost
|
|
||||||
cd -
|
|
||||||
- name: Build and run C API demo with shared
|
|
||||||
run: |
|
|
||||||
pushd .
|
|
||||||
cd demo/c-api/
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
|
|
||||||
ninja -v
|
|
||||||
ctest
|
|
||||||
popd
|
|
||||||
./tests/ci_build/verify_link.sh ./demo/c-api/build/basic/api-demo
|
|
||||||
./tests/ci_build/verify_link.sh ./demo/c-api/build/external-memory/external-memory-demo
|
|
||||||
|
|
||||||
cpp-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Code linting for C++
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
|
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
architecture: 'x64'
|
|
||||||
- name: Install Python packages
|
|
||||||
run: |
|
|
||||||
python -m pip install wheel setuptools cmakelint cpplint pylint
|
|
||||||
- name: Run lint
|
|
||||||
run: |
|
|
||||||
python3 tests/ci_build/lint_cpp.py
|
|
||||||
sh ./tests/ci_build/lint_cmake.sh
|
|
||||||
348
.github/workflows/python_tests.yml
vendored
348
.github/workflows/python_tests.yml
vendored
@@ -1,348 +0,0 @@
|
|||||||
name: XGBoost-Python-Tests
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -l {0}
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
python-mypy-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Type and format checks for the Python package
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: python_lint
|
|
||||||
environment-file: tests/ci_build/conda_env/python_lint.yml
|
|
||||||
use-mamba: true
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
- name: Run mypy
|
|
||||||
run: |
|
|
||||||
python tests/ci_build/lint_python.py --format=0 --type-check=1 --pylint=0
|
|
||||||
- name: Run formatter
|
|
||||||
run: |
|
|
||||||
python tests/ci_build/lint_python.py --format=1 --type-check=0 --pylint=0
|
|
||||||
- name: Run pylint
|
|
||||||
run: |
|
|
||||||
python tests/ci_build/lint_python.py --format=0 --type-check=0 --pylint=1
|
|
||||||
|
|
||||||
python-sdist-test-on-Linux:
|
|
||||||
# Mismatched glibcxx version between system and conda forge.
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
name: Test installing XGBoost Python source package on ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: sdist_test
|
|
||||||
environment-file: tests/ci_build/conda_env/sdist_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
- name: Build and install XGBoost
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
python -m build --sdist
|
|
||||||
pip install -v ./dist/xgboost-*.tar.gz --config-settings use_openmp=False
|
|
||||||
cd ..
|
|
||||||
python -c 'import xgboost'
|
|
||||||
|
|
||||||
python-sdist-test:
|
|
||||||
# Use system toolchain instead of conda toolchain for macos and windows.
|
|
||||||
# MacOS has linker error if clang++ from conda-forge is used
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
name: Test installing XGBoost Python source package on ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [macos-13, windows-latest]
|
|
||||||
python-version: ["3.10"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Install osx system dependencies
|
|
||||||
if: matrix.os == 'macos-13'
|
|
||||||
run: |
|
|
||||||
brew install ninja libomp
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
auto-update-conda: true
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
activate-environment: test
|
|
||||||
- name: Install build
|
|
||||||
run: |
|
|
||||||
conda install -c conda-forge python-build
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
- name: Build and install XGBoost
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
python -m build --sdist
|
|
||||||
pip install -v ./dist/xgboost-*.tar.gz
|
|
||||||
cd ..
|
|
||||||
python -c 'import xgboost'
|
|
||||||
|
|
||||||
python-tests-on-macos:
|
|
||||||
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
timeout-minutes: 60
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: macos-13}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: macos_cpu_test
|
|
||||||
environment-file: tests/ci_build/conda_env/macos_cpu_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
|
|
||||||
- name: Build XGBoost on macos
|
|
||||||
run: |
|
|
||||||
brew install ninja
|
|
||||||
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
# Set prefix, to use OpenMP library from Conda env
|
|
||||||
# See https://github.com/dmlc/xgboost/issues/7039#issuecomment-1025038228
|
|
||||||
# to learn why we don't use libomp from Homebrew.
|
|
||||||
cmake .. -GNinja -DCMAKE_PREFIX_PATH=$CONDA_PREFIX -DBUILD_DEPRECATED_CLI=ON
|
|
||||||
ninja
|
|
||||||
|
|
||||||
- name: Install Python package
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
pip install -v .
|
|
||||||
|
|
||||||
- name: Test Python package
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/python
|
|
||||||
|
|
||||||
- name: Test Dask Interface
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/test_distributed/test_with_dask
|
|
||||||
|
|
||||||
python-tests-on-win:
|
|
||||||
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
timeout-minutes: 60
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: windows-latest, python-version: '3.10'}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
auto-update-conda: true
|
|
||||||
python-version: ${{ matrix.config.python-version }}
|
|
||||||
activate-environment: win64_env
|
|
||||||
environment-file: tests/ci_build/conda_env/win64_cpu_test.yml
|
|
||||||
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
|
|
||||||
- name: Build XGBoost on Windows
|
|
||||||
run: |
|
|
||||||
mkdir build_msvc
|
|
||||||
cd build_msvc
|
|
||||||
cmake .. -G"Visual Studio 17 2022" -DCMAKE_CONFIGURATION_TYPES="Release" -A x64 -DBUILD_DEPRECATED_CLI=ON
|
|
||||||
cmake --build . --config Release --parallel $(nproc)
|
|
||||||
|
|
||||||
- name: Install Python package
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
pip wheel -v . --wheel-dir dist/
|
|
||||||
pip install ./dist/*.whl
|
|
||||||
|
|
||||||
- name: Test Python package
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/python
|
|
||||||
|
|
||||||
python-tests-on-ubuntu:
|
|
||||||
name: Test XGBoost Python package on ${{ matrix.config.os }}
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
timeout-minutes: 90
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: ubuntu-latest, python-version: "3.10"}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: linux_cpu_test
|
|
||||||
environment-file: tests/ci_build/conda_env/linux_cpu_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
|
|
||||||
- name: Build XGBoost on Ubuntu
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja -DCMAKE_PREFIX_PATH=$CONDA_PREFIX -DBUILD_DEPRECATED_CLI=ON
|
|
||||||
ninja
|
|
||||||
|
|
||||||
- name: Install Python package
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
pip install -v .
|
|
||||||
|
|
||||||
- name: Test Python package
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/python
|
|
||||||
|
|
||||||
- name: Test Dask Interface
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/test_distributed/test_with_dask
|
|
||||||
|
|
||||||
- name: Test PySpark Interface
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/test_distributed/test_with_spark
|
|
||||||
|
|
||||||
python-sycl-tests-on-ubuntu:
|
|
||||||
name: Test XGBoost Python package with SYCL on ${{ matrix.config.os }}
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
timeout-minutes: 90
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: ubuntu-latest, python-version: "3.10"}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
activate-environment: linux_sycl_test
|
|
||||||
environment-file: tests/ci_build/conda_env/linux_sycl_test.yml
|
|
||||||
use-mamba: true
|
|
||||||
|
|
||||||
- name: Display Conda env
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list
|
|
||||||
- name: Build XGBoost on Ubuntu
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DPLUGIN_SYCL=ON -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
|
|
||||||
make -j$(nproc)
|
|
||||||
- name: Install Python package
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
python --version
|
|
||||||
pip install -v .
|
|
||||||
- name: Test Python package
|
|
||||||
run: |
|
|
||||||
pytest -s -v -rxXs --durations=0 ./tests/python-sycl/
|
|
||||||
|
|
||||||
|
|
||||||
python-system-installation-on-ubuntu:
|
|
||||||
name: Test XGBoost Python package System Installation on ${{ matrix.os }}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- name: Set up Python 3.10
|
|
||||||
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
|
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
|
|
||||||
- name: Install ninja
|
|
||||||
run: |
|
|
||||||
sudo apt-get update && sudo apt-get install -y ninja-build
|
|
||||||
|
|
||||||
- name: Build XGBoost on Ubuntu
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -GNinja
|
|
||||||
ninja
|
|
||||||
|
|
||||||
- name: Copy lib to system lib
|
|
||||||
run: |
|
|
||||||
cp lib/* "$(python -c 'import sys; print(sys.base_prefix)')/lib"
|
|
||||||
|
|
||||||
- name: Install XGBoost in Virtual Environment
|
|
||||||
run: |
|
|
||||||
cd python-package
|
|
||||||
pip install virtualenv
|
|
||||||
virtualenv venv
|
|
||||||
source venv/bin/activate && \
|
|
||||||
pip install -v . --config-settings use_system_libxgboost=True && \
|
|
||||||
python -c 'import xgboost'
|
|
||||||
55
.github/workflows/python_wheels.yml
vendored
55
.github/workflows/python_wheels.yml
vendored
@@ -1,55 +0,0 @@
|
|||||||
name: XGBoost-Python-Wheels
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -l {0}
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
python-wheels:
|
|
||||||
name: Build wheel for ${{ matrix.platform_id }}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: macos-13
|
|
||||||
platform_id: macosx_x86_64
|
|
||||||
- os: macos-14
|
|
||||||
platform_id: macosx_arm64
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Set up homebrew
|
|
||||||
uses: Homebrew/actions/setup-homebrew@68fa6aeb1ccb0596d311f2b34ec74ec21ee68e54
|
|
||||||
- name: Install libomp
|
|
||||||
run: brew install libomp
|
|
||||||
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4
|
|
||||||
with:
|
|
||||||
miniforge-variant: Mambaforge
|
|
||||||
miniforge-version: latest
|
|
||||||
python-version: "3.10"
|
|
||||||
use-mamba: true
|
|
||||||
- name: Build wheels
|
|
||||||
run: bash tests/ci_build/build_python_wheels.sh ${{ matrix.platform_id }} ${{ github.sha }}
|
|
||||||
- name: Extract branch name
|
|
||||||
run: |
|
|
||||||
echo "branch=${GITHUB_REF#refs/heads/}" >> "$GITHUB_OUTPUT"
|
|
||||||
id: extract_branch
|
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
|
||||||
- name: Upload Python wheel
|
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/heads/release_')
|
|
||||||
run: |
|
|
||||||
python -m pip install awscli
|
|
||||||
python -m awscli s3 cp wheelhouse/*.whl s3://xgboost-nightly-builds/${{ steps.extract_branch.outputs.branch }}/ --acl public-read --region us-west-2
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_IAM_S3_UPLOADER }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_IAM_S3_UPLOADER }}
|
|
||||||
44
.github/workflows/r_nold.yml
vendored
44
.github/workflows/r_nold.yml
vendored
@@ -1,44 +0,0 @@
|
|||||||
# Run expensive R tests with the help of rhub. Only triggered by a pull request review
|
|
||||||
# See discussion at https://github.com/dmlc/xgboost/pull/6378
|
|
||||||
|
|
||||||
name: XGBoost-R-noLD
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_review_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-R-noLD:
|
|
||||||
if: github.event.comment.body == '/gha run r-nold-test' && contains('OWNER,MEMBER,COLLABORATOR', github.event.comment.author_association)
|
|
||||||
timeout-minutes: 120
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: rhub/debian-gcc-devel-nold
|
|
||||||
steps:
|
|
||||||
- name: Install git and system packages
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
apt update && apt install libcurl4-openssl-dev libssl-dev libssh2-1-dev libgit2-dev libglpk-dev libxml2-dev libharfbuzz-dev libfribidi-dev git -y
|
|
||||||
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
/tmp/R-devel/bin/Rscript -e "source('./R-package/tests/helper_scripts/install_deps.R')"
|
|
||||||
|
|
||||||
- name: Run R tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cd R-package && \
|
|
||||||
/tmp/R-devel/bin/R CMD INSTALL . && \
|
|
||||||
/tmp/R-devel/bin/R -q -e "library(testthat); setwd('tests'); source('testthat.R')"
|
|
||||||
150
.github/workflows/r_tests.yml
vendored
150
.github/workflows/r_tests.yml
vendored
@@ -1,150 +0,0 @@
|
|||||||
name: XGBoost-R-Tests
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # to fetch code (actions/checkout)
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lintr:
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
name: Run R linters on OS ${{ matrix.config.os }}, R ${{ matrix.config.r }}, Compiler ${{ matrix.config.compiler }}, Build ${{ matrix.config.build }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: ubuntu-latest, r: 'release'}
|
|
||||||
env:
|
|
||||||
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
|
|
||||||
RSPM: ${{ matrix.config.rspm }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: r-lib/actions/setup-r@929c772977a3a13c8733b363bf5a2f685c25dd91 # v2.9.0
|
|
||||||
with:
|
|
||||||
r-version: ${{ matrix.config.r }}
|
|
||||||
|
|
||||||
- name: Cache R packages
|
|
||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
|
||||||
with:
|
|
||||||
path: ${{ env.R_LIBS_USER }}
|
|
||||||
key: ${{ runner.os }}-r-${{ matrix.config.r }}-7-${{ hashFiles('R-package/DESCRIPTION') }}
|
|
||||||
restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}-7-${{ hashFiles('R-package/DESCRIPTION') }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: Rscript {0}
|
|
||||||
run: |
|
|
||||||
source("./R-package/tests/helper_scripts/install_deps.R")
|
|
||||||
|
|
||||||
- name: Run lintr
|
|
||||||
run: |
|
|
||||||
MAKEFLAGS="-j$(nproc)" R CMD INSTALL R-package/
|
|
||||||
Rscript tests/ci_build/lint_r.R $(pwd)
|
|
||||||
|
|
||||||
test-Rpkg:
|
|
||||||
runs-on: ${{ matrix.config.os }}
|
|
||||||
name: Test R on OS ${{ matrix.config.os }}, R ${{ matrix.config.r }}, Compiler ${{ matrix.config.compiler }}, Build ${{ matrix.config.build }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
config:
|
|
||||||
- {os: windows-latest, r: 'release', compiler: 'mingw', build: 'autotools'}
|
|
||||||
- {os: ubuntu-latest, r: 'release', compiler: 'none', build: 'cmake'}
|
|
||||||
env:
|
|
||||||
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
|
|
||||||
RSPM: ${{ matrix.config.rspm }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install system dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install libcurl4-openssl-dev libssl-dev libssh2-1-dev libgit2-dev libglpk-dev libxml2-dev libharfbuzz-dev libfribidi-dev
|
|
||||||
if: matrix.config.os == 'ubuntu-latest'
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- uses: r-lib/actions/setup-r@929c772977a3a13c8733b363bf5a2f685c25dd91 # v2.9.0
|
|
||||||
with:
|
|
||||||
r-version: ${{ matrix.config.r }}
|
|
||||||
|
|
||||||
- name: Cache R packages
|
|
||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
|
||||||
with:
|
|
||||||
path: ${{ env.R_LIBS_USER }}
|
|
||||||
key: ${{ runner.os }}-r-${{ matrix.config.r }}-7-${{ hashFiles('R-package/DESCRIPTION') }}
|
|
||||||
restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}-7-${{ hashFiles('R-package/DESCRIPTION') }}
|
|
||||||
|
|
||||||
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
|
|
||||||
with:
|
|
||||||
python-version: "3.10"
|
|
||||||
architecture: 'x64'
|
|
||||||
|
|
||||||
- uses: r-lib/actions/setup-tinytex@v2
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: Rscript {0}
|
|
||||||
run: |
|
|
||||||
source("./R-package/tests/helper_scripts/install_deps.R")
|
|
||||||
|
|
||||||
- name: Test R
|
|
||||||
run: |
|
|
||||||
python tests/ci_build/test_r_package.py --compiler='${{ matrix.config.compiler }}' --build-tool="${{ matrix.config.build }}" --task=check
|
|
||||||
if: matrix.config.compiler != 'none'
|
|
||||||
|
|
||||||
- name: Test R
|
|
||||||
run: |
|
|
||||||
python tests/ci_build/test_r_package.py --build-tool="${{ matrix.config.build }}" --task=check
|
|
||||||
if: matrix.config.compiler == 'none'
|
|
||||||
|
|
||||||
test-R-on-Debian:
|
|
||||||
name: Test R package on Debian
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: rhub/debian-gcc-release
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install system dependencies
|
|
||||||
run: |
|
|
||||||
# Must run before checkout to have the latest git installed.
|
|
||||||
# No need to add pandoc, the container has it figured out.
|
|
||||||
apt update && apt install libcurl4-openssl-dev libssl-dev libssh2-1-dev libgit2-dev libglpk-dev libxml2-dev libharfbuzz-dev libfribidi-dev git -y
|
|
||||||
|
|
||||||
- name: Trust git cloning project sources
|
|
||||||
run: |
|
|
||||||
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
|
|
||||||
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
Rscript -e "source('./R-package/tests/helper_scripts/install_deps.R')"
|
|
||||||
|
|
||||||
- name: Test R
|
|
||||||
shell: bash -l {0}
|
|
||||||
run: |
|
|
||||||
python3 tests/ci_build/test_r_package.py --r=/usr/bin/R --build-tool=autotools --task=check
|
|
||||||
|
|
||||||
- uses: dorny/paths-filter@v3
|
|
||||||
id: changes
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
r_package:
|
|
||||||
- 'R-package/**'
|
|
||||||
|
|
||||||
- name: Run document check
|
|
||||||
if: steps.changes.outputs.r_package == 'true'
|
|
||||||
run: |
|
|
||||||
python3 tests/ci_build/test_r_package.py --r=/usr/bin/R --task=doc
|
|
||||||
54
.github/workflows/scorecards.yml
vendored
54
.github/workflows/scorecards.yml
vendored
@@ -1,54 +0,0 @@
|
|||||||
name: Scorecards supply-chain security
|
|
||||||
on:
|
|
||||||
# Only the default branch is supported.
|
|
||||||
branch_protection_rule:
|
|
||||||
schedule:
|
|
||||||
- cron: '17 2 * * 6'
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
|
|
||||||
# Declare default permissions as read only.
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analysis:
|
|
||||||
name: Scorecards analysis
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
# Needed to upload the results to code-scanning dashboard.
|
|
||||||
security-events: write
|
|
||||||
# Used to receive a badge.
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout code"
|
|
||||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: "Run analysis"
|
|
||||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
|
||||||
with:
|
|
||||||
results_file: results.sarif
|
|
||||||
results_format: sarif
|
|
||||||
|
|
||||||
# Publish the results for public repositories to enable scorecard badges. For more details, see
|
|
||||||
# https://github.com/ossf/scorecard-action#publishing-results.
|
|
||||||
# For private repositories, `publish_results` will automatically be set to `false`, regardless
|
|
||||||
# of the value entered here.
|
|
||||||
publish_results: true
|
|
||||||
|
|
||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
|
||||||
# format to the repository Actions tab.
|
|
||||||
- name: "Upload artifact"
|
|
||||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
|
||||||
with:
|
|
||||||
name: SARIF file
|
|
||||||
path: results.sarif
|
|
||||||
retention-days: 5
|
|
||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
|
||||||
- name: "Upload to code-scanning"
|
|
||||||
uses: github/codeql-action/upload-sarif@83a02f7883b12e0e4e1a146174f5e2292a01e601 # v2.16.4
|
|
||||||
with:
|
|
||||||
sarif_file: results.sarif
|
|
||||||
44
.github/workflows/update_rapids.yml
vendored
44
.github/workflows/update_rapids.yml
vendored
@@ -1,44 +0,0 @@
|
|||||||
name: update-rapids
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 20 * * 1" # Run once weekly
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -l {0}
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # To use GitHub CLI
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-rapids:
|
|
||||||
name: Check latest RAPIDS
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Check latest RAPIDS and update conftest.sh
|
|
||||||
run: |
|
|
||||||
bash tests/buildkite/update-rapids.sh
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v6
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
||||||
with:
|
|
||||||
add-paths: |
|
|
||||||
tests/buildkite
|
|
||||||
branch: create-pull-request/update-rapids
|
|
||||||
base: master
|
|
||||||
title: "[CI] Update RAPIDS to latest stable"
|
|
||||||
commit-message: "[CI] Update RAPIDS to latest stable"
|
|
||||||
|
|
||||||
151
.gitignore
vendored
151
.gitignore
vendored
@@ -2,160 +2,25 @@
|
|||||||
*.slo
|
*.slo
|
||||||
*.lo
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.page
|
|
||||||
# Compiled Dynamic libraries
|
# Compiled Dynamic libraries
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
*.page
|
|
||||||
# Compiled Static libraries
|
# Compiled Static libraries
|
||||||
*.lai
|
*.lai
|
||||||
*.la
|
*.la
|
||||||
*.a
|
*.a
|
||||||
*~
|
*~
|
||||||
*.Rcheck
|
*txt*
|
||||||
*.rds
|
|
||||||
*.tar.gz
|
|
||||||
*conf
|
*conf
|
||||||
*buffer
|
*buffer
|
||||||
*.model
|
*model
|
||||||
|
xgboost
|
||||||
*pyc
|
*pyc
|
||||||
*.train
|
*train
|
||||||
*.test
|
*test
|
||||||
*.tar
|
|
||||||
*group
|
*group
|
||||||
*rar
|
*rar
|
||||||
*vali
|
*vali
|
||||||
*sdf
|
*data
|
||||||
Release
|
|
||||||
*exe
|
|
||||||
*exp
|
|
||||||
ipch
|
|
||||||
*.filters
|
|
||||||
*.user
|
|
||||||
*log
|
|
||||||
rmm_log.txt
|
|
||||||
Debug
|
|
||||||
*suo
|
|
||||||
.Rhistory
|
|
||||||
*.dll
|
|
||||||
*i386
|
|
||||||
*x64
|
|
||||||
*dump
|
|
||||||
*save
|
|
||||||
*csv
|
|
||||||
.Rproj.user
|
|
||||||
*.cpage.col
|
|
||||||
*.cpage
|
|
||||||
*.Rproj
|
|
||||||
./xgboost.mpi
|
|
||||||
./xgboost.mock
|
|
||||||
*.bak
|
|
||||||
#.Rbuildignore
|
|
||||||
R-package.Rproj
|
|
||||||
*.cache*
|
|
||||||
.mypy_cache/
|
|
||||||
doxygen
|
|
||||||
|
|
||||||
# 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
|
|
||||||
.classpath
|
|
||||||
.pydevproject
|
|
||||||
.settings/
|
|
||||||
build
|
|
||||||
/xgboost
|
|
||||||
*.data
|
|
||||||
build_plugin
|
|
||||||
recommonmark/
|
|
||||||
tags
|
|
||||||
TAGS
|
|
||||||
*.class
|
|
||||||
target
|
|
||||||
*.swp
|
|
||||||
|
|
||||||
# cpp tests and gcov generated files
|
|
||||||
*.gcov
|
|
||||||
*.gcda
|
|
||||||
*.gcno
|
|
||||||
*.ubj
|
|
||||||
build_tests
|
|
||||||
/tests/cpp/xgboost_test
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
lib/
|
|
||||||
|
|
||||||
# spark
|
|
||||||
metastore_db
|
|
||||||
|
|
||||||
/include/xgboost/build_config.h
|
|
||||||
|
|
||||||
# files from R-package source install
|
|
||||||
**/config.status
|
|
||||||
R-package/config.h
|
|
||||||
R-package/src/Makevars
|
|
||||||
*.lib
|
|
||||||
|
|
||||||
# Visual Studio
|
|
||||||
.vs/
|
|
||||||
CMakeSettings.json
|
|
||||||
*.ilk
|
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# IntelliJ/CLion
|
|
||||||
.idea
|
|
||||||
*.iml
|
|
||||||
/cmake-build-debug/
|
|
||||||
|
|
||||||
# GDB
|
|
||||||
.gdb_history
|
|
||||||
|
|
||||||
# Python joblib.Memory used in pytest.
|
|
||||||
cachedir/
|
|
||||||
|
|
||||||
# Files from local Dask work
|
|
||||||
dask-worker-space/
|
|
||||||
|
|
||||||
# Jupyter notebook checkpoints
|
|
||||||
.ipynb_checkpoints/
|
|
||||||
|
|
||||||
# credentials and key material
|
|
||||||
config
|
|
||||||
credentials
|
|
||||||
credentials.csv
|
|
||||||
*.env
|
|
||||||
*.pem
|
|
||||||
*.pub
|
|
||||||
*.rdp
|
|
||||||
*_rsa
|
|
||||||
|
|
||||||
# Visual Studio code + extensions
|
|
||||||
.vscode
|
|
||||||
.metals
|
|
||||||
.bloop
|
|
||||||
|
|
||||||
# python tests
|
|
||||||
demo/**/*.txt
|
|
||||||
*.dmatrix
|
|
||||||
.hypothesis
|
|
||||||
__MACOSX/
|
|
||||||
model*.json
|
|
||||||
|
|
||||||
# R tests
|
|
||||||
*.htm
|
|
||||||
*.html
|
|
||||||
*.libsvm
|
|
||||||
*.rds
|
|
||||||
Rplots.pdf
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# nsys
|
|
||||||
*.nsys-rep
|
|
||||||
|
|||||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -1,7 +0,0 @@
|
|||||||
[submodule "dmlc-core"]
|
|
||||||
path = dmlc-core
|
|
||||||
url = https://github.com/dmlc/dmlc-core
|
|
||||||
branch = main
|
|
||||||
[submodule "gputreeshap"]
|
|
||||||
path = gputreeshap
|
|
||||||
url = https://github.com/rapidsai/gputreeshap.git
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# .readthedocs.yaml
|
|
||||||
# Read the Docs configuration file
|
|
||||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
||||||
|
|
||||||
# Required
|
|
||||||
version: 2
|
|
||||||
|
|
||||||
submodules:
|
|
||||||
include: all
|
|
||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
|
||||||
build:
|
|
||||||
os: ubuntu-22.04
|
|
||||||
tools:
|
|
||||||
python: "3.10"
|
|
||||||
apt_packages:
|
|
||||||
- graphviz
|
|
||||||
- cmake
|
|
||||||
- g++
|
|
||||||
- doxygen
|
|
||||||
- ninja-build
|
|
||||||
|
|
||||||
# Build documentation in the docs/ directory with Sphinx
|
|
||||||
sphinx:
|
|
||||||
configuration: doc/conf.py
|
|
||||||
|
|
||||||
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
|
||||||
formats:
|
|
||||||
- pdf
|
|
||||||
|
|
||||||
# Optionally declare the Python requirements required to build your docs
|
|
||||||
python:
|
|
||||||
install:
|
|
||||||
- requirements: doc/requirements.txt
|
|
||||||
17
CITATION
17
CITATION
@@ -1,17 +0,0 @@
|
|||||||
@inproceedings{Chen:2016:XST:2939672.2939785,
|
|
||||||
author = {Chen, Tianqi and Guestrin, Carlos},
|
|
||||||
title = {{XGBoost}: A Scalable Tree Boosting System},
|
|
||||||
booktitle = {Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining},
|
|
||||||
series = {KDD '16},
|
|
||||||
year = {2016},
|
|
||||||
isbn = {978-1-4503-4232-2},
|
|
||||||
location = {San Francisco, California, USA},
|
|
||||||
pages = {785--794},
|
|
||||||
numpages = {10},
|
|
||||||
url = {http://doi.acm.org/10.1145/2939672.2939785},
|
|
||||||
doi = {10.1145/2939672.2939785},
|
|
||||||
acmid = {2939785},
|
|
||||||
publisher = {ACM},
|
|
||||||
address = {New York, NY, USA},
|
|
||||||
keywords = {large-scale machine learning},
|
|
||||||
}
|
|
||||||
513
CMakeLists.txt
513
CMakeLists.txt
@@ -1,513 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
|
|
||||||
|
|
||||||
if(PLUGIN_SYCL)
|
|
||||||
string(REPLACE " -isystem ${CONDA_PREFIX}/include" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(xgboost LANGUAGES CXX C VERSION 2.2.0)
|
|
||||||
include(cmake/Utils.cmake)
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${xgboost_SOURCE_DIR}/cmake/modules")
|
|
||||||
|
|
||||||
# These policies are already set from 3.18 but we still need to set the policy
|
|
||||||
# default variables here for lower minimum versions in the submodules
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0076 NEW)
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0079 NEW)
|
|
||||||
|
|
||||||
message(STATUS "CMake version ${CMAKE_VERSION}")
|
|
||||||
|
|
||||||
# Check compiler versions
|
|
||||||
# Use recent compilers to ensure that std::filesystem is available
|
|
||||||
if(MSVC)
|
|
||||||
if(MSVC_VERSION LESS 1920)
|
|
||||||
message(FATAL_ERROR "Need Visual Studio 2019 or newer to build XGBoost")
|
|
||||||
endif()
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.1")
|
|
||||||
message(FATAL_ERROR "Need GCC 8.1 or newer to build XGBoost")
|
|
||||||
endif()
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "11.0")
|
|
||||||
message(FATAL_ERROR "Need Xcode 11.0 (AppleClang 11.0) or newer to build XGBoost")
|
|
||||||
endif()
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0")
|
|
||||||
message(FATAL_ERROR "Need Clang 9.0 or newer to build XGBoost")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(${xgboost_SOURCE_DIR}/cmake/PrefetchIntrinsics.cmake)
|
|
||||||
find_prefetch_intrinsics()
|
|
||||||
include(${xgboost_SOURCE_DIR}/cmake/Version.cmake)
|
|
||||||
write_version()
|
|
||||||
set_default_configuration_release()
|
|
||||||
|
|
||||||
#-- Options
|
|
||||||
include(CMakeDependentOption)
|
|
||||||
|
|
||||||
## User options
|
|
||||||
option(BUILD_C_DOC "Build documentation for C APIs using Doxygen." OFF)
|
|
||||||
option(USE_OPENMP "Build with OpenMP support." ON)
|
|
||||||
option(BUILD_STATIC_LIB "Build static library" OFF)
|
|
||||||
option(BUILD_DEPRECATED_CLI "Build the deprecated command line interface" OFF)
|
|
||||||
option(FORCE_SHARED_CRT "Build with dynamic CRT on Windows (/MD)" OFF)
|
|
||||||
## Bindings
|
|
||||||
option(JVM_BINDINGS "Build JVM bindings" OFF)
|
|
||||||
option(R_LIB "Build shared library for R package" OFF)
|
|
||||||
## Dev
|
|
||||||
option(USE_DEBUG_OUTPUT "Dump internal training results like gradients and predictions to stdout.
|
|
||||||
Should only be used for debugging." OFF)
|
|
||||||
option(FORCE_COLORED_OUTPUT "Force colored output from compilers, useful when ninja is used instead of make." OFF)
|
|
||||||
option(ENABLE_ALL_WARNINGS "Enable all compiler warnings. Only effective for GCC/Clang" OFF)
|
|
||||||
option(LOG_CAPI_INVOCATION "Log all C API invocations for debugging" OFF)
|
|
||||||
option(GOOGLE_TEST "Build google tests" OFF)
|
|
||||||
option(USE_DMLC_GTEST "Use google tests bundled with dmlc-core submodule" OFF)
|
|
||||||
option(USE_DEVICE_DEBUG "Generate CUDA device debug info." OFF)
|
|
||||||
option(USE_NVTX "Build with cuda profiling annotations. Developers only." OFF)
|
|
||||||
set(NVTX_HEADER_DIR "" CACHE PATH "Path to the stand-alone nvtx header")
|
|
||||||
option(HIDE_CXX_SYMBOLS "Build shared library and hide all C++ symbols" OFF)
|
|
||||||
option(KEEP_BUILD_ARTIFACTS_IN_BINARY_DIR "Output build artifacts in CMake binary dir" OFF)
|
|
||||||
## CUDA
|
|
||||||
option(USE_CUDA "Build with GPU acceleration" OFF)
|
|
||||||
option(USE_NCCL "Build with NCCL to enable distributed GPU support." OFF)
|
|
||||||
# This is specifically designed for PyPI binary release and should be disabled for most of the cases.
|
|
||||||
option(USE_DLOPEN_NCCL "Whether to load nccl dynamically." OFF)
|
|
||||||
option(BUILD_WITH_SHARED_NCCL "Build with shared NCCL library." OFF)
|
|
||||||
|
|
||||||
if(USE_CUDA)
|
|
||||||
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES AND NOT DEFINED ENV{CUDAARCHS})
|
|
||||||
set(GPU_COMPUTE_VER "" CACHE STRING
|
|
||||||
"Semicolon separated list of compute versions to be built against, e.g. '35;61'")
|
|
||||||
else()
|
|
||||||
# Clear any cached values from previous runs
|
|
||||||
unset(GPU_COMPUTE_VER)
|
|
||||||
unset(GPU_COMPUTE_VER CACHE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CUDA device LTO was introduced in CMake v3.25 and requires host LTO to also be enabled but can still
|
|
||||||
# be explicitly disabled allowing for LTO on host only, host and device, or neither, but device-only LTO
|
|
||||||
# is not a supproted configuration
|
|
||||||
cmake_dependent_option(USE_CUDA_LTO
|
|
||||||
"Enable link-time optimization for CUDA device code"
|
|
||||||
"${CMAKE_INTERPROCEDURAL_OPTIMIZATION}"
|
|
||||||
"CMAKE_VERSION VERSION_GREATER_EQUAL 3.25;USE_CUDA;CMAKE_INTERPROCEDURAL_OPTIMIZATION"
|
|
||||||
OFF)
|
|
||||||
## Sanitizers
|
|
||||||
option(USE_SANITIZER "Use santizer flags" OFF)
|
|
||||||
option(SANITIZER_PATH "Path to sanitizes.")
|
|
||||||
set(ENABLED_SANITIZERS "address" "leak" CACHE STRING
|
|
||||||
"Semicolon separated list of sanitizer names. E.g 'address;leak'. Supported sanitizers are
|
|
||||||
address, leak, undefined and thread.")
|
|
||||||
## Plugins
|
|
||||||
option(PLUGIN_RMM "Build with RAPIDS Memory Manager (RMM)" OFF)
|
|
||||||
option(PLUGIN_FEDERATED "Build with Federated Learning" OFF)
|
|
||||||
## TODO: 1. Add check if DPC++ compiler is used for building
|
|
||||||
option(PLUGIN_SYCL "SYCL plugin" OFF)
|
|
||||||
option(ADD_PKGCONFIG "Add xgboost.pc into system." ON)
|
|
||||||
|
|
||||||
#-- Checks for building XGBoost
|
|
||||||
if(USE_DEBUG_OUTPUT AND (NOT (CMAKE_BUILD_TYPE MATCHES Debug)))
|
|
||||||
message(SEND_ERROR "Do not enable `USE_DEBUG_OUTPUT' with release build.")
|
|
||||||
endif()
|
|
||||||
if(USE_NCCL AND NOT (USE_CUDA))
|
|
||||||
message(SEND_ERROR "`USE_NCCL` must be enabled with `USE_CUDA` flag.")
|
|
||||||
endif()
|
|
||||||
if(USE_DEVICE_DEBUG AND NOT (USE_CUDA))
|
|
||||||
message(SEND_ERROR "`USE_DEVICE_DEBUG` must be enabled with `USE_CUDA` flag.")
|
|
||||||
endif()
|
|
||||||
if(BUILD_WITH_SHARED_NCCL AND (NOT USE_NCCL))
|
|
||||||
message(SEND_ERROR "Build XGBoost with -DUSE_NCCL=ON to enable BUILD_WITH_SHARED_NCCL.")
|
|
||||||
endif()
|
|
||||||
if(USE_DLOPEN_NCCL AND (NOT USE_NCCL))
|
|
||||||
message(SEND_ERROR "Build XGBoost with -DUSE_NCCL=ON to enable USE_DLOPEN_NCCL.")
|
|
||||||
endif()
|
|
||||||
if(USE_DLOPEN_NCCL AND (NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux")))
|
|
||||||
message(SEND_ERROR "`USE_DLOPEN_NCCL` supports only Linux at the moment.")
|
|
||||||
endif()
|
|
||||||
if(JVM_BINDINGS AND R_LIB)
|
|
||||||
message(SEND_ERROR "`R_LIB' is not compatible with `JVM_BINDINGS' as they both have customized configurations.")
|
|
||||||
endif()
|
|
||||||
if(R_LIB AND GOOGLE_TEST)
|
|
||||||
message(
|
|
||||||
WARNING
|
|
||||||
"Some C++ tests will fail with `R_LIB` enabled, as R package redirects some functions to R runtime implementation."
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_RMM AND NOT (USE_CUDA))
|
|
||||||
message(SEND_ERROR "`PLUGIN_RMM` must be enabled with `USE_CUDA` flag.")
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_RMM AND NOT ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")))
|
|
||||||
message(SEND_ERROR "`PLUGIN_RMM` must be used with GCC or Clang compiler.")
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_RMM AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
|
|
||||||
message(SEND_ERROR "`PLUGIN_RMM` must be used with Linux.")
|
|
||||||
endif()
|
|
||||||
if(ENABLE_ALL_WARNINGS)
|
|
||||||
if((NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU"))
|
|
||||||
message(SEND_ERROR "ENABLE_ALL_WARNINGS is only available for Clang and GCC.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(BUILD_STATIC_LIB AND (R_LIB OR JVM_BINDINGS))
|
|
||||||
message(SEND_ERROR "Cannot build a static library libxgboost.a when R or JVM packages are enabled.")
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_FEDERATED)
|
|
||||||
if(CMAKE_CROSSCOMPILING)
|
|
||||||
message(SEND_ERROR "Cannot cross compile with federated learning support")
|
|
||||||
endif()
|
|
||||||
if(BUILD_STATIC_LIB)
|
|
||||||
message(SEND_ERROR "Cannot build static lib with federated learning support")
|
|
||||||
endif()
|
|
||||||
if(R_LIB OR JVM_BINDINGS)
|
|
||||||
message(SEND_ERROR "Cannot enable federated learning support when R or JVM packages are enabled.")
|
|
||||||
endif()
|
|
||||||
if(WIN32)
|
|
||||||
message(SEND_ERROR "Federated learning not supported for Windows platform")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-- Removed options
|
|
||||||
if(USE_AVX)
|
|
||||||
message(SEND_ERROR "The option `USE_AVX` is deprecated as experimental AVX features have been removed from XGBoost.")
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_LZ4)
|
|
||||||
message(SEND_ERROR "The option `PLUGIN_LZ4` is removed from XGBoost.")
|
|
||||||
endif()
|
|
||||||
if(RABIT_BUILD_MPI)
|
|
||||||
message(SEND_ERROR "The option `RABIT_BUILD_MPI` has been removed from XGBoost.")
|
|
||||||
endif()
|
|
||||||
if(USE_S3)
|
|
||||||
message(SEND_ERROR "The option `USE_S3` has been removed from XGBoost")
|
|
||||||
endif()
|
|
||||||
if(USE_AZURE)
|
|
||||||
message(SEND_ERROR "The option `USE_AZURE` has been removed from XGBoost")
|
|
||||||
endif()
|
|
||||||
if(USE_HDFS)
|
|
||||||
message(SEND_ERROR "The option `USE_HDFS` has been removed from XGBoost")
|
|
||||||
endif()
|
|
||||||
if(PLUGIN_DENSE_PARSER)
|
|
||||||
message(SEND_ERROR "The option `PLUGIN_DENSE_PARSER` has been removed from XGBoost.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-- Sanitizer
|
|
||||||
if(USE_SANITIZER)
|
|
||||||
include(cmake/Sanitizer.cmake)
|
|
||||||
enable_sanitizers("${ENABLED_SANITIZERS}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_CUDA)
|
|
||||||
set(USE_OPENMP ON CACHE BOOL "CUDA requires OpenMP" FORCE)
|
|
||||||
# `export CXX=' is ignored by CMake CUDA.
|
|
||||||
if(NOT DEFINED CMAKE_CUDA_HOST_COMPILER AND NOT DEFINED ENV{CUDAHOSTCXX})
|
|
||||||
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH
|
|
||||||
"The compiler executable to use when compiling host code for CUDA or HIP language files.")
|
|
||||||
mark_as_advanced(CMAKE_CUDA_HOST_COMPILER)
|
|
||||||
message(STATUS "Configured CUDA host compiler: ${CMAKE_CUDA_HOST_COMPILER}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT DEFINED CMAKE_CUDA_RUNTIME_LIBRARY)
|
|
||||||
set(CMAKE_CUDA_RUNTIME_LIBRARY Static)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
enable_language(CUDA)
|
|
||||||
if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_LESS 11.0)
|
|
||||||
message(FATAL_ERROR "CUDA version must be at least 11.0!")
|
|
||||||
endif()
|
|
||||||
if(DEFINED GPU_COMPUTE_VER)
|
|
||||||
compute_cmake_cuda_archs("${GPU_COMPUTE_VER}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(CUDAToolkit REQUIRED)
|
|
||||||
find_package(CCCL CONFIG)
|
|
||||||
if(NOT CCCL_FOUND)
|
|
||||||
message(STATUS "Standalone CCCL not found. Attempting to use CCCL from CUDA Toolkit...")
|
|
||||||
find_package(CCCL CONFIG
|
|
||||||
HINTS ${CUDAToolkit_LIBRARY_DIR}/cmake)
|
|
||||||
if(NOT CCCL_FOUND)
|
|
||||||
message(STATUS "Could not locate CCCL from CUDA Toolkit. Using Thrust and CUB from CUDA Toolkit...")
|
|
||||||
find_package(libcudacxx CONFIG REQUIRED
|
|
||||||
HINTS ${CUDAToolkit_LIBRARY_DIR}/cmake)
|
|
||||||
find_package(CUB CONFIG REQUIRED
|
|
||||||
HINTS ${CUDAToolkit_LIBRARY_DIR}/cmake)
|
|
||||||
find_package(Thrust CONFIG REQUIRED
|
|
||||||
HINTS ${CUDAToolkit_LIBRARY_DIR}/cmake)
|
|
||||||
thrust_create_target(Thrust HOST CPP DEVICE CUDA)
|
|
||||||
add_library(CCCL::CCCL INTERFACE IMPORTED GLOBAL)
|
|
||||||
target_link_libraries(CCCL::CCCL INTERFACE libcudacxx::libcudacxx CUB::CUB Thrust)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FORCE_COLORED_OUTPUT AND (CMAKE_GENERATOR STREQUAL "Ninja") AND
|
|
||||||
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
|
|
||||||
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")))
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
|
|
||||||
# -- OpenMP
|
|
||||||
include(cmake/FindOpenMPMacOS.cmake)
|
|
||||||
if(USE_OPENMP)
|
|
||||||
if(APPLE)
|
|
||||||
find_openmp_macos()
|
|
||||||
else()
|
|
||||||
find_package(OpenMP REQUIRED)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add for IBM i
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "OS400")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
|
||||||
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> -X64 qc <TARGET> <OBJECTS>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_NCCL)
|
|
||||||
find_package(Nccl REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
if(FORCE_SHARED_CRT)
|
|
||||||
message(STATUS "XGBoost: Using dynamically linked MSVC runtime...")
|
|
||||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
||||||
else()
|
|
||||||
message(STATUS "XGBoost: Using statically linked MSVC runtime...")
|
|
||||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# dmlc-core
|
|
||||||
set(DMLC_FORCE_SHARED_CRT ${FORCE_SHARED_CRT})
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/dmlc-core)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
if(TARGET dmlc_unit_tests)
|
|
||||||
target_compile_options(
|
|
||||||
dmlc_unit_tests PRIVATE
|
|
||||||
-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# core xgboost
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/src)
|
|
||||||
target_link_libraries(objxgboost PUBLIC dmlc)
|
|
||||||
|
|
||||||
# Link -lstdc++fs for GCC 8.x
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0")
|
|
||||||
target_link_libraries(objxgboost PUBLIC stdc++fs)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Exports some R specific definitions and objects
|
|
||||||
if(R_LIB)
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/R-package)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# This creates its own shared library `xgboost4j'.
|
|
||||||
if(JVM_BINDINGS)
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/jvm-packages)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Plugin
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/plugin)
|
|
||||||
|
|
||||||
if(PLUGIN_RMM)
|
|
||||||
find_package(rmm REQUIRED)
|
|
||||||
|
|
||||||
# Patch the rmm targets so they reference the static cudart
|
|
||||||
# Remove this patch once RMM stops specifying cudart requirement
|
|
||||||
# (since RMM is a header-only library, it should not specify cudart in its CMake config)
|
|
||||||
get_target_property(rmm_link_libs rmm::rmm INTERFACE_LINK_LIBRARIES)
|
|
||||||
list(REMOVE_ITEM rmm_link_libs CUDA::cudart)
|
|
||||||
list(APPEND rmm_link_libs CUDA::cudart_static)
|
|
||||||
set_target_properties(rmm::rmm PROPERTIES INTERFACE_LINK_LIBRARIES "${rmm_link_libs}")
|
|
||||||
get_target_property(rmm_link_libs rmm::rmm INTERFACE_LINK_LIBRARIES)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(PLUGIN_SYCL)
|
|
||||||
set(CMAKE_CXX_LINK_EXECUTABLE
|
|
||||||
"icpx <FLAGS> <CMAKE_CXX_LINK_FLAGS> -qopenmp <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
|
||||||
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
|
|
||||||
"icpx <CMAKE_SHARED_LIBRARY_CXX_FLAGS> -qopenmp <LANGUAGE_COMPILE_FLAGS> \
|
|
||||||
<CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG>,<TARGET_SONAME> \
|
|
||||||
-o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-- library
|
|
||||||
if(BUILD_STATIC_LIB)
|
|
||||||
add_library(xgboost STATIC)
|
|
||||||
else()
|
|
||||||
add_library(xgboost SHARED)
|
|
||||||
endif()
|
|
||||||
target_link_libraries(xgboost PRIVATE objxgboost)
|
|
||||||
target_include_directories(xgboost
|
|
||||||
INTERFACE
|
|
||||||
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
|
|
||||||
#-- End shared library
|
|
||||||
|
|
||||||
#-- CLI for xgboost
|
|
||||||
if(BUILD_DEPRECATED_CLI)
|
|
||||||
add_executable(runxgboost ${xgboost_SOURCE_DIR}/src/cli_main.cc)
|
|
||||||
target_link_libraries(runxgboost PRIVATE objxgboost)
|
|
||||||
target_include_directories(runxgboost
|
|
||||||
PRIVATE
|
|
||||||
${xgboost_SOURCE_DIR}/include
|
|
||||||
${xgboost_SOURCE_DIR}/dmlc-core/include
|
|
||||||
)
|
|
||||||
set_target_properties(runxgboost PROPERTIES OUTPUT_NAME xgboost)
|
|
||||||
xgboost_target_properties(runxgboost)
|
|
||||||
xgboost_target_link_libraries(runxgboost)
|
|
||||||
xgboost_target_defs(runxgboost)
|
|
||||||
|
|
||||||
if(KEEP_BUILD_ARTIFACTS_IN_BINARY_DIR)
|
|
||||||
set_output_directory(runxgboost ${xgboost_BINARY_DIR})
|
|
||||||
else()
|
|
||||||
set_output_directory(runxgboost ${xgboost_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
#-- End CLI for xgboost
|
|
||||||
|
|
||||||
# Common setup for all targets
|
|
||||||
foreach(target xgboost objxgboost dmlc)
|
|
||||||
xgboost_target_properties(${target})
|
|
||||||
xgboost_target_link_libraries(${target})
|
|
||||||
xgboost_target_defs(${target})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(JVM_BINDINGS)
|
|
||||||
xgboost_target_properties(xgboost4j)
|
|
||||||
xgboost_target_link_libraries(xgboost4j)
|
|
||||||
xgboost_target_defs(xgboost4j)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_OPENMP AND APPLE)
|
|
||||||
patch_openmp_path_macos(xgboost libxgboost)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(KEEP_BUILD_ARTIFACTS_IN_BINARY_DIR)
|
|
||||||
set_output_directory(xgboost ${xgboost_BINARY_DIR}/lib)
|
|
||||||
else()
|
|
||||||
set_output_directory(xgboost ${xgboost_SOURCE_DIR}/lib)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
|
|
||||||
if(BUILD_DEPRECATED_CLI)
|
|
||||||
add_dependencies(xgboost runxgboost)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-- Installing XGBoost
|
|
||||||
if(R_LIB)
|
|
||||||
include(cmake/RPackageInstallTargetSetup.cmake)
|
|
||||||
set_target_properties(xgboost PROPERTIES PREFIX "")
|
|
||||||
if(APPLE)
|
|
||||||
set_target_properties(xgboost PROPERTIES SUFFIX ".so")
|
|
||||||
endif()
|
|
||||||
setup_rpackage_install_target(xgboost "${CMAKE_CURRENT_BINARY_DIR}/R-package-install")
|
|
||||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/dummy_inst")
|
|
||||||
endif()
|
|
||||||
if(MINGW)
|
|
||||||
set_target_properties(xgboost PROPERTIES PREFIX "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_C_DOC)
|
|
||||||
include(cmake/Doc.cmake)
|
|
||||||
run_doxygen()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CPack)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
# Install all headers. Please note that currently the C++ headers does not form an "API".
|
|
||||||
install(DIRECTORY ${xgboost_SOURCE_DIR}/include/xgboost
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
||||||
|
|
||||||
# Install libraries. If `xgboost` is a static lib, specify `objxgboost` also, to avoid the
|
|
||||||
# following error:
|
|
||||||
#
|
|
||||||
# > install(EXPORT ...) includes target "xgboost" which requires target "objxgboost" that is not
|
|
||||||
# > in any export set.
|
|
||||||
#
|
|
||||||
# https://github.com/dmlc/xgboost/issues/6085
|
|
||||||
if(BUILD_STATIC_LIB)
|
|
||||||
if(BUILD_DEPRECATED_CLI)
|
|
||||||
set(INSTALL_TARGETS xgboost runxgboost objxgboost dmlc)
|
|
||||||
else()
|
|
||||||
set(INSTALL_TARGETS xgboost objxgboost dmlc)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
if(BUILD_DEPRECATED_CLI)
|
|
||||||
set(INSTALL_TARGETS xgboost runxgboost)
|
|
||||||
else()
|
|
||||||
set(INSTALL_TARGETS xgboost)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(TARGETS ${INSTALL_TARGETS}
|
|
||||||
EXPORT XGBoostTargets
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
INCLUDES DESTINATION ${LIBLEGACY_INCLUDE_DIRS})
|
|
||||||
install(EXPORT XGBoostTargets
|
|
||||||
FILE XGBoostTargets.cmake
|
|
||||||
NAMESPACE xgboost::
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
|
||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
configure_package_config_file(
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/cmake/xgboost-config.cmake.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/cmake/xgboost-config.cmake
|
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
|
||||||
write_basic_package_version_file(
|
|
||||||
${CMAKE_BINARY_DIR}/cmake/xgboost-config-version.cmake
|
|
||||||
VERSION ${XGBOOST_VERSION}
|
|
||||||
COMPATIBILITY AnyNewerVersion)
|
|
||||||
install(
|
|
||||||
FILES
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/cmake/xgboost-config.cmake
|
|
||||||
${CMAKE_BINARY_DIR}/cmake/xgboost-config-version.cmake
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/xgboost)
|
|
||||||
|
|
||||||
#-- Test
|
|
||||||
if(GOOGLE_TEST)
|
|
||||||
enable_testing()
|
|
||||||
# Unittests.
|
|
||||||
add_executable(testxgboost)
|
|
||||||
target_link_libraries(testxgboost PRIVATE objxgboost)
|
|
||||||
xgboost_target_properties(testxgboost)
|
|
||||||
xgboost_target_link_libraries(testxgboost)
|
|
||||||
xgboost_target_defs(testxgboost)
|
|
||||||
|
|
||||||
add_subdirectory(${xgboost_SOURCE_DIR}/tests/cpp)
|
|
||||||
|
|
||||||
add_test(
|
|
||||||
NAME TestXGBoostLib
|
|
||||||
COMMAND testxgboost
|
|
||||||
WORKING_DIRECTORY ${xgboost_BINARY_DIR})
|
|
||||||
# CLI tests
|
|
||||||
configure_file(
|
|
||||||
${xgboost_SOURCE_DIR}/tests/cli/machine.conf.in
|
|
||||||
${xgboost_BINARY_DIR}/tests/cli/machine.conf
|
|
||||||
@ONLY)
|
|
||||||
if(BUILD_DEPRECATED_CLI)
|
|
||||||
add_test(
|
|
||||||
NAME TestXGBoostCLI
|
|
||||||
COMMAND runxgboost ${xgboost_BINARY_DIR}/tests/cli/machine.conf
|
|
||||||
WORKING_DIRECTORY ${xgboost_BINARY_DIR})
|
|
||||||
set_tests_properties(TestXGBoostCLI
|
|
||||||
PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION ".*test-rmse:0.087.*")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add xgboost.pc
|
|
||||||
if(ADD_PKGCONFIG)
|
|
||||||
configure_file(${xgboost_SOURCE_DIR}/cmake/xgboost.pc.in ${xgboost_BINARY_DIR}/xgboost.pc @ONLY)
|
|
||||||
|
|
||||||
install(
|
|
||||||
FILES ${xgboost_BINARY_DIR}/xgboost.pc
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
|
||||||
endif()
|
|
||||||
106
CONTRIBUTORS.md
106
CONTRIBUTORS.md
@@ -1,106 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
||||||
Project Management Committee(PMC)
|
|
||||||
----------
|
|
||||||
The Project Management Committee(PMC) consists group of active committers that moderate the discussion, manage the project release, and proposes new committer/PMC members.
|
|
||||||
|
|
||||||
* [Tianqi Chen](https://github.com/tqchen), University of Washington
|
|
||||||
- Tianqi is a Ph.D. student working on large-scale machine learning. He is the creator of the project.
|
|
||||||
* [Michael Benesty](https://github.com/pommedeterresautee)
|
|
||||||
- Michael is a lawyer and data scientist in France. He is the creator of XGBoost interactive analysis module in R.
|
|
||||||
* [Yuan Tang](https://github.com/terrytangyuan), Red Hat
|
|
||||||
- Yuan is a principal software engineer at Red Hat. He contributed mostly in R and Python packages.
|
|
||||||
* [Nan Zhu](https://github.com/CodingCat), Uber
|
|
||||||
- Nan is a software engineer in Uber. He contributed mostly in JVM packages.
|
|
||||||
* [Jiaming Yuan](https://github.com/trivialfis)
|
|
||||||
- Jiaming contributed to the GPU algorithms. He has also introduced new abstractions to improve the quality of the C++ codebase.
|
|
||||||
* [Hyunsu Cho](http://hyunsu-cho.io/), NVIDIA
|
|
||||||
- Hyunsu is the maintainer of the XGBoost Python package. He also manages the Jenkins continuous integration system (https://xgboost-ci.net/). He is the initial author of the CPU 'hist' updater.
|
|
||||||
* [Rory Mitchell](https://github.com/RAMitchell), University of Waikato
|
|
||||||
- Rory is a Ph.D. student at University of Waikato. He is the original creator of the GPU training algorithms. He improved the CMake build system and continuous integration.
|
|
||||||
* [Hongliang Liu](https://github.com/phunterlau)
|
|
||||||
|
|
||||||
|
|
||||||
Committers
|
|
||||||
----------
|
|
||||||
Committers are people who have made substantial contribution to the project and granted write access to the project.
|
|
||||||
|
|
||||||
* [Tong He](https://github.com/hetong007), Amazon AI
|
|
||||||
- Tong is an applied scientist in Amazon AI. He is the maintainer of XGBoost R package.
|
|
||||||
* [Vadim Khotilovich](https://github.com/khotilov)
|
|
||||||
- Vadim contributes many improvements in R and core packages.
|
|
||||||
* [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).
|
|
||||||
* [Sergei Lebedev](https://github.com/superbobry), Criteo
|
|
||||||
- Sergei is a software engineer in Criteo. He contributed mostly in JVM packages.
|
|
||||||
* [Scott Lundberg](http://scottlundberg.com/), University of Washington
|
|
||||||
- Scott is a Ph.D. student at University of Washington. He is the creator of SHAP, a unified approach to explain the output of machine learning models such as decision tree ensembles. He also helps maintain the XGBoost Julia package.
|
|
||||||
* [Egor Smirnov](https://github.com/SmirnovEgorRu), Intel
|
|
||||||
- Egor has led a major effort to improve the performance of XGBoost on multi-core CPUs.
|
|
||||||
|
|
||||||
|
|
||||||
Become a Committer
|
|
||||||
------------------
|
|
||||||
XGBoost is a open source project and we are actively looking for new committers 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 committer members, with support from more than two of current committers.
|
|
||||||
|
|
||||||
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)
|
|
||||||
* [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 scikit-learn module.
|
|
||||||
* [Yen-Ying Lee](https://github.com/white1033)
|
|
||||||
* [Masaaki Horikoshi](https://github.com/sinhrks)
|
|
||||||
- Masaaki is the initial creator of XGBoost Python plotting module.
|
|
||||||
* [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)
|
|
||||||
* [Baltazar Bieniek](https://github.com/bbieniek)
|
|
||||||
* [Adam Pocock](https://github.com/Craigacp)
|
|
||||||
* [Gideon Whitehead](https://github.com/gaw89)
|
|
||||||
* [Yi-Lin Juang](https://github.com/frankyjuang)
|
|
||||||
* [Andrew Hannigan](https://github.com/andrewhannigan)
|
|
||||||
* [Andy Adinets](https://github.com/canonizer)
|
|
||||||
* [Henry Gouk](https://github.com/henrygouk)
|
|
||||||
* [Pierre de Sahb](https://github.com/pdesahb)
|
|
||||||
* [liuliang01](https://github.com/liuliang01)
|
|
||||||
- liuliang01 added support for the qid column for LIBSVM input format. This makes ranking task easier in distributed setting.
|
|
||||||
* [Andrew Thia](https://github.com/BlueTea88)
|
|
||||||
- Andrew Thia implemented feature interaction constraints
|
|
||||||
* [Wei Tian](https://github.com/weitian)
|
|
||||||
* [Chen Qin](https://github.com/chenqin)
|
|
||||||
* [Sam Wilkinson](https://samwilkinson.io)
|
|
||||||
* [Matthew Jones](https://github.com/mt-jones)
|
|
||||||
* [Jiaxiang Li](https://github.com/JiaxiangBU)
|
|
||||||
* [Bryan Woods](https://github.com/bryan-woods)
|
|
||||||
- Bryan added support for cross-validation for the ranking objective
|
|
||||||
* [Haoda Fu](https://github.com/fuhaoda)
|
|
||||||
* [Evan Kepner](https://github.com/EvanKepner)
|
|
||||||
- Evan Kepner added support for os.PathLike file paths in Python
|
|
||||||
210
LICENSE
210
LICENSE
@@ -1,201 +1,13 @@
|
|||||||
Apache License
|
Copyright (c) 2014 by Tianqi Chen and Contributors
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
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
|
||||||
|
|
||||||
1. Definitions.
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright (c) 2019 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
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|||||||
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export CC = gcc
|
||||||
|
export CXX = g++
|
||||||
|
export CFLAGS = -Wall -O3 -msse2 -Wno-unknown-pragmas -fopenmp
|
||||||
|
|
||||||
|
# specify tensor path
|
||||||
|
BIN = xgboost
|
||||||
|
OBJ =
|
||||||
|
.PHONY: clean all
|
||||||
|
|
||||||
|
all: $(BIN) $(OBJ)
|
||||||
|
export LDFLAGS= -pthread -lm
|
||||||
|
|
||||||
|
xgboost: regrank/xgboost_regrank_main.cpp regrank/*.h regrank/*.hpp booster/*.h booster/*/*.hpp booster/*.hpp
|
||||||
|
|
||||||
|
|
||||||
|
$(BIN) :
|
||||||
|
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(filter %.cpp %.o %.c, $^)
|
||||||
|
|
||||||
|
$(OBJ) :
|
||||||
|
$(CXX) -c $(CFLAGS) -o $@ $(firstword $(filter %.cpp %.c, $^) )
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp -f -r $(BIN) $(INSTALL_PATH)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJ) $(BIN) *~
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
\.o$
|
|
||||||
\.so$
|
|
||||||
\.dll$
|
|
||||||
^.*\.Rproj$
|
|
||||||
^\.Rproj\.user$
|
|
||||||
README.md
|
|
||||||
^doc$
|
|
||||||
^Meta$
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
find_package(LibR REQUIRED)
|
|
||||||
message(STATUS "LIBR_CORE_LIBRARY " ${LIBR_CORE_LIBRARY})
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB_RECURSE R_SOURCES
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/*.cc
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/*.c
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use object library to expose symbols
|
|
||||||
add_library(xgboost-r OBJECT ${R_SOURCES})
|
|
||||||
|
|
||||||
if(ENABLE_ALL_WARNINGS)
|
|
||||||
target_compile_options(xgboost-r PRIVATE -Wall -Wextra)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
# https://github.com/microsoft/LightGBM/pull/6061
|
|
||||||
# MSVC doesn't work with anonymous types in structs. (R complex)
|
|
||||||
#
|
|
||||||
# syntax error: missing ';' before identifier 'private_data_c'
|
|
||||||
#
|
|
||||||
target_compile_definitions(xgboost-r PRIVATE -DR_LEGACY_RCOMPLEX)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_definitions(
|
|
||||||
xgboost-r PUBLIC
|
|
||||||
-DXGBOOST_STRICT_R_MODE=1
|
|
||||||
-DDMLC_LOG_BEFORE_THROW=0
|
|
||||||
-DDMLC_DISABLE_STDIN=1
|
|
||||||
-DDMLC_LOG_CUSTOMIZE=1
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(
|
|
||||||
xgboost-r PRIVATE
|
|
||||||
${LIBR_INCLUDE_DIRS}
|
|
||||||
${PROJECT_SOURCE_DIR}/include
|
|
||||||
${PROJECT_SOURCE_DIR}/dmlc-core/include
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(xgboost-r PUBLIC ${LIBR_CORE_LIBRARY})
|
|
||||||
|
|
||||||
if(USE_OPENMP)
|
|
||||||
find_package(OpenMP REQUIRED)
|
|
||||||
target_link_libraries(xgboost-r PUBLIC OpenMP::OpenMP_CXX OpenMP::OpenMP_C)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(
|
|
||||||
xgboost-r PROPERTIES
|
|
||||||
CXX_STANDARD 17
|
|
||||||
CXX_STANDARD_REQUIRED ON
|
|
||||||
POSITION_INDEPENDENT_CODE ON
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get compilation and link flags of xgboost-r and propagate to objxgboost
|
|
||||||
target_link_libraries(objxgboost PUBLIC xgboost-r)
|
|
||||||
|
|
||||||
# Add all objects of xgboost-r to objxgboost
|
|
||||||
target_sources(objxgboost INTERFACE $<TARGET_OBJECTS:xgboost-r>)
|
|
||||||
|
|
||||||
set(LIBR_HOME "${LIBR_HOME}" PARENT_SCOPE)
|
|
||||||
set(LIBR_EXECUTABLE "${LIBR_EXECUTABLE}" PARENT_SCOPE)
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
Package: xgboost
|
|
||||||
Type: Package
|
|
||||||
Title: Extreme Gradient Boosting
|
|
||||||
Version: 2.2.0.0
|
|
||||||
Date: 2024-06-03
|
|
||||||
Authors@R: c(
|
|
||||||
person("Tianqi", "Chen", role = c("aut"),
|
|
||||||
email = "tianqi.tchen@gmail.com"),
|
|
||||||
person("Tong", "He", role = c("aut"),
|
|
||||||
email = "hetong007@gmail.com"),
|
|
||||||
person("Michael", "Benesty", role = c("aut"),
|
|
||||||
email = "michael@benesty.fr"),
|
|
||||||
person("Vadim", "Khotilovich", role = c("aut"),
|
|
||||||
email = "khotilovich@gmail.com"),
|
|
||||||
person("Yuan", "Tang", role = c("aut"),
|
|
||||||
email = "terrytangyuan@gmail.com",
|
|
||||||
comment = c(ORCID = "0000-0001-5243-233X")),
|
|
||||||
person("Hyunsu", "Cho", role = c("aut"),
|
|
||||||
email = "chohyu01@cs.washington.edu"),
|
|
||||||
person("Kailong", "Chen", role = c("aut")),
|
|
||||||
person("Rory", "Mitchell", role = c("aut")),
|
|
||||||
person("Ignacio", "Cano", role = c("aut")),
|
|
||||||
person("Tianyi", "Zhou", role = c("aut")),
|
|
||||||
person("Mu", "Li", role = c("aut")),
|
|
||||||
person("Junyuan", "Xie", role = c("aut")),
|
|
||||||
person("Min", "Lin", role = c("aut")),
|
|
||||||
person("Yifeng", "Geng", role = c("aut")),
|
|
||||||
person("Yutian", "Li", role = c("aut")),
|
|
||||||
person("Jiaming", "Yuan", role = c("aut", "cre"),
|
|
||||||
email = "jm.yuan@outlook.com"),
|
|
||||||
person("XGBoost contributors", role = c("cph"),
|
|
||||||
comment = "base XGBoost implementation")
|
|
||||||
)
|
|
||||||
Maintainer: Jiaming Yuan <jm.yuan@outlook.com>
|
|
||||||
Description: Extreme Gradient Boosting, which is an efficient implementation
|
|
||||||
of the gradient boosting framework from Chen & Guestrin (2016) <doi:10.1145/2939672.2939785>.
|
|
||||||
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
|
|
||||||
BugReports: https://github.com/dmlc/xgboost/issues
|
|
||||||
NeedsCompilation: yes
|
|
||||||
VignetteBuilder: knitr
|
|
||||||
Suggests:
|
|
||||||
knitr,
|
|
||||||
rmarkdown,
|
|
||||||
ggplot2 (>= 1.0.1),
|
|
||||||
DiagrammeR (>= 0.9.0),
|
|
||||||
Ckmeans.1d.dp (>= 3.3.1),
|
|
||||||
vcd (>= 1.3),
|
|
||||||
testthat,
|
|
||||||
igraph (>= 1.0.1),
|
|
||||||
float,
|
|
||||||
titanic,
|
|
||||||
RhpcBLASctl,
|
|
||||||
survival
|
|
||||||
Depends:
|
|
||||||
R (>= 4.3.0)
|
|
||||||
Imports:
|
|
||||||
Matrix (>= 1.1-0),
|
|
||||||
methods,
|
|
||||||
data.table (>= 1.9.6),
|
|
||||||
jsonlite (>= 1.0)
|
|
||||||
Roxygen: list(markdown = TRUE)
|
|
||||||
RoxygenNote: 7.3.2
|
|
||||||
Encoding: UTF-8
|
|
||||||
SystemRequirements: GNU make, C++17
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
Copyright (c) 2014-2023, Tianqi Chen and XBGoost 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
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# Generated by roxygen2: do not edit by hand
|
|
||||||
|
|
||||||
S3method("[",xgb.Booster)
|
|
||||||
S3method("[",xgb.DMatrix)
|
|
||||||
S3method("dimnames<-",xgb.DMatrix)
|
|
||||||
S3method(coef,xgb.Booster)
|
|
||||||
S3method(dim,xgb.DMatrix)
|
|
||||||
S3method(dimnames,xgb.DMatrix)
|
|
||||||
S3method(getinfo,xgb.Booster)
|
|
||||||
S3method(getinfo,xgb.DMatrix)
|
|
||||||
S3method(length,xgb.Booster)
|
|
||||||
S3method(predict,xgb.Booster)
|
|
||||||
S3method(print,xgb.Booster)
|
|
||||||
S3method(print,xgb.DMatrix)
|
|
||||||
S3method(print,xgb.cv.synchronous)
|
|
||||||
S3method(print,xgboost)
|
|
||||||
S3method(setinfo,xgb.Booster)
|
|
||||||
S3method(setinfo,xgb.DMatrix)
|
|
||||||
S3method(variable.names,xgb.Booster)
|
|
||||||
export("xgb.attr<-")
|
|
||||||
export("xgb.attributes<-")
|
|
||||||
export("xgb.config<-")
|
|
||||||
export("xgb.parameters<-")
|
|
||||||
export(getinfo)
|
|
||||||
export(setinfo)
|
|
||||||
export(xgb.Callback)
|
|
||||||
export(xgb.DMatrix)
|
|
||||||
export(xgb.DMatrix.hasinfo)
|
|
||||||
export(xgb.DMatrix.save)
|
|
||||||
export(xgb.DataBatch)
|
|
||||||
export(xgb.DataIter)
|
|
||||||
export(xgb.ExtMemDMatrix)
|
|
||||||
export(xgb.QuantileDMatrix)
|
|
||||||
export(xgb.QuantileDMatrix.from_iterator)
|
|
||||||
export(xgb.attr)
|
|
||||||
export(xgb.attributes)
|
|
||||||
export(xgb.cb.cv.predict)
|
|
||||||
export(xgb.cb.early.stop)
|
|
||||||
export(xgb.cb.evaluation.log)
|
|
||||||
export(xgb.cb.gblinear.history)
|
|
||||||
export(xgb.cb.print.evaluation)
|
|
||||||
export(xgb.cb.reset.parameters)
|
|
||||||
export(xgb.cb.save.model)
|
|
||||||
export(xgb.config)
|
|
||||||
export(xgb.copy.Booster)
|
|
||||||
export(xgb.create.features)
|
|
||||||
export(xgb.cv)
|
|
||||||
export(xgb.dump)
|
|
||||||
export(xgb.gblinear.history)
|
|
||||||
export(xgb.get.DMatrix.data)
|
|
||||||
export(xgb.get.DMatrix.num.non.missing)
|
|
||||||
export(xgb.get.DMatrix.qcut)
|
|
||||||
export(xgb.get.config)
|
|
||||||
export(xgb.get.num.boosted.rounds)
|
|
||||||
export(xgb.ggplot.deepness)
|
|
||||||
export(xgb.ggplot.importance)
|
|
||||||
export(xgb.ggplot.shap.summary)
|
|
||||||
export(xgb.importance)
|
|
||||||
export(xgb.is.same.Booster)
|
|
||||||
export(xgb.load)
|
|
||||||
export(xgb.load.raw)
|
|
||||||
export(xgb.model.dt.tree)
|
|
||||||
export(xgb.plot.deepness)
|
|
||||||
export(xgb.plot.importance)
|
|
||||||
export(xgb.plot.multi.trees)
|
|
||||||
export(xgb.plot.shap)
|
|
||||||
export(xgb.plot.shap.summary)
|
|
||||||
export(xgb.plot.tree)
|
|
||||||
export(xgb.save)
|
|
||||||
export(xgb.save.raw)
|
|
||||||
export(xgb.set.config)
|
|
||||||
export(xgb.slice.Booster)
|
|
||||||
export(xgb.slice.DMatrix)
|
|
||||||
export(xgb.train)
|
|
||||||
export(xgboost)
|
|
||||||
import(methods)
|
|
||||||
importClassesFrom(Matrix,CsparseMatrix)
|
|
||||||
importClassesFrom(Matrix,dgCMatrix)
|
|
||||||
importClassesFrom(Matrix,dgRMatrix)
|
|
||||||
importFrom(Matrix,sparse.model.matrix)
|
|
||||||
importFrom(data.table,":=")
|
|
||||||
importFrom(data.table,as.data.table)
|
|
||||||
importFrom(data.table,data.table)
|
|
||||||
importFrom(data.table,is.data.table)
|
|
||||||
importFrom(data.table,rbindlist)
|
|
||||||
importFrom(data.table,setkey)
|
|
||||||
importFrom(data.table,setkeyv)
|
|
||||||
importFrom(data.table,setnames)
|
|
||||||
importFrom(grDevices,rgb)
|
|
||||||
importFrom(graphics,barplot)
|
|
||||||
importFrom(graphics,grid)
|
|
||||||
importFrom(graphics,lines)
|
|
||||||
importFrom(graphics,par)
|
|
||||||
importFrom(graphics,points)
|
|
||||||
importFrom(graphics,title)
|
|
||||||
importFrom(jsonlite,fromJSON)
|
|
||||||
importFrom(jsonlite,toJSON)
|
|
||||||
importFrom(methods,new)
|
|
||||||
importFrom(stats,coef)
|
|
||||||
importFrom(stats,median)
|
|
||||||
importFrom(stats,predict)
|
|
||||||
importFrom(stats,sd)
|
|
||||||
importFrom(stats,variable.names)
|
|
||||||
importFrom(utils,head)
|
|
||||||
importFrom(utils,object.size)
|
|
||||||
importFrom(utils,str)
|
|
||||||
importFrom(utils,tail)
|
|
||||||
useDynLib(xgboost, .registration = TRUE)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,579 +0,0 @@
|
|||||||
#
|
|
||||||
# This file is for the low level reusable utility functions
|
|
||||||
# that are not supposed to be visible to a user.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# 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("typeof(x) == ", typeof(x), " is not supported by NVL")
|
|
||||||
}
|
|
||||||
|
|
||||||
# List of classification and ranking objectives
|
|
||||||
.CLASSIFICATION_OBJECTIVES <- function() {
|
|
||||||
return(c('binary:logistic', 'binary:logitraw', 'binary:hinge', 'multi:softmax',
|
|
||||||
'multi:softprob', 'rank:pairwise', 'rank:ndcg', 'rank:map'))
|
|
||||||
}
|
|
||||||
|
|
||||||
.RANKING_OBJECTIVES <- function() {
|
|
||||||
return(c('rank:pairwise', 'rank:ndcg', 'rank:map'))
|
|
||||||
}
|
|
||||||
|
|
||||||
.OBJECTIVES_NON_DEFAULT_MODE <- function() {
|
|
||||||
return(c("reg:logistic", "binary:logitraw", "multi:softmax"))
|
|
||||||
}
|
|
||||||
|
|
||||||
.BINARY_CLASSIF_OBJECTIVES <- function() {
|
|
||||||
return(c("binary:logistic", "binary:hinge"))
|
|
||||||
}
|
|
||||||
|
|
||||||
.MULTICLASS_CLASSIF_OBJECTIVES <- function() {
|
|
||||||
return("multi:softprob")
|
|
||||||
}
|
|
||||||
|
|
||||||
.SURVIVAL_RIGHT_CENSORING_OBJECTIVES <- function() { # nolint
|
|
||||||
return(c("survival:cox", "survival:aft"))
|
|
||||||
}
|
|
||||||
|
|
||||||
.SURVIVAL_ALL_CENSORING_OBJECTIVES <- function() { # nolint
|
|
||||||
return("survival:aft")
|
|
||||||
}
|
|
||||||
|
|
||||||
.REGRESSION_OBJECTIVES <- function() {
|
|
||||||
return(c(
|
|
||||||
"reg:squarederror", "reg:squaredlogerror", "reg:logistic", "reg:pseudohubererror",
|
|
||||||
"reg:absoluteerror", "reg:quantileerror", "count:poisson", "reg:gamma", "reg:tweedie"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
.MULTI_TARGET_OBJECTIVES <- function() {
|
|
||||||
return(c(
|
|
||||||
"reg:squarederror", "reg:squaredlogerror", "reg:logistic", "reg:pseudohubererror",
|
|
||||||
"reg:quantileerror", "reg:gamma"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Low-level functions for boosting --------------------------------------------
|
|
||||||
#
|
|
||||||
|
|
||||||
# Merges booster params with whatever is provided in ...
|
|
||||||
# plus runs some checks
|
|
||||||
check.booster.params <- function(params, ...) {
|
|
||||||
if (!identical(class(params), "list"))
|
|
||||||
stop("params must be a list")
|
|
||||||
|
|
||||||
# in R interface, allow for '.' instead of '_' in parameter names
|
|
||||||
names(params) <- gsub(".", "_", names(params), fixed = TRUE)
|
|
||||||
|
|
||||||
# merge parameters from the params and the dots-expansion
|
|
||||||
dot_params <- list(...)
|
|
||||||
names(dot_params) <- gsub(".", "_", names(dot_params), fixed = TRUE)
|
|
||||||
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 makes sense only 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 internals would choose the last value for a multiple-times parameter,
|
|
||||||
# enforce it here in R as well (b/c multi-parameters might be used further in R code,
|
|
||||||
# and R takes the 1st 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# for multiclass, expect num_class to be set
|
|
||||||
if (typeof(params[['objective']]) == "character" &&
|
|
||||||
startsWith(NVL(params[['objective']], 'x'), 'multi:') &&
|
|
||||||
as.numeric(NVL(params[['num_class']], 0)) < 2) {
|
|
||||||
stop("'num_class' > 1 parameter must be set for multiclass classification")
|
|
||||||
}
|
|
||||||
|
|
||||||
# monotone_constraints parser
|
|
||||||
|
|
||||||
if (!is.null(params[['monotone_constraints']]) &&
|
|
||||||
typeof(params[['monotone_constraints']]) != "character") {
|
|
||||||
vec2str <- paste(params[['monotone_constraints']], collapse = ',')
|
|
||||||
vec2str <- paste0('(', vec2str, ')')
|
|
||||||
params[['monotone_constraints']] <- vec2str
|
|
||||||
}
|
|
||||||
|
|
||||||
# interaction constraints parser (convert from list of column indices to string)
|
|
||||||
if (!is.null(params[['interaction_constraints']]) &&
|
|
||||||
typeof(params[['interaction_constraints']]) != "character") {
|
|
||||||
# check input class
|
|
||||||
if (!identical(class(params[['interaction_constraints']]), 'list')) stop('interaction_constraints should be class list')
|
|
||||||
if (!all(unique(sapply(params[['interaction_constraints']], class)) %in% c('numeric', 'integer'))) {
|
|
||||||
stop('interaction_constraints should be a list of numeric/integer vectors')
|
|
||||||
}
|
|
||||||
|
|
||||||
# recast parameter as string
|
|
||||||
interaction_constraints <- sapply(params[['interaction_constraints']], function(x) paste0('[', paste(x, collapse = ','), ']'))
|
|
||||||
params[['interaction_constraints']] <- paste0('[', paste(interaction_constraints, collapse = ','), ']')
|
|
||||||
}
|
|
||||||
|
|
||||||
# for evaluation metrics, should generate multiple entries per metric
|
|
||||||
if (NROW(params[['eval_metric']]) > 1) {
|
|
||||||
eval_metrics <- as.list(params[["eval_metric"]])
|
|
||||||
names(eval_metrics) <- rep("eval_metric", length(eval_metrics))
|
|
||||||
params_without_ev_metrics <- within(params, rm("eval_metric"))
|
|
||||||
params <- c(params_without_ev_metrics, eval_metrics)
|
|
||||||
}
|
|
||||||
return(params)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# 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
|
|
||||||
env$params$objective <- NULL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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")
|
|
||||||
|
|
||||||
# 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
|
|
||||||
env$params$eval_metric <- NULL
|
|
||||||
}
|
|
||||||
|
|
||||||
# require maximize to be set when custom feval and early stopping are used together
|
|
||||||
if (!is.null(env$feval) &&
|
|
||||||
is.null(env$maximize) && (
|
|
||||||
!is.null(env$early_stopping_rounds) ||
|
|
||||||
has.callbacks(env$callbacks, "early_stop")))
|
|
||||||
stop("Please set 'maximize' to indicate whether the evaluation metric needs to be maximized or not")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Update a booster handle for an iteration with dtrain data
|
|
||||||
xgb.iter.update <- function(bst, dtrain, iter, obj) {
|
|
||||||
if (!inherits(dtrain, "xgb.DMatrix")) {
|
|
||||||
stop("dtrain must be of xgb.DMatrix class")
|
|
||||||
}
|
|
||||||
handle <- xgb.get.handle(bst)
|
|
||||||
|
|
||||||
if (is.null(obj)) {
|
|
||||||
.Call(XGBoosterUpdateOneIter_R, handle, as.integer(iter), dtrain)
|
|
||||||
} else {
|
|
||||||
pred <- predict(
|
|
||||||
bst,
|
|
||||||
dtrain,
|
|
||||||
outputmargin = TRUE,
|
|
||||||
training = TRUE
|
|
||||||
)
|
|
||||||
gpair <- obj(pred, dtrain)
|
|
||||||
n_samples <- dim(dtrain)[1]
|
|
||||||
grad <- gpair$grad
|
|
||||||
hess <- gpair$hess
|
|
||||||
|
|
||||||
if ((is.matrix(grad) && dim(grad)[1] != n_samples) ||
|
|
||||||
(is.vector(grad) && length(grad) != n_samples) ||
|
|
||||||
(is.vector(grad) != is.vector(hess))) {
|
|
||||||
warning(paste(
|
|
||||||
"Since 2.1.0, the shape of the gradient and hessian is required to be ",
|
|
||||||
"(n_samples, n_targets) or (n_samples, n_classes). Will reshape assuming ",
|
|
||||||
"column-major order.",
|
|
||||||
sep = ""
|
|
||||||
))
|
|
||||||
grad <- matrix(grad, nrow = n_samples)
|
|
||||||
hess <- matrix(hess, nrow = n_samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
.Call(
|
|
||||||
XGBoosterTrainOneIter_R, handle, dtrain, iter, grad, hess
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return(TRUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Evaluate one iteration.
|
|
||||||
# Returns a named vector of evaluation metrics
|
|
||||||
# with the names in a 'datasetname-metricname' format.
|
|
||||||
xgb.iter.eval <- function(bst, evals, iter, feval) {
|
|
||||||
handle <- xgb.get.handle(bst)
|
|
||||||
|
|
||||||
if (length(evals) == 0)
|
|
||||||
return(NULL)
|
|
||||||
|
|
||||||
evnames <- names(evals)
|
|
||||||
if (is.null(feval)) {
|
|
||||||
msg <- .Call(XGBoosterEvalOneIter_R, handle, as.integer(iter), evals, as.list(evnames))
|
|
||||||
mat <- matrix(strsplit(msg, '\\s+|:')[[1]][-1], nrow = 2)
|
|
||||||
res <- structure(as.numeric(mat[2, ]), names = mat[1, ])
|
|
||||||
} else {
|
|
||||||
res <- sapply(seq_along(evals), function(j) {
|
|
||||||
w <- evals[[j]]
|
|
||||||
## predict using all trees
|
|
||||||
preds <- predict(bst, w, outputmargin = TRUE, iterationrange = "all")
|
|
||||||
eval_res <- feval(preds, w)
|
|
||||||
out <- eval_res$value
|
|
||||||
names(out) <- paste0(evnames[j], "-", eval_res$metric)
|
|
||||||
out
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Helper functions for cross validation ---------------------------------------
|
|
||||||
#
|
|
||||||
|
|
||||||
# Possibly convert the labels into factors, depending on the objective.
|
|
||||||
# The labels are converted into factors only when the given objective refers to the classification
|
|
||||||
# or ranking tasks.
|
|
||||||
convert.labels <- function(labels, objective_name) {
|
|
||||||
if (objective_name %in% .CLASSIFICATION_OBJECTIVES()) {
|
|
||||||
return(as.factor(labels))
|
|
||||||
} else {
|
|
||||||
return(labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generates random (stratified if needed) CV folds
|
|
||||||
generate.cv.folds <- function(nfold, nrows, stratified, label, group, params) {
|
|
||||||
if (NROW(group)) {
|
|
||||||
if (stratified) {
|
|
||||||
warning(
|
|
||||||
paste0(
|
|
||||||
"Stratified splitting is not supported when using 'group' attribute.",
|
|
||||||
" Will use unstratified splitting."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return(generate.group.folds(nfold, group))
|
|
||||||
}
|
|
||||||
objective <- params$objective
|
|
||||||
if (!is.character(objective)) {
|
|
||||||
warning("Will use unstratified splitting (custom objective used)")
|
|
||||||
stratified <- FALSE
|
|
||||||
}
|
|
||||||
# cannot stratify if label is NULL
|
|
||||||
if (stratified && is.null(label)) {
|
|
||||||
warning("Will use unstratified splitting (no 'labels' available)")
|
|
||||||
stratified <- FALSE
|
|
||||||
}
|
|
||||||
|
|
||||||
# cannot do it for rank
|
|
||||||
if (is.character(objective) && strtrim(objective, 5) == 'rank:') {
|
|
||||||
stop("\n\tAutomatic generation of CV-folds is not implemented for ranking without 'group' field!\n",
|
|
||||||
"\tConsider providing pre-computed CV-folds through the 'folds=' parameter.\n")
|
|
||||||
}
|
|
||||||
# shuffle
|
|
||||||
rnd_idx <- sample.int(nrows)
|
|
||||||
if (stratified && length(label) == length(rnd_idx)) {
|
|
||||||
y <- label[rnd_idx]
|
|
||||||
# - 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 (is.character(objective)) {
|
|
||||||
y <- convert.labels(y, objective)
|
|
||||||
}
|
|
||||||
folds <- xgb.createFolds(y = y, k = nfold)
|
|
||||||
} else {
|
|
||||||
# make simple non-stratified folds
|
|
||||||
kstep <- length(rnd_idx) %/% nfold
|
|
||||||
folds <- list()
|
|
||||||
for (i in seq_len(nfold - 1)) {
|
|
||||||
folds[[i]] <- rnd_idx[seq_len(kstep)]
|
|
||||||
rnd_idx <- rnd_idx[-seq_len(kstep)]
|
|
||||||
}
|
|
||||||
folds[[nfold]] <- rnd_idx
|
|
||||||
}
|
|
||||||
return(folds)
|
|
||||||
}
|
|
||||||
|
|
||||||
generate.group.folds <- function(nfold, group) {
|
|
||||||
ngroups <- length(group) - 1
|
|
||||||
if (ngroups < nfold) {
|
|
||||||
stop("DMatrix has fewer groups than folds.")
|
|
||||||
}
|
|
||||||
seq_groups <- seq_len(ngroups)
|
|
||||||
indices <- lapply(seq_groups, function(gr) seq(group[gr] + 1, group[gr + 1]))
|
|
||||||
assignments <- base::split(seq_groups, as.integer(seq_groups %% nfold))
|
|
||||||
assignments <- unname(assignments)
|
|
||||||
|
|
||||||
out <- vector("list", nfold)
|
|
||||||
randomized_groups <- sample(ngroups)
|
|
||||||
for (idx in seq_len(nfold)) {
|
|
||||||
groups_idx_test <- randomized_groups[assignments[[idx]]]
|
|
||||||
groups_test <- indices[groups_idx_test]
|
|
||||||
idx_test <- unlist(groups_test)
|
|
||||||
attributes(idx_test)$group_test <- lengths(groups_test)
|
|
||||||
attributes(idx_test)$group_train <- lengths(indices[-groups_idx_test])
|
|
||||||
out[[idx]] <- idx_test
|
|
||||||
}
|
|
||||||
return(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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) {
|
|
||||||
if (is.numeric(y)) {
|
|
||||||
## Group the numeric data based on their magnitudes
|
|
||||||
## and sample within those groups.
|
|
||||||
|
|
||||||
## When the number of samples is low, we may have
|
|
||||||
## issues further slicing the numeric data into
|
|
||||||
## groups. The number of groups will depend on the
|
|
||||||
## ratio of the number of folds to the sample size.
|
|
||||||
## 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
|
|
||||||
y <- cut(y,
|
|
||||||
unique(stats::quantile(y, probs = seq(0, 1, length = cuts))),
|
|
||||||
include.lowest = TRUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 seq_along(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 produced here.
|
|
||||||
seqVector <- rep(seq_len(k), numInClass[i] %/% k)
|
|
||||||
## add enough random integers to get length(seqVector) == numInClass[i]
|
|
||||||
if (numInClass[i] %% k > 0) seqVector <- c(seqVector, sample.int(k, numInClass[i] %% k))
|
|
||||||
## shuffle the integers for fold assignment and assign to this classes's data
|
|
||||||
## seqVector[sample.int(length(seqVector))] is used to handle length(seqVector) == 1
|
|
||||||
foldVector[y == dimnames(numInClass)$y[i]] <- seqVector[sample.int(length(seqVector))]
|
|
||||||
}
|
|
||||||
} 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 `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
|
|
||||||
|
|
||||||
#' Model Serialization and Compatibility
|
|
||||||
#'
|
|
||||||
#' @description
|
|
||||||
#' When it comes to serializing XGBoost models, it's possible to use R serializers such as
|
|
||||||
#' [save()] or [saveRDS()] to serialize an XGBoost R model, but XGBoost also provides
|
|
||||||
#' its own serializers with better compatibility guarantees, which allow loading
|
|
||||||
#' said models in other language bindings of XGBoost.
|
|
||||||
#'
|
|
||||||
#' Note that an `xgb.Booster` object (**as produced by [xgb.train()]**, see rest of the doc
|
|
||||||
#' for objects produced by [xgboost()]), outside of its core components, might also keep:
|
|
||||||
#' - Additional model configuration (accessible through [xgb.config()]), which includes
|
|
||||||
#' model fitting parameters like `max_depth` and runtime parameters like `nthread`.
|
|
||||||
#' These are not necessarily useful for prediction/importance/plotting.
|
|
||||||
#' - Additional R specific attributes - e.g. results of callbacks, such as evaluation logs,
|
|
||||||
#' which are kept as a `data.table` object, accessible through
|
|
||||||
#' `attributes(model)$evaluation_log` if present.
|
|
||||||
#'
|
|
||||||
#' The first one (configurations) does not have the same compatibility guarantees as
|
|
||||||
#' the model itself, including attributes that are set and accessed through
|
|
||||||
#' [xgb.attributes()] - that is, such configuration might be lost after loading the
|
|
||||||
#' booster in a different XGBoost version, regardless of the serializer that was used.
|
|
||||||
#' These are saved when using [saveRDS()], but will be discarded if loaded into an
|
|
||||||
#' incompatible XGBoost version. They are not saved when using XGBoost's
|
|
||||||
#' serializers from its public interface including [xgb.save()] and [xgb.save.raw()].
|
|
||||||
#'
|
|
||||||
#' The second ones (R attributes) are not part of the standard XGBoost model structure,
|
|
||||||
#' and thus are not saved when using XGBoost's own serializers. These attributes are
|
|
||||||
#' only used for informational purposes, such as keeping track of evaluation metrics as
|
|
||||||
#' the model was fit, or saving the R call that produced the model, but are otherwise
|
|
||||||
#' not used for prediction / importance / plotting / etc.
|
|
||||||
#' These R attributes are only preserved when using R's serializers.
|
|
||||||
#'
|
|
||||||
#' In addition to the regular `xgb.Booster` objects producted by [xgb.train()], the
|
|
||||||
#' function [xgboost()] produces a different subclass `xgboost`, which keeps other
|
|
||||||
#' additional metadata as R attributes such as class names in classification problems,
|
|
||||||
#' and which has a dedicated `predict` method that uses different defaults. XGBoost's
|
|
||||||
#' own serializers can work with this `xgboost` class, but as they do not keep R
|
|
||||||
#' attributes, the resulting object, when deserialized, is downcasted to the regular
|
|
||||||
#' `xgb.Booster` class (i.e. it loses the metadata, and the resulting object will use
|
|
||||||
#' `predict.xgb.Booster` instead of `predict.xgboost`) - for these `xgboost` objects,
|
|
||||||
#' `saveRDS` might thus be a better option if the extra functionalities are needed.
|
|
||||||
#'
|
|
||||||
#' Note that XGBoost models in R starting from version `2.1.0` and onwards, and
|
|
||||||
#' XGBoost models before version `2.1.0`; have a very different R object structure and
|
|
||||||
#' are incompatible with each other. Hence, models that were saved with R serializers
|
|
||||||
#' like [saveRDS()] or [save()] before version `2.1.0` will not work with latter
|
|
||||||
#' `xgboost` versions and vice versa. Be aware that the structure of R model objects
|
|
||||||
#' could in theory change again in the future, so XGBoost's serializers
|
|
||||||
#' should be preferred for long-term storage.
|
|
||||||
#'
|
|
||||||
#' Furthermore, note that using the package `qs` for serialization will require
|
|
||||||
#' version 0.26 or higher of said package, and will have the same compatibility
|
|
||||||
#' restrictions as R serializers.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' Use [xgb.save()] to save the XGBoost model as a stand-alone file. You may opt into
|
|
||||||
#' the JSON format by specifying the JSON extension. To read the model back, use
|
|
||||||
#' [xgb.load()].
|
|
||||||
#'
|
|
||||||
#' Use [xgb.save.raw()] to save the XGBoost model as a sequence (vector) of raw bytes
|
|
||||||
#' in a future-proof manner. Future releases of XGBoost will be able to read the raw bytes and
|
|
||||||
#' re-construct the corresponding model. To read the model back, use [xgb.load.raw()].
|
|
||||||
#' The [xgb.save.raw()] function is useful if you would like to persist the XGBoost model
|
|
||||||
#' as part of another R object.
|
|
||||||
#'
|
|
||||||
#' Use [saveRDS()] if you require the R-specific attributes that a booster might have, such
|
|
||||||
#' as evaluation logs or the model class `xgboost` instead of `xgb.Booster`, but note that
|
|
||||||
#' future compatibility of such objects is outside XGBoost's control as it relies on R's
|
|
||||||
#' serialization format (see e.g. the details section in [serialize] and [save()] from base R).
|
|
||||||
#'
|
|
||||||
#' For more details and explanation about model persistence and archival, consult the page
|
|
||||||
#' \url{https://xgboost.readthedocs.io/en/latest/tutorials/saving_model.html}.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = 2,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # Save as a stand-alone file; load it with xgb.load()
|
|
||||||
#' fname <- file.path(tempdir(), "xgb_model.ubj")
|
|
||||||
#' xgb.save(bst, fname)
|
|
||||||
#' bst2 <- xgb.load(fname)
|
|
||||||
#'
|
|
||||||
#' # Save as a stand-alone file (JSON); load it with xgb.load()
|
|
||||||
#' fname <- file.path(tempdir(), "xgb_model.json")
|
|
||||||
#' xgb.save(bst, fname)
|
|
||||||
#' bst2 <- xgb.load(fname)
|
|
||||||
#'
|
|
||||||
#' # Save as a raw byte vector; load it with xgb.load.raw()
|
|
||||||
#' xgb_bytes <- xgb.save.raw(bst)
|
|
||||||
#' bst2 <- xgb.load.raw(xgb_bytes)
|
|
||||||
#'
|
|
||||||
#' # Persist XGBoost model as part of another R object
|
|
||||||
#' obj <- list(xgb_model_bytes = xgb.save.raw(bst), description = "My first XGBoost model")
|
|
||||||
#' # Persist the R object. Here, saveRDS() is okay, since it doesn't persist
|
|
||||||
#' # xgb.Booster directly. What's being persisted is the future-proof byte representation
|
|
||||||
#' # as given by xgb.save.raw().
|
|
||||||
#' fname <- file.path(tempdir(), "my_object.Rds")
|
|
||||||
#' saveRDS(obj, fname)
|
|
||||||
#' # Read back the R object
|
|
||||||
#' obj2 <- readRDS(fname)
|
|
||||||
#' # Re-construct xgb.Booster object from the bytes
|
|
||||||
#' bst2 <- xgb.load.raw(obj2$xgb_model_bytes)
|
|
||||||
#'
|
|
||||||
#' @name a-compatibility-note-for-saveRDS-save
|
|
||||||
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',
|
|
||||||
'n_first_tree', 'trees',
|
|
||||||
'dummy', 'DUMMY',
|
|
||||||
'watchlist', 'evals'
|
|
||||||
), 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
|||||||
#' Save xgb.DMatrix object to binary file
|
|
||||||
#'
|
|
||||||
#' Save xgb.DMatrix object to binary file
|
|
||||||
#'
|
|
||||||
#' @param dmatrix the `xgb.DMatrix` object
|
|
||||||
#' @param fname the name of the file to write.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' \dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
#' fname <- file.path(tempdir(), "xgb.DMatrix.data")
|
|
||||||
#' xgb.DMatrix.save(dtrain, fname)
|
|
||||||
#' dtrain <- xgb.DMatrix(fname)
|
|
||||||
#' @export
|
|
||||||
xgb.DMatrix.save <- function(dmatrix, fname) {
|
|
||||||
if (typeof(fname) != "character")
|
|
||||||
stop("fname must be character")
|
|
||||||
if (!inherits(dmatrix, "xgb.DMatrix"))
|
|
||||||
stop("dmatrix must be xgb.DMatrix")
|
|
||||||
|
|
||||||
fname <- path.expand(fname)
|
|
||||||
.Call(XGDMatrixSaveBinary_R, dmatrix, fname[1], 0L)
|
|
||||||
return(TRUE)
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#' Set and get global configuration
|
|
||||||
#'
|
|
||||||
#' Global configuration consists of a collection of parameters that can be applied in the global
|
|
||||||
#' scope. See \url{https://xgboost.readthedocs.io/en/stable/parameter.html} for the full list of
|
|
||||||
#' parameters supported in the global configuration. Use `xgb.set.config()` to update the
|
|
||||||
#' values of one or more global-scope parameters. Use `xgb.get.config()` to fetch the current
|
|
||||||
#' values of all global-scope parameters (listed in
|
|
||||||
#' \url{https://xgboost.readthedocs.io/en/stable/parameter.html}).
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' Note that serialization-related functions might use a globally-configured number of threads,
|
|
||||||
#' which is managed by the system's OpenMP (OMP) configuration instead. Typically, XGBoost methods
|
|
||||||
#' accept an `nthreads` parameter, but some methods like [readRDS()] might get executed before such
|
|
||||||
#' parameter can be supplied.
|
|
||||||
#'
|
|
||||||
#' The number of OMP threads can in turn be configured for example through an environment variable
|
|
||||||
#' `OMP_NUM_THREADS` (needs to be set before R is started), or through `RhpcBLASctl::omp_set_num_threads`.
|
|
||||||
#' @rdname xgbConfig
|
|
||||||
#' @name xgb.set.config, xgb.get.config
|
|
||||||
#' @export xgb.set.config xgb.get.config
|
|
||||||
#' @param ... List of parameters to be set, as keyword arguments
|
|
||||||
#' @return
|
|
||||||
#' `xgb.set.config()` returns `TRUE` to signal success. `xgb.get.config()` returns
|
|
||||||
#' a list containing all global-scope parameters and their values.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' # Set verbosity level to silent (0)
|
|
||||||
#' xgb.set.config(verbosity = 0)
|
|
||||||
#' # Now global verbosity level is 0
|
|
||||||
#' config <- xgb.get.config()
|
|
||||||
#' print(config$verbosity)
|
|
||||||
#' # Set verbosity level to warning (1)
|
|
||||||
#' xgb.set.config(verbosity = 1)
|
|
||||||
#' # Now global verbosity level is 1
|
|
||||||
#' config <- xgb.get.config()
|
|
||||||
#' print(config$verbosity)
|
|
||||||
xgb.set.config <- function(...) {
|
|
||||||
new_config <- list(...)
|
|
||||||
.Call(XGBSetGlobalConfig_R, jsonlite::toJSON(new_config, auto_unbox = TRUE))
|
|
||||||
return(TRUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
#' @rdname xgbConfig
|
|
||||||
xgb.get.config <- function() {
|
|
||||||
config <- .Call(XGBGetGlobalConfig_R)
|
|
||||||
return(jsonlite::fromJSON(config))
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
#' 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.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' This is the function inspired from the paragraph 3.1 of the paper:
|
|
||||||
#'
|
|
||||||
#' **Practical Lessons from Predicting Clicks on Ads at Facebook**
|
|
||||||
#'
|
|
||||||
#' *(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/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 `[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."
|
|
||||||
#'
|
|
||||||
#' @param model Decision tree boosting model learned on the original data.
|
|
||||||
#' @param data Original data (usually provided as a `dgCMatrix` matrix).
|
|
||||||
#' @param ... Currently not used.
|
|
||||||
#'
|
|
||||||
#' @return A `dgCMatrix` matrix including both the original data and the new features.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
#' dtest <- with(agaricus.test, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
#'
|
|
||||||
#' param <- list(max_depth = 2, eta = 1, objective = 'binary:logistic')
|
|
||||||
#' nrounds = 4
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(params = param, data = dtrain, nrounds = nrounds, 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, nthread = 2
|
|
||||||
#' )
|
|
||||||
#' new.dtest <- xgb.DMatrix(
|
|
||||||
#' data = new.features.test, label = agaricus.test$label, nthread = 2
|
|
||||||
#' )
|
|
||||||
#' bst <- xgb.train(params = param, data = new.dtrain, nrounds = nrounds, 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)) # nolint
|
|
||||||
}
|
|
||||||
@@ -1,394 +0,0 @@
|
|||||||
#' Cross Validation
|
|
||||||
#'
|
|
||||||
#' The cross validation function of xgboost.
|
|
||||||
#'
|
|
||||||
#' @param params The list of parameters. The complete list of parameters is available in the
|
|
||||||
#' [online documentation](http://xgboost.readthedocs.io/en/latest/parameter.html).
|
|
||||||
#' Below is a shorter summary:
|
|
||||||
#' - `objective`: Objective function, common ones are
|
|
||||||
#' - `reg:squarederror`: Regression with squared loss.
|
|
||||||
#' - `binary:logistic`: Logistic regression for classification.
|
|
||||||
#'
|
|
||||||
#' See [xgb.train()] for complete list of objectives.
|
|
||||||
#' - `eta`: Step size of each boosting step
|
|
||||||
#' - `max_depth`: Maximum depth of the tree
|
|
||||||
#' - `nthread`: Number of threads used in training. If not set, all threads are used
|
|
||||||
#'
|
|
||||||
#' See [xgb.train()] for further details.
|
|
||||||
#' See also demo for walkthrough example in R.
|
|
||||||
#'
|
|
||||||
#' Note that, while `params` accepts a `seed` entry and will use such parameter for model training if
|
|
||||||
#' supplied, this seed is not used for creation of train-test splits, which instead rely on R's own RNG
|
|
||||||
#' system - thus, for reproducible results, one needs to call the [set.seed()] function beforehand.
|
|
||||||
#' @param data An `xgb.DMatrix` object, with corresponding fields like `label` or bounds as required
|
|
||||||
#' for model training by the objective.
|
|
||||||
#'
|
|
||||||
#' Note that only the basic `xgb.DMatrix` class is supported - variants such as `xgb.QuantileDMatrix`
|
|
||||||
#' or `xgb.ExtMemDMatrix` are not supported here.
|
|
||||||
#' @param nrounds The max number of iterations.
|
|
||||||
#' @param nfold The original dataset is randomly partitioned into `nfold` equal size subsamples.
|
|
||||||
#' @param prediction A logical value indicating whether to return the test fold predictions
|
|
||||||
#' from each CV model. This parameter engages the [xgb.cb.cv.predict()] callback.
|
|
||||||
#' @param showsd Logical value 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:
|
|
||||||
#' - `error`: Binary classification error rate
|
|
||||||
#' - `rmse`: Root mean square error
|
|
||||||
#' - `logloss`: Negative log-likelihood function
|
|
||||||
#' - `mae`: Mean absolute error
|
|
||||||
#' - `mape`: Mean absolute percentage error
|
|
||||||
#' - `auc`: Area under curve
|
|
||||||
#' - `aucpr`: Area under PR curve
|
|
||||||
#' - `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.
|
|
||||||
#' @param feval Customized evaluation function. Returns
|
|
||||||
#' `list(metric='metric-name', value='metric-value')` with given prediction and dtrain.
|
|
||||||
#' @param stratified Logical flag indicating whether sampling of folds should be stratified
|
|
||||||
#' by the values of outcome labels. For real-valued labels in regression objectives,
|
|
||||||
#' stratification will be done by discretizing the labels into up to 5 buckets beforehand.
|
|
||||||
#'
|
|
||||||
#' If passing "auto", will be set to `TRUE` if the objective in `params` is a classification
|
|
||||||
#' objective (from XGBoost's built-in objectives, doesn't apply to custom ones), and to
|
|
||||||
#' `FALSE` otherwise.
|
|
||||||
#'
|
|
||||||
#' This parameter is ignored when `data` has a `group` field - in such case, the splitting
|
|
||||||
#' will be based on whole groups (note that this might make the folds have different sizes).
|
|
||||||
#'
|
|
||||||
#' Value `TRUE` here is **not** supported for custom objectives.
|
|
||||||
#' @param folds List with pre-defined CV folds (each element must be a vector of test fold's indices).
|
|
||||||
#' When folds are supplied, the `nfold` and `stratified` parameters are ignored.
|
|
||||||
#'
|
|
||||||
#' If `data` has a `group` field and the objective requires this field, each fold (list element)
|
|
||||||
#' must additionally have two attributes (retrievable through `attributes`) named `group_test`
|
|
||||||
#' and `group_train`, which should hold the `group` to assign through [setinfo.xgb.DMatrix()] to
|
|
||||||
#' the resulting DMatrices.
|
|
||||||
#' @param train_folds List specifying which indices to use for training. If `NULL`
|
|
||||||
#' (the default) all indices not specified in `folds` will be used for training.
|
|
||||||
#'
|
|
||||||
#' This is not supported when `data` has `group` field.
|
|
||||||
#' @param verbose Logical flag. Should statistics be printed during the process?
|
|
||||||
#' @param print_every_n Print each nth iteration evaluation messages when `verbose > 0`.
|
|
||||||
#' Default is 1 which means all messages are printed. This parameter is passed to the
|
|
||||||
#' [xgb.cb.print.evaluation()] callback.
|
|
||||||
#' @param early_stopping_rounds If `NULL`, the early stopping function is not triggered.
|
|
||||||
#' If set to an integer `k`, training with a validation set will stop if the performance
|
|
||||||
#' doesn't improve for `k` rounds.
|
|
||||||
#' Setting this parameter engages the [xgb.cb.early.stop()] callback.
|
|
||||||
#' @param maximize If `feval` and `early_stopping_rounds` are set,
|
|
||||||
#' then this parameter must be set as well.
|
|
||||||
#' When it is `TRUE`, it means the larger the evaluation score the better.
|
|
||||||
#' This parameter is passed to the [xgb.cb.early.stop()] callback.
|
|
||||||
#' @param callbacks A list of callback functions to perform various task during boosting.
|
|
||||||
#' See [xgb.Callback()]. 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 `params`.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' The original sample is randomly partitioned into `nfold` equal size subsamples.
|
|
||||||
#'
|
|
||||||
#' Of the `nfold` subsamples, a single subsample is retained as the validation data for testing the model,
|
|
||||||
#' and the remaining `nfold - 1` subsamples are used as training data.
|
|
||||||
#'
|
|
||||||
#' The cross-validation process is then repeated `nrounds` times, with each of the
|
|
||||||
#' `nfold` subsamples used exactly once as the validation data.
|
|
||||||
#'
|
|
||||||
#' All observations are used for both training and validation.
|
|
||||||
#'
|
|
||||||
#' Adapted from \url{https://en.wikipedia.org/wiki/Cross-validation_\%28statistics\%29}
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' An object of class 'xgb.cv.synchronous' with the following elements:
|
|
||||||
#' - `call`: Function call.
|
|
||||||
#' - `params`: Parameters that were passed to the xgboost library. Note that it does not
|
|
||||||
#' capture parameters changed by the [xgb.cb.reset.parameters()] callback.
|
|
||||||
#' - `evaluation_log`: Evaluation history stored as a `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 [xgb.cb.evaluation.log()] callback.
|
|
||||||
#' - `niter`: Number of boosting iterations.
|
|
||||||
#' - `nfeatures`: Number of features in training data.
|
|
||||||
#' - `folds`: The list of CV folds' indices - either those passed through the `folds`
|
|
||||||
#' parameter or randomly generated.
|
|
||||||
#' - `best_iteration`: Iteration number with the best evaluation metric value
|
|
||||||
#' (only available with early stopping).
|
|
||||||
#'
|
|
||||||
#' Plus other potential elements that are the result of callbacks, such as a list `cv_predict` with
|
|
||||||
#' a sub-element `pred` when passing `prediction = TRUE`, which is added by the [xgb.cb.cv.predict()]
|
|
||||||
#' callback (note that one can also pass it manually under `callbacks` with different settings,
|
|
||||||
#' such as saving also the models created during cross validation); or a list `early_stop` which
|
|
||||||
#' will contain elements such as `best_iteration` when using the early stopping callback ([xgb.cb.early.stop()]).
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
#'
|
|
||||||
#' 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,
|
|
||||||
prediction = FALSE, showsd = TRUE, metrics = list(),
|
|
||||||
obj = NULL, feval = NULL, stratified = "auto", folds = NULL, train_folds = NULL,
|
|
||||||
verbose = TRUE, print_every_n = 1L,
|
|
||||||
early_stopping_rounds = NULL, maximize = NULL, callbacks = list(), ...) {
|
|
||||||
|
|
||||||
check.deprecation(...)
|
|
||||||
stopifnot(inherits(data, "xgb.DMatrix"))
|
|
||||||
if (inherits(data, "xgb.DMatrix") && .Call(XGCheckNullPtr_R, data)) {
|
|
||||||
stop("'data' is an invalid 'xgb.DMatrix' object. Must be constructed again.")
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (stratified == "auto") {
|
|
||||||
if (is.character(params$objective)) {
|
|
||||||
stratified <- (
|
|
||||||
(params$objective %in% .CLASSIFICATION_OBJECTIVES())
|
|
||||||
&& !(params$objective %in% .RANKING_OBJECTIVES())
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
stratified <- FALSE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check the labels and groups
|
|
||||||
cv_label <- getinfo(data, "label")
|
|
||||||
cv_group <- getinfo(data, "group")
|
|
||||||
if (!is.null(train_folds) && NROW(cv_group)) {
|
|
||||||
stop("'train_folds' is not supported for DMatrix object with 'group' field.")
|
|
||||||
}
|
|
||||||
|
|
||||||
# CV folds
|
|
||||||
if (!is.null(folds)) {
|
|
||||||
if (!is.list(folds) || 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)
|
|
||||||
} else {
|
|
||||||
if (nfold <= 1)
|
|
||||||
stop("'nfold' must be > 1")
|
|
||||||
folds <- generate.cv.folds(nfold, nrow(data), stratified, cv_label, cv_group, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Callbacks
|
|
||||||
tmp <- .process.callbacks(callbacks, is_cv = TRUE)
|
|
||||||
callbacks <- tmp$callbacks
|
|
||||||
cb_names <- tmp$cb_names
|
|
||||||
rm(tmp)
|
|
||||||
|
|
||||||
# Early stopping callback
|
|
||||||
if (!is.null(early_stopping_rounds) && !("early_stop" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(
|
|
||||||
callbacks,
|
|
||||||
xgb.cb.early.stop(
|
|
||||||
early_stopping_rounds,
|
|
||||||
maximize = maximize,
|
|
||||||
verbose = verbose
|
|
||||||
),
|
|
||||||
as_first_elt = TRUE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
# verbosity & evaluation printing callback:
|
|
||||||
params <- c(params, list(silent = 1))
|
|
||||||
print_every_n <- max(as.integer(print_every_n), 1L)
|
|
||||||
if (verbose && !("print_evaluation" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.print.evaluation(print_every_n, showsd = showsd))
|
|
||||||
}
|
|
||||||
# evaluation log callback: always is on in CV
|
|
||||||
if (!("evaluation_log" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.evaluation.log())
|
|
||||||
}
|
|
||||||
# CV-predictions callback
|
|
||||||
if (prediction && !("cv_predict" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.cv.predict(save_models = FALSE))
|
|
||||||
}
|
|
||||||
|
|
||||||
# create the booster-folds
|
|
||||||
# train_folds
|
|
||||||
dall <- data
|
|
||||||
bst_folds <- lapply(seq_along(folds), function(k) {
|
|
||||||
dtest <- xgb.slice.DMatrix(dall, folds[[k]], allow_groups = TRUE)
|
|
||||||
# code originally contributed by @RolandASc on stackoverflow
|
|
||||||
if (is.null(train_folds))
|
|
||||||
dtrain <- xgb.slice.DMatrix(dall, unlist(folds[-k]), allow_groups = TRUE)
|
|
||||||
else
|
|
||||||
dtrain <- xgb.slice.DMatrix(dall, train_folds[[k]], allow_groups = TRUE)
|
|
||||||
if (!is.null(attributes(folds[[k]])$group_test)) {
|
|
||||||
setinfo(dtest, "group", attributes(folds[[k]])$group_test)
|
|
||||||
setinfo(dtrain, "group", attributes(folds[[k]])$group_train)
|
|
||||||
}
|
|
||||||
bst <- xgb.Booster(
|
|
||||||
params = params,
|
|
||||||
cachelist = list(dtrain, dtest),
|
|
||||||
modelfile = NULL
|
|
||||||
)
|
|
||||||
bst <- bst$bst
|
|
||||||
list(dtrain = dtrain, bst = bst, evals = list(train = dtrain, test = dtest), index = folds[[k]])
|
|
||||||
})
|
|
||||||
|
|
||||||
# extract parameters that can affect the relationship b/w #trees and #iterations
|
|
||||||
num_class <- max(as.numeric(NVL(params[['num_class']], 1)), 1) # nolint
|
|
||||||
|
|
||||||
# those are fixed for CV (no training continuation)
|
|
||||||
begin_iteration <- 1
|
|
||||||
end_iteration <- nrounds
|
|
||||||
|
|
||||||
.execute.cb.before.training(
|
|
||||||
callbacks,
|
|
||||||
bst_folds,
|
|
||||||
dall,
|
|
||||||
NULL,
|
|
||||||
begin_iteration,
|
|
||||||
end_iteration
|
|
||||||
)
|
|
||||||
|
|
||||||
# synchronous CV boosting: run CV folds' models within each iteration
|
|
||||||
for (iteration in begin_iteration:end_iteration) {
|
|
||||||
|
|
||||||
.execute.cb.before.iter(
|
|
||||||
callbacks,
|
|
||||||
bst_folds,
|
|
||||||
dall,
|
|
||||||
NULL,
|
|
||||||
iteration
|
|
||||||
)
|
|
||||||
|
|
||||||
msg <- lapply(bst_folds, function(fd) {
|
|
||||||
xgb.iter.update(
|
|
||||||
bst = fd$bst,
|
|
||||||
dtrain = fd$dtrain,
|
|
||||||
iter = iteration - 1,
|
|
||||||
obj = obj
|
|
||||||
)
|
|
||||||
xgb.iter.eval(
|
|
||||||
bst = fd$bst,
|
|
||||||
evals = fd$evals,
|
|
||||||
iter = iteration - 1,
|
|
||||||
feval = feval
|
|
||||||
)
|
|
||||||
})
|
|
||||||
msg <- simplify2array(msg)
|
|
||||||
|
|
||||||
should_stop <- .execute.cb.after.iter(
|
|
||||||
callbacks,
|
|
||||||
bst_folds,
|
|
||||||
dall,
|
|
||||||
NULL,
|
|
||||||
iteration,
|
|
||||||
msg
|
|
||||||
)
|
|
||||||
|
|
||||||
if (should_stop) break
|
|
||||||
}
|
|
||||||
cb_outputs <- .execute.cb.after.training(
|
|
||||||
callbacks,
|
|
||||||
bst_folds,
|
|
||||||
dall,
|
|
||||||
NULL,
|
|
||||||
iteration,
|
|
||||||
msg
|
|
||||||
)
|
|
||||||
|
|
||||||
# the CV result
|
|
||||||
ret <- list(
|
|
||||||
call = match.call(),
|
|
||||||
params = params,
|
|
||||||
niter = iteration,
|
|
||||||
nfeatures = ncol(dall),
|
|
||||||
folds = folds
|
|
||||||
)
|
|
||||||
ret <- c(ret, cb_outputs)
|
|
||||||
|
|
||||||
class(ret) <- 'xgb.cv.synchronous'
|
|
||||||
return(invisible(ret))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#' Print xgb.cv result
|
|
||||||
#'
|
|
||||||
#' Prints formatted results of [xgb.cv()].
|
|
||||||
#'
|
|
||||||
#' @param x An `xgb.cv.synchronous` object.
|
|
||||||
#' @param verbose Whether to print detailed data.
|
|
||||||
#' @param ... Passed to `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 = xgb.DMatrix(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 = '')
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n in c('niter', 'best_iteration')) {
|
|
||||||
if (is.null(x$early_stop[[n]]))
|
|
||||||
next
|
|
||||||
cat(n, ': ', x$early_stop[[n]], '\n', sep = '')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is.null(x$cv_predict$pred)) {
|
|
||||||
cat('pred:\n')
|
|
||||||
str(x$cv_predict$pred)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
cat('evaluation_log:\n')
|
|
||||||
print(x$evaluation_log, row.names = FALSE, ...)
|
|
||||||
|
|
||||||
if (!is.null(x$early_stop$best_iteration)) {
|
|
||||||
cat('Best iteration:\n')
|
|
||||||
print(x$evaluation_log[x$early_stop$best_iteration], row.names = FALSE, ...)
|
|
||||||
}
|
|
||||||
invisible(x)
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#' Dump an XGBoost model in text format.
|
|
||||||
#'
|
|
||||||
#' Dump an XGBoost model in text format.
|
|
||||||
#'
|
|
||||||
#' @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 `NULL`, the model is returned as a character vector.
|
|
||||||
#' @param fmap Feature map file representing feature types. See demo/ for a walkthrough
|
|
||||||
#' example in R, and \url{https://github.com/dmlc/xgboost/blob/master/demo/data/featmap.txt}
|
|
||||||
#' to see an example of the value.
|
|
||||||
#' @param with_stats Whether to dump some additional statistics about the splits.
|
|
||||||
#' When this option is on, the model dump contains two additional values:
|
|
||||||
#' gain is the approximate loss function gain we get in each split;
|
|
||||||
#' cover is the sum of second order gradient in each node.
|
|
||||||
#' @param dump_format Either 'text', 'json', or 'dot' (graphviz) format could be specified.
|
|
||||||
#'
|
|
||||||
#' Format 'dot' for a single tree can be passed directly to packages that consume this format
|
|
||||||
#' for graph visualization, such as function `DiagrammeR::grViz()`
|
|
||||||
#' @param ... Currently not used
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' If fname is not provided or set to `NULL` the function will return the model
|
|
||||||
#' as a character vector. Otherwise it will return `TRUE`.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' \dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' train <- agaricus.train
|
|
||||||
#' test <- agaricus.test
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(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'
|
|
||||||
#' dump_path = file.path(tempdir(), 'model.dump')
|
|
||||||
#' xgb.dump(bst, dump_path, with_stats = TRUE)
|
|
||||||
#'
|
|
||||||
#' # print the model without saving it to a file
|
|
||||||
#' print(xgb.dump(bst, with_stats = TRUE))
|
|
||||||
#'
|
|
||||||
#' # print in JSON format:
|
|
||||||
#' cat(xgb.dump(bst, with_stats = TRUE, dump_format = "json"))
|
|
||||||
#'
|
|
||||||
#' # plot first tree leveraging the 'dot' format
|
|
||||||
#' if (requireNamespace('DiagrammeR', quietly = TRUE)) {
|
|
||||||
#' DiagrammeR::grViz(xgb.dump(bst, dump_format = "dot")[[1L]])
|
|
||||||
#' }
|
|
||||||
#' @export
|
|
||||||
xgb.dump <- function(model, fname = NULL, fmap = "", with_stats = FALSE,
|
|
||||||
dump_format = c("text", "json", "dot"), ...) {
|
|
||||||
check.deprecation(...)
|
|
||||||
dump_format <- match.arg(dump_format)
|
|
||||||
if (!inherits(model, "xgb.Booster"))
|
|
||||||
stop("model: argument must be of type xgb.Booster")
|
|
||||||
if (!(is.null(fname) || is.character(fname)))
|
|
||||||
stop("fname: argument must be a character string (when provided)")
|
|
||||||
if (!(is.null(fmap) || is.character(fmap)))
|
|
||||||
stop("fmap: argument must be a character string (when provided)")
|
|
||||||
|
|
||||||
model_dump <- .Call(
|
|
||||||
XGBoosterDumpModel_R,
|
|
||||||
xgb.get.handle(model),
|
|
||||||
NVL(fmap, "")[1],
|
|
||||||
as.integer(with_stats),
|
|
||||||
as.character(dump_format)
|
|
||||||
)
|
|
||||||
if (dump_format == "dot") {
|
|
||||||
return(sapply(model_dump, function(x) gsub("^booster\\[\\d+\\]\\n", "\\1", x)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is.null(fname))
|
|
||||||
model_dump <- gsub('\t', '', model_dump, fixed = TRUE)
|
|
||||||
|
|
||||||
if (dump_format == "text")
|
|
||||||
model_dump <- unlist(strsplit(model_dump, '\n', fixed = TRUE))
|
|
||||||
|
|
||||||
model_dump <- grep('^\\s*$', model_dump, invert = TRUE, value = TRUE)
|
|
||||||
|
|
||||||
if (is.null(fname)) {
|
|
||||||
return(model_dump)
|
|
||||||
} else {
|
|
||||||
fname <- path.expand(fname)
|
|
||||||
writeLines(model_dump, fname[1])
|
|
||||||
return(TRUE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
# 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 = seq_len(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.5),
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#' @rdname xgb.plot.shap.summary
|
|
||||||
#' @export
|
|
||||||
xgb.ggplot.shap.summary <- function(data, shap_contrib = NULL, features = NULL, top_n = 10, model = NULL,
|
|
||||||
trees = NULL, target_class = NULL, approxcontrib = FALSE, subsample = NULL) {
|
|
||||||
if (inherits(data, "xgb.DMatrix")) {
|
|
||||||
stop(
|
|
||||||
"'xgb.ggplot.shap.summary' is not compatible with 'xgb.DMatrix' objects. Try passing a matrix or data.frame."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
cols_categ <- NULL
|
|
||||||
if (!is.null(model)) {
|
|
||||||
ftypes <- getinfo(model, "feature_type")
|
|
||||||
if (NROW(ftypes)) {
|
|
||||||
if (length(ftypes) != ncol(data)) {
|
|
||||||
stop(sprintf("'data' has incorrect number of columns (expected: %d, got: %d).", length(ftypes), ncol(data)))
|
|
||||||
}
|
|
||||||
cols_categ <- colnames(data)[ftypes == "c"]
|
|
||||||
}
|
|
||||||
} else if (inherits(data, "data.frame")) {
|
|
||||||
cols_categ <- names(data)[sapply(data, function(x) is.factor(x) || is.character(x))]
|
|
||||||
}
|
|
||||||
if (NROW(cols_categ)) {
|
|
||||||
warning("Categorical features are ignored in 'xgb.ggplot.shap.summary'.")
|
|
||||||
}
|
|
||||||
|
|
||||||
data_list <- xgb.shap.data(
|
|
||||||
data = data,
|
|
||||||
shap_contrib = shap_contrib,
|
|
||||||
features = features,
|
|
||||||
top_n = top_n,
|
|
||||||
model = model,
|
|
||||||
trees = trees,
|
|
||||||
target_class = target_class,
|
|
||||||
approxcontrib = approxcontrib,
|
|
||||||
subsample = subsample,
|
|
||||||
max_observations = 10000 # 10,000 samples per feature.
|
|
||||||
)
|
|
||||||
if (NROW(cols_categ)) {
|
|
||||||
data_list <- lapply(data_list, function(x) x[, !(colnames(x) %in% cols_categ), drop = FALSE])
|
|
||||||
}
|
|
||||||
|
|
||||||
p_data <- prepare.ggplot.shap.data(data_list, normalize = TRUE)
|
|
||||||
# Reverse factor levels so that the first level is at the top of the plot
|
|
||||||
p_data[, "feature" := factor(feature, rev(levels(feature)))]
|
|
||||||
p <- ggplot2::ggplot(p_data, ggplot2::aes(x = feature, y = p_data$shap_value, colour = p_data$feature_value)) +
|
|
||||||
ggplot2::geom_jitter(alpha = 0.5, width = 0.1) +
|
|
||||||
ggplot2::scale_colour_viridis_c(limits = c(-3, 3), option = "plasma", direction = -1) +
|
|
||||||
ggplot2::geom_abline(slope = 0, intercept = 0, colour = "darkgrey") +
|
|
||||||
ggplot2::coord_flip()
|
|
||||||
|
|
||||||
p
|
|
||||||
}
|
|
||||||
|
|
||||||
#' Combine feature values and SHAP values
|
|
||||||
#'
|
|
||||||
#' Internal function used to combine and melt feature values and SHAP contributions
|
|
||||||
#' as required for ggplot functions related to SHAP.
|
|
||||||
#'
|
|
||||||
#' @param data_list The result of `xgb.shap.data()`.
|
|
||||||
#' @param normalize Whether to standardize feature values to mean 0 and
|
|
||||||
#' standard deviation 1. This is useful for comparing multiple features on the same
|
|
||||||
#' plot. Default is `FALSE`. Note that it cannot be used when the data contains
|
|
||||||
#' categorical features.
|
|
||||||
#' @return A `data.table` containing the observation ID, the feature name, the
|
|
||||||
#' feature value (normalized if specified), and the SHAP contribution value.
|
|
||||||
#' @noRd
|
|
||||||
#' @keywords internal
|
|
||||||
prepare.ggplot.shap.data <- function(data_list, normalize = FALSE) {
|
|
||||||
data <- data_list[["data"]]
|
|
||||||
shap_contrib <- data_list[["shap_contrib"]]
|
|
||||||
|
|
||||||
data <- data.table::as.data.table(as.matrix(data))
|
|
||||||
if (normalize) {
|
|
||||||
data[, (names(data)) := lapply(.SD, normalize)]
|
|
||||||
}
|
|
||||||
data[, "id" := seq_len(nrow(data))]
|
|
||||||
data_m <- data.table::melt.data.table(data, id.vars = "id", variable.name = "feature", value.name = "feature_value")
|
|
||||||
|
|
||||||
shap_contrib <- data.table::as.data.table(as.matrix(shap_contrib))
|
|
||||||
shap_contrib[, "id" := seq_len(nrow(shap_contrib))]
|
|
||||||
shap_contrib_m <- data.table::melt.data.table(shap_contrib, id.vars = "id", variable.name = "feature", value.name = "shap_value")
|
|
||||||
|
|
||||||
p_data <- data.table::merge.data.table(data_m, shap_contrib_m, by = c("id", "feature"))
|
|
||||||
|
|
||||||
p_data
|
|
||||||
}
|
|
||||||
|
|
||||||
#' Scale feature values
|
|
||||||
#'
|
|
||||||
#' Internal function that scales feature values to mean 0 and standard deviation 1.
|
|
||||||
#' Useful to compare multiple features on the same plot.
|
|
||||||
#'
|
|
||||||
#' @param x Numeric vector.
|
|
||||||
#' @return Numeric vector with mean 0 and standard deviation 1.
|
|
||||||
#' @noRd
|
|
||||||
#' @keywords internal
|
|
||||||
normalize <- function(x) {
|
|
||||||
loc <- mean(x, na.rm = TRUE)
|
|
||||||
scale <- stats::sd(x, na.rm = TRUE)
|
|
||||||
|
|
||||||
(x - loc) / scale
|
|
||||||
}
|
|
||||||
|
|
||||||
# Plot multiple ggplot graph aligned by rows and columns.
|
|
||||||
# ... the plots
|
|
||||||
# cols number of columns
|
|
||||||
# internal utility function
|
|
||||||
multiplot <- function(..., cols) {
|
|
||||||
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", "V1", "Weight", "feature"
|
|
||||||
))
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
#' Feature importance
|
|
||||||
#'
|
|
||||||
#' Creates a `data.table` of feature importances.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' This function works for both linear and tree models.
|
|
||||||
#'
|
|
||||||
#' For linear models, the importance is the absolute magnitude of linear coefficients.
|
|
||||||
#' To obtain a meaningful ranking by importance for linear models, the features need to
|
|
||||||
#' be on the same scale (which is also recommended when using L1 or L2 regularization).
|
|
||||||
#'
|
|
||||||
#' @param feature_names Character vector used to overwrite the feature names
|
|
||||||
#' of the model. The default is `NULL` (use original feature names).
|
|
||||||
#' @param model Object of class `xgb.Booster`.
|
|
||||||
#' @param trees An integer vector of tree indices that should be included
|
|
||||||
#' into the importance calculation (only for the "gbtree" booster).
|
|
||||||
#' The default (`NULL`) parses all trees.
|
|
||||||
#' It could be useful, e.g., in multiclass classification to get feature importances
|
|
||||||
#' for each class separately. *Important*: the tree index in XGBoost models
|
|
||||||
#' is zero-based (e.g., use `trees = 0:4` for the first five trees).
|
|
||||||
#' @param data Deprecated.
|
|
||||||
#' @param label Deprecated.
|
|
||||||
#' @param target Deprecated.
|
|
||||||
#' @return A `data.table` with the following columns:
|
|
||||||
#'
|
|
||||||
#' For a tree model:
|
|
||||||
#' - `Features`: Names of the features used in the model.
|
|
||||||
#' - `Gain`: Fractional contribution of each feature to the model based on
|
|
||||||
#' the total gain of this feature's splits. Higher percentage means higher importance.
|
|
||||||
#' - `Cover`: Metric of the number of observation related to this feature.
|
|
||||||
#' - `Frequency`: Percentage of times a feature has been used in trees.
|
|
||||||
#'
|
|
||||||
#' For a linear model:
|
|
||||||
#' - `Features`: Names of the features used in the model.
|
|
||||||
#' - `Weight`: Linear coefficient of this feature.
|
|
||||||
#' - `Class`: Class label (only for multiclass models).
|
|
||||||
#'
|
|
||||||
#' If `feature_names` is not provided and `model` doesn't have `feature_names`,
|
|
||||||
#' the index of the features will be used instead. Because the index is extracted from the model dump
|
|
||||||
#' (based on C++ code), it starts at 0 (as in C/C++ or Python) instead of 1 (usual in R).
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#'
|
|
||||||
#' # binomial classification using "gbtree":
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = 2,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.importance(model = bst)
|
|
||||||
#'
|
|
||||||
#' # binomial classification using "gblinear":
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' booster = "gblinear",
|
|
||||||
#' eta = 0.3,
|
|
||||||
#' nthread = 1,
|
|
||||||
#' nrounds = 20,objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.importance(model = bst)
|
|
||||||
#'
|
|
||||||
#' # multiclass classification using "gbtree":
|
|
||||||
#' nclass <- 3
|
|
||||||
#' nrounds <- 10
|
|
||||||
#' mbst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(
|
|
||||||
#' as.matrix(iris[, -5]),
|
|
||||||
#' label = as.numeric(iris$Species) - 1
|
|
||||||
#' ),
|
|
||||||
#' max_depth = 3,
|
|
||||||
#' eta = 0.2,
|
|
||||||
#' nthread = 2,
|
|
||||||
#' nrounds = nrounds,
|
|
||||||
#' objective = "multi:softprob",
|
|
||||||
#' num_class = nclass
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # all classes clumped together:
|
|
||||||
#' xgb.importance(model = mbst)
|
|
||||||
#'
|
|
||||||
#' # inspect importances separately for each class:
|
|
||||||
#' xgb.importance(
|
|
||||||
#' model = mbst, trees = seq(from = 0, by = nclass, length.out = nrounds)
|
|
||||||
#' )
|
|
||||||
#' xgb.importance(
|
|
||||||
#' model = mbst, trees = seq(from = 1, by = nclass, length.out = nrounds)
|
|
||||||
#' )
|
|
||||||
#' xgb.importance(
|
|
||||||
#' model = mbst, trees = seq(from = 2, by = nclass, length.out = nrounds)
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # multiclass classification using "gblinear":
|
|
||||||
#' mbst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(
|
|
||||||
#' scale(as.matrix(iris[, -5])),
|
|
||||||
#' label = as.numeric(iris$Species) - 1
|
|
||||||
#' ),
|
|
||||||
#' booster = "gblinear",
|
|
||||||
#' eta = 0.2,
|
|
||||||
#' nthread = 1,
|
|
||||||
#' nrounds = 15,
|
|
||||||
#' objective = "multi:softprob",
|
|
||||||
#' num_class = nclass
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.importance(model = mbst)
|
|
||||||
#'
|
|
||||||
#' @export
|
|
||||||
xgb.importance <- function(model = NULL, feature_names = getinfo(model, "feature_name"), trees = NULL,
|
|
||||||
data = NULL, label = NULL, target = NULL) {
|
|
||||||
|
|
||||||
if (!(is.null(data) && is.null(label) && is.null(target)))
|
|
||||||
warning("xgb.importance: parameters 'data', 'label' and 'target' are deprecated")
|
|
||||||
|
|
||||||
if (!(is.null(feature_names) || is.character(feature_names)))
|
|
||||||
stop("feature_names: Has to be a character vector")
|
|
||||||
|
|
||||||
handle <- xgb.get.handle(model)
|
|
||||||
if (xgb.booster_type(model) == "gblinear") {
|
|
||||||
args <- list(importance_type = "weight", feature_names = feature_names)
|
|
||||||
results <- .Call(
|
|
||||||
XGBoosterFeatureScore_R, handle, jsonlite::toJSON(args, auto_unbox = TRUE, null = "null")
|
|
||||||
)
|
|
||||||
names(results) <- c("features", "shape", "weight")
|
|
||||||
if (length(results$shape) == 2) {
|
|
||||||
n_classes <- results$shape[2]
|
|
||||||
} else {
|
|
||||||
n_classes <- 0
|
|
||||||
}
|
|
||||||
importance <- if (n_classes == 0) {
|
|
||||||
data.table(Feature = results$features, Weight = results$weight)[order(-abs(Weight))]
|
|
||||||
} else {
|
|
||||||
data.table(
|
|
||||||
Feature = rep(results$features, each = n_classes), Weight = results$weight, Class = seq_len(n_classes) - 1
|
|
||||||
)[order(Class, -abs(Weight))]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
concatenated <- list()
|
|
||||||
output_names <- vector()
|
|
||||||
for (importance_type in c("weight", "total_gain", "total_cover")) {
|
|
||||||
args <- list(importance_type = importance_type, feature_names = feature_names, tree_idx = trees)
|
|
||||||
results <- .Call(
|
|
||||||
XGBoosterFeatureScore_R, handle, jsonlite::toJSON(args, auto_unbox = TRUE, null = "null")
|
|
||||||
)
|
|
||||||
names(results) <- c("features", "shape", importance_type)
|
|
||||||
concatenated[
|
|
||||||
switch(importance_type, "weight" = "Frequency", "total_gain" = "Gain", "total_cover" = "Cover")
|
|
||||||
] <- results[importance_type]
|
|
||||||
output_names <- results$features
|
|
||||||
}
|
|
||||||
importance <- data.table(
|
|
||||||
Feature = output_names,
|
|
||||||
Gain = concatenated$Gain / sum(concatenated$Gain),
|
|
||||||
Cover = concatenated$Cover / sum(concatenated$Cover),
|
|
||||||
Frequency = concatenated$Frequency / sum(concatenated$Frequency)
|
|
||||||
)[order(Gain, decreasing = TRUE)]
|
|
||||||
}
|
|
||||||
importance
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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", "Gain", "Cover", "Frequency", "Feature", "Class"))
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#' Load XGBoost model from binary file
|
|
||||||
#'
|
|
||||||
#' Load XGBoost model from binary model file.
|
|
||||||
#'
|
|
||||||
#' @param modelfile The name of the binary input file.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' The input file is expected to contain a model saved in an XGBoost model format
|
|
||||||
#' using either [xgb.save()] in R, or using some
|
|
||||||
#' appropriate methods from other XGBoost interfaces. E.g., a model trained in Python and
|
|
||||||
#' saved from there in XGBoost format, could be loaded from R.
|
|
||||||
#'
|
|
||||||
#' Note: a model saved as an R object has to be loaded using corresponding R-methods,
|
|
||||||
#' not by [xgb.load()].
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' An object of `xgb.Booster` class.
|
|
||||||
#'
|
|
||||||
#' @seealso [xgb.save()]
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' \dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' train <- agaricus.train
|
|
||||||
#' test <- agaricus.test
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' fname <- file.path(tempdir(), "xgb.ubj")
|
|
||||||
#' xgb.save(bst, fname)
|
|
||||||
#' bst <- xgb.load(fname)
|
|
||||||
#' @export
|
|
||||||
xgb.load <- function(modelfile) {
|
|
||||||
if (is.null(modelfile))
|
|
||||||
stop("xgb.load: modelfile cannot be NULL")
|
|
||||||
|
|
||||||
bst <- xgb.Booster(
|
|
||||||
params = list(),
|
|
||||||
cachelist = list(),
|
|
||||||
modelfile = modelfile
|
|
||||||
)
|
|
||||||
bst <- bst$bst
|
|
||||||
# re-use modelfile if it is raw so we do not need to serialize
|
|
||||||
if (typeof(modelfile) == "raw") {
|
|
||||||
warning(
|
|
||||||
paste(
|
|
||||||
"The support for loading raw booster with `xgb.load` will be ",
|
|
||||||
"discontinued in upcoming release. Use `xgb.load.raw` instead. "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return(bst)
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#' Load serialised XGBoost model from R's raw vector
|
|
||||||
#'
|
|
||||||
#' User can generate raw memory buffer by calling [xgb.save.raw()].
|
|
||||||
#'
|
|
||||||
#' @param buffer The buffer returned by [xgb.save.raw()].
|
|
||||||
#' @export
|
|
||||||
xgb.load.raw <- function(buffer) {
|
|
||||||
cachelist <- list()
|
|
||||||
bst <- .Call(XGBoosterCreate_R, cachelist)
|
|
||||||
.Call(XGBoosterLoadModelFromRaw_R, xgb.get.handle(bst), buffer)
|
|
||||||
return(bst)
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
#' Parse model text dump
|
|
||||||
#'
|
|
||||||
#' Parse a boosted tree model text dump into a `data.table` structure.
|
|
||||||
#'
|
|
||||||
#' @param model Object of class `xgb.Booster`. If it contains feature names (they can
|
|
||||||
#' be set through [setinfo()]), they will be used in the output from this function.
|
|
||||||
#' @param text Character vector previously generated by the function [xgb.dump()]
|
|
||||||
#' (called with parameter `with_stats = TRUE`). `text` takes precedence over `model`.
|
|
||||||
#' @param trees An integer vector of tree indices that should be used. The default
|
|
||||||
#' (`NULL`) uses all trees. Useful, e.g., in multiclass classification to get only
|
|
||||||
#' the trees of one class. *Important*: the tree index in XGBoost models
|
|
||||||
#' is zero-based (e.g., use `trees = 0:4` for the first five trees).
|
|
||||||
#' @param use_int_id A logical flag indicating whether nodes in columns "Yes", "No", and
|
|
||||||
#' "Missing" should be represented as integers (when `TRUE`) or as "Tree-Node"
|
|
||||||
#' character strings (when `FALSE`, default).
|
|
||||||
#' @param ... Currently not used.
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' A `data.table` with detailed information about tree nodes. It has the following columns:
|
|
||||||
#' - `Tree`: integer ID of a tree in a model (zero-based index).
|
|
||||||
#' - `Node`: integer ID of a node in a tree (zero-based index).
|
|
||||||
#' - `ID`: character identifier of a node in a model (only when `use_int_id = FALSE`).
|
|
||||||
#' - `Feature`: for a branch node, a feature ID or name (when available);
|
|
||||||
#' for a leaf node, it simply labels it as `"Leaf"`.
|
|
||||||
#' - `Split`: location of the split for a branch node (split condition is always "less than").
|
|
||||||
#' - `Yes`: ID of the next node when the split condition is met.
|
|
||||||
#' - `No`: ID of the next node when the split condition is not met.
|
|
||||||
#' - `Missing`: ID of the next node when the branch value is missing.
|
|
||||||
#' - `Gain`: either the split gain (change in loss) or the leaf value.
|
|
||||||
#' - `Cover`: metric related to the number of observations either seen by a split
|
|
||||||
#' or collected by a leaf during training.
|
|
||||||
#'
|
|
||||||
#' When `use_int_id = FALSE`, columns "Yes", "No", and "Missing" point to model-wide node identifiers
|
|
||||||
#' in the "ID" column. When `use_int_id = TRUE`, those columns point to node identifiers from
|
|
||||||
#' the corresponding trees in the "Node" column.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' # Basic use:
|
|
||||||
#'
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # This bst model already has feature_names stored with it, so those would be used when
|
|
||||||
#' # feature_names is not set:
|
|
||||||
#' dt <- xgb.model.dt.tree(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(model = NULL, text = NULL,
|
|
||||||
trees = NULL, use_int_id = FALSE, ...) {
|
|
||||||
check.deprecation(...)
|
|
||||||
|
|
||||||
if (!inherits(model, "xgb.Booster") && !is.character(text)) {
|
|
||||||
stop("Either 'model' must be an object of class xgb.Booster\n",
|
|
||||||
" or 'text' must be a character vector with the result of xgb.dump\n",
|
|
||||||
" (or NULL if 'model' was provided).")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(is.null(trees) || is.numeric(trees))) {
|
|
||||||
stop("trees: must be a vector of integers.")
|
|
||||||
}
|
|
||||||
|
|
||||||
feature_names <- NULL
|
|
||||||
if (inherits(model, "xgb.Booster")) {
|
|
||||||
feature_names <- xgb.feature_names(model)
|
|
||||||
}
|
|
||||||
|
|
||||||
from_text <- TRUE
|
|
||||||
if (is.null(text)) {
|
|
||||||
text <- xgb.dump(model = model, with_stats = TRUE)
|
|
||||||
from_text <- FALSE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length(text) < 2 || !any(grepl('leaf=(-?\\d+)', text))) {
|
|
||||||
stop("Non-tree model detected! This function can only be used with tree models.")
|
|
||||||
}
|
|
||||||
|
|
||||||
position <- which(grepl("booster", text, fixed = TRUE))
|
|
||||||
|
|
||||||
add.tree.id <- function(node, tree) if (use_int_id) node else paste(tree, node, sep = "-")
|
|
||||||
|
|
||||||
anynumber_regex <- "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"
|
|
||||||
|
|
||||||
td <- data.table(t = text)
|
|
||||||
td[position, Tree := 1L]
|
|
||||||
td[, Tree := cumsum(ifelse(is.na(Tree), 0L, Tree)) - 1L]
|
|
||||||
|
|
||||||
if (is.null(trees)) {
|
|
||||||
trees <- 0:max(td$Tree)
|
|
||||||
} else {
|
|
||||||
trees <- trees[trees >= 0 & trees <= max(td$Tree)]
|
|
||||||
}
|
|
||||||
td <- td[Tree %in% trees & !is.na(t) & !startsWith(t, 'booster')]
|
|
||||||
|
|
||||||
td[, Node := as.integer(sub("^([0-9]+):.*", "\\1", t))]
|
|
||||||
if (!use_int_id) td[, ID := add.tree.id(Node, Tree)]
|
|
||||||
td[, isLeaf := grepl("leaf", t, fixed = TRUE)]
|
|
||||||
|
|
||||||
# parse branch lines
|
|
||||||
branch_rx_nonames <- paste0("f(\\d+)<(", anynumber_regex, ")\\] yes=(\\d+),no=(\\d+),missing=(\\d+),",
|
|
||||||
"gain=(", anynumber_regex, "),cover=(", anynumber_regex, ")")
|
|
||||||
branch_rx_w_names <- paste0("\\d+:\\[(.+)<(", anynumber_regex, ")\\] yes=(\\d+),no=(\\d+),missing=(\\d+),",
|
|
||||||
"gain=(", anynumber_regex, "),cover=(", anynumber_regex, ")")
|
|
||||||
text_has_feature_names <- FALSE
|
|
||||||
if (NROW(feature_names)) {
|
|
||||||
branch_rx <- branch_rx_w_names
|
|
||||||
text_has_feature_names <- TRUE
|
|
||||||
} else {
|
|
||||||
# Note: when passing a text dump, it might or might not have feature names,
|
|
||||||
# but that aspect is unknown from just the text attributes
|
|
||||||
branch_rx <- branch_rx_nonames
|
|
||||||
if (from_text) {
|
|
||||||
if (sum(grepl(branch_rx_w_names, text)) > sum(grepl(branch_rx_nonames, text))) {
|
|
||||||
branch_rx <- branch_rx_w_names
|
|
||||||
text_has_feature_names <- TRUE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
branch_cols <- c("Feature", "Split", "Yes", "No", "Missing", "Gain", "Cover")
|
|
||||||
td[
|
|
||||||
isLeaf == FALSE,
|
|
||||||
(branch_cols) := {
|
|
||||||
matches <- regmatches(t, regexec(branch_rx, t))
|
|
||||||
# skip some indices with spurious capture groups from anynumber_regex
|
|
||||||
xtr <- do.call(rbind, matches)[, c(2, 3, 5, 6, 7, 8, 10), drop = FALSE]
|
|
||||||
xtr[, 3:5] <- add.tree.id(xtr[, 3:5], Tree)
|
|
||||||
if (length(xtr) == 0) {
|
|
||||||
as.data.table(
|
|
||||||
list(Feature = "NA", Split = "NA", Yes = "NA", No = "NA", Missing = "NA", Gain = "NA", Cover = "NA")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
as.data.table(xtr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# assign feature_names when available
|
|
||||||
is_stump <- function() {
|
|
||||||
return(length(td$Feature) == 1 && is.na(td$Feature))
|
|
||||||
}
|
|
||||||
if (!text_has_feature_names) {
|
|
||||||
if (!is.null(feature_names) && !is_stump()) {
|
|
||||||
if (length(feature_names) <= max(as.numeric(td$Feature), na.rm = TRUE))
|
|
||||||
stop("feature_names has less elements than there are features used in the model")
|
|
||||||
td[isLeaf == FALSE, Feature := feature_names[as.numeric(Feature) + 1]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# parse leaf lines
|
|
||||||
leaf_rx <- paste0("leaf=(", anynumber_regex, "),cover=(", anynumber_regex, ")")
|
|
||||||
leaf_cols <- c("Feature", "Gain", "Cover")
|
|
||||||
td[
|
|
||||||
isLeaf == TRUE,
|
|
||||||
(leaf_cols) := {
|
|
||||||
matches <- regmatches(t, regexec(leaf_rx, t))
|
|
||||||
xtr <- do.call(rbind, matches)[, c(2, 4)]
|
|
||||||
if (length(xtr) == 2) {
|
|
||||||
c("Leaf", as.data.table(xtr[1]), as.data.table(xtr[2]))
|
|
||||||
} else {
|
|
||||||
c("Leaf", as.data.table(xtr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# convert some columns to numeric
|
|
||||||
numeric_cols <- c("Split", "Gain", "Cover")
|
|
||||||
td[, (numeric_cols) := lapply(.SD, as.numeric), .SDcols = numeric_cols]
|
|
||||||
if (use_int_id) {
|
|
||||||
int_cols <- c("Yes", "No", "Missing")
|
|
||||||
td[, (int_cols) := lapply(.SD, as.integer), .SDcols = int_cols]
|
|
||||||
}
|
|
||||||
|
|
||||||
td[, t := NULL]
|
|
||||||
td[, isLeaf := NULL]
|
|
||||||
|
|
||||||
td[order(Tree, Node)]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Avoid notes during CRAN check.
|
|
||||||
# The reason is that these variables are never declared
|
|
||||||
# They are mainly column names inferred by Data.table...
|
|
||||||
globalVariables(c("Tree", "Node", "ID", "Feature", "t", "isLeaf", ".SD", ".SDcols"))
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
#' Plot model tree depth
|
|
||||||
#'
|
|
||||||
#' Visualizes distributions related to the depth of tree leaves.
|
|
||||||
#' - `xgb.plot.deepness()` uses base R graphics, while
|
|
||||||
#' - `xgb.ggplot.deepness()` uses "ggplot2".
|
|
||||||
#'
|
|
||||||
#' @param model Either an `xgb.Booster` model, or the "data.table" returned
|
|
||||||
#' by [xgb.model.dt.tree()].
|
|
||||||
#' @param which Which distribution to plot (see details).
|
|
||||||
#' @param plot Should the plot be shown? Default is `TRUE`.
|
|
||||||
#' @param ... Other parameters passed to [graphics::barplot()] or [graphics::plot()].
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#'
|
|
||||||
#' When `which = "2x1"`, two distributions with respect to the leaf depth
|
|
||||||
#' are plotted on top of each other:
|
|
||||||
#' 1. The distribution of the number of leaves in a tree model at a certain depth.
|
|
||||||
#' 2. The distribution of the average weighted number of observations ("cover")
|
|
||||||
#' ending up in leaves at a certain depth.
|
|
||||||
#'
|
|
||||||
#' Those could be helpful in determining sensible ranges of the `max_depth`
|
|
||||||
#' and `min_child_weight` parameters.
|
|
||||||
#'
|
|
||||||
#' When `which = "max.depth"` or `which = "med.depth"`, plots of either maximum or
|
|
||||||
#' median depth per tree with respect to the tree number are created.
|
|
||||||
#'
|
|
||||||
#' Finally, `which = "med.weight"` allows to see how
|
|
||||||
#' a tree's median absolute leaf weight changes through the iterations.
|
|
||||||
#'
|
|
||||||
#' These functions have been inspired by the blog post
|
|
||||||
#' <https://github.com/aysent/random-forest-leaf-visualization>.
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' The return value of the two functions is as follows:
|
|
||||||
#' - `xgb.plot.deepness()`: A "data.table" (invisibly).
|
|
||||||
#' Each row corresponds to a terminal leaf in the model. It contains its information
|
|
||||||
#' about depth, cover, and weight (used in calculating predictions).
|
|
||||||
#' If `plot = TRUE`, also a plot is shown.
|
|
||||||
#' - `xgb.ggplot.deepness()`: When `which = "2x1"`, a list of two "ggplot" objects,
|
|
||||||
#' and a single "ggplot" object otherwise.
|
|
||||||
#'
|
|
||||||
#' @seealso [xgb.train()] and [xgb.model.dt.tree()].
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#'
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' ## Keep the number of threads to 2 for examples
|
|
||||||
#' nthread <- 2
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' ## Change max_depth to a higher number to get a more significant result
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 6,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' 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 (!(inherits(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 (inherits(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 = Gain)], 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 = lengths(paths), 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", "Gain", "Cover", "Tree", "ID", "Yes", "No", "Feature", "Leaf", "Weight"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
#' Plot feature importance
|
|
||||||
#'
|
|
||||||
#' Represents previously calculated feature importance as a bar graph.
|
|
||||||
#' - `xgb.plot.importance()` uses base R graphics, while
|
|
||||||
#' - `xgb.ggplot.importance()` uses "ggplot".
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' The graph represents each feature as a horizontal bar of length proportional to the
|
|
||||||
#' importance of a feature. Features are sorted by decreasing importance.
|
|
||||||
#' It works for both "gblinear" and "gbtree" models.
|
|
||||||
#'
|
|
||||||
#' When `rel_to_first = FALSE`, the values would be plotted as in `importance_matrix`.
|
|
||||||
#' For a "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, `rel_to_first = FALSE` would show actual values of the coefficients.
|
|
||||||
#' Setting `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 performs 1-D clustering of the importance values,
|
|
||||||
#' with bar colors corresponding to different clusters having similar importance values.
|
|
||||||
#'
|
|
||||||
#' @param importance_matrix A `data.table` as returned by [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 `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 Adjust the left margin size to fit feature names.
|
|
||||||
#' When `NULL`, the existing `par("mar")` is used.
|
|
||||||
#' @param cex Passed as `cex.names` parameter to [graphics::barplot()].
|
|
||||||
#' @param plot Should the barplot be shown? Default is `TRUE`.
|
|
||||||
#' @param n_clusters A numeric vector containing the min and the max range
|
|
||||||
#' of the possible number of clusters of bars.
|
|
||||||
#' @param ... Other parameters passed to [graphics::barplot()]
|
|
||||||
#' (except `horiz`, `border`, `cex.names`, `names.arg`, and `las`).
|
|
||||||
#' Only used in `xgb.plot.importance()`.
|
|
||||||
#' @return
|
|
||||||
#' The return value depends on the function:
|
|
||||||
#' - `xgb.plot.importance()`: Invisibly, a "data.table" with `n_top` features sorted
|
|
||||||
#' by importance. If `plot = TRUE`, the values are also plotted as barplot.
|
|
||||||
#' - `xgb.ggplot.importance()`: A customizable "ggplot" object.
|
|
||||||
#' E.g., to change the title, set `+ ggtitle("A GRAPH NAME")`.
|
|
||||||
#'
|
|
||||||
#' @seealso [graphics::barplot()]
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train)
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 2 for examples
|
|
||||||
#' nthread <- 2
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 3,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' importance_matrix <- xgb.importance(colnames(agaricus.train$data), model = bst)
|
|
||||||
#' 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
|
|
||||||
#' gg + ggplot2::ylab("Frequency")
|
|
||||||
#'
|
|
||||||
#' @rdname xgb.plot.importance
|
|
||||||
#' @export
|
|
||||||
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 (!is.data.table(importance_matrix)) {
|
|
||||||
stop("importance_matrix: must be a data.table")
|
|
||||||
}
|
|
||||||
|
|
||||||
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!")
|
|
||||||
}
|
|
||||||
|
|
||||||
# also aggregate, just in case when the values were not yet summed up by feature
|
|
||||||
importance_matrix <- importance_matrix[
|
|
||||||
, lapply(.SD, sum)
|
|
||||||
, .SDcols = setdiff(names(importance_matrix), "Feature")
|
|
||||||
, by = Feature
|
|
||||||
][
|
|
||||||
, Importance := get(measure)
|
|
||||||
]
|
|
||||||
|
|
||||||
# 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) {
|
|
||||||
original_mar <- par()$mar
|
|
||||||
|
|
||||||
# reset margins so this function doesn't have side effects
|
|
||||||
on.exit({
|
|
||||||
par(mar = original_mar)
|
|
||||||
})
|
|
||||||
|
|
||||||
mar <- original_mar
|
|
||||||
if (!is.null(left_margin))
|
|
||||||
mar[2] <- left_margin
|
|
||||||
par(mar = mar)
|
|
||||||
|
|
||||||
# reverse the order of rows to have the highest ranked at the top
|
|
||||||
importance_matrix[rev(seq_len(nrow(importance_matrix))),
|
|
||||||
barplot(Importance, horiz = TRUE, border = NA, cex.names = cex,
|
|
||||||
names.arg = Feature, las = 1, ...)]
|
|
||||||
}
|
|
||||||
|
|
||||||
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", "Importance"))
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
#' Project all trees on one tree
|
|
||||||
#'
|
|
||||||
#' Visualization of the ensemble of trees as a single collective unit.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' This function tries to capture the complexity of a gradient boosted tree model
|
|
||||||
#' in a cohesive way by compressing an ensemble of trees into a single tree-graph representation.
|
|
||||||
#' The goal is to improve the interpretability of a model generally seen as black box.
|
|
||||||
#'
|
|
||||||
#' Note: this function is applicable to tree booster-based models only.
|
|
||||||
#'
|
|
||||||
#' It takes advantage of the fact that the shape of a binary tree is only defined by
|
|
||||||
#' its depth (therefore, in a boosting model, all trees have similar shape).
|
|
||||||
#'
|
|
||||||
#' Moreover, the trees tend to reuse the same features.
|
|
||||||
#'
|
|
||||||
#' The function projects each tree onto one, and keeps for each position the
|
|
||||||
#' `features_keep` first features (based on the Gain per feature measure).
|
|
||||||
#'
|
|
||||||
#' This function is inspired by this blog post:
|
|
||||||
#' <https://wellecks.wordpress.com/2015/02/21/peering-into-the-black-box-visualizing-lambdamart/>
|
|
||||||
#'
|
|
||||||
#' @inheritParams xgb.plot.tree
|
|
||||||
#' @param features_keep Number of features to keep in each position of the multi trees,
|
|
||||||
#' by default 5.
|
|
||||||
#' @inherit xgb.plot.tree return
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#'
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 2 for examples
|
|
||||||
#' nthread <- 2
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
#' max_depth = 15,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 30,
|
|
||||||
#' objective = "binary:logistic",
|
|
||||||
#' min_child_weight = 50,
|
|
||||||
#' verbose = 0
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' p <- xgb.plot.multi.trees(model = bst, features_keep = 3)
|
|
||||||
#' print(p)
|
|
||||||
#'
|
|
||||||
#' \dontrun{
|
|
||||||
#' # Below is an example of how to save this plot to a file.
|
|
||||||
#' # Note that for export_graph() to work, the {DiagrammeRsvg} and {rsvg} packages
|
|
||||||
#' # must also be installed.
|
|
||||||
#'
|
|
||||||
#' library(DiagrammeR)
|
|
||||||
#'
|
|
||||||
#' gr <- xgb.plot.multi.trees(model = bst, features_keep = 3, render = FALSE)
|
|
||||||
#' export_graph(gr, "tree.pdf", width = 1500, height = 600)
|
|
||||||
#' }
|
|
||||||
#'
|
|
||||||
#' @export
|
|
||||||
xgb.plot.multi.trees <- function(model, features_keep = 5, plot_width = NULL, plot_height = NULL,
|
|
||||||
render = TRUE, ...) {
|
|
||||||
if (!requireNamespace("DiagrammeR", quietly = TRUE)) {
|
|
||||||
stop("DiagrammeR is required for xgb.plot.multi.trees")
|
|
||||||
}
|
|
||||||
check.deprecation(...)
|
|
||||||
tree.matrix <- xgb.model.dt.tree(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[Node == 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 <- paste0(yes.row.nodes[, abs.node.position], "_0")
|
|
||||||
no.nodes.abs.pos <- paste0(no.row.nodes[, abs.node.position], "_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")]
|
|
||||||
|
|
||||||
for (nm in c("abs.node.position", "Yes", "No"))
|
|
||||||
data.table::set(tree.matrix, j = nm, value = sub("^\\d+-", "", tree.matrix[[nm]]))
|
|
||||||
|
|
||||||
nodes.dt <- tree.matrix[
|
|
||||||
, .(Gain = sum(Gain))
|
|
||||||
, by = .(abs.node.position, Feature)
|
|
||||||
][, .(Text = paste0(
|
|
||||||
paste0(
|
|
||||||
Feature[seq_len(min(length(Feature), features_keep))],
|
|
||||||
" (",
|
|
||||||
format(Gain[seq_len(min(length(Gain), features_keep))], digits = 5),
|
|
||||||
")"
|
|
||||||
),
|
|
||||||
collapse = "\n"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
, by = abs.node.position
|
|
||||||
]
|
|
||||||
|
|
||||||
edges.dt <- data.table::rbindlist(
|
|
||||||
l = list(
|
|
||||||
tree.matrix[Feature != "Leaf", .(From = abs.node.position, To = Yes)],
|
|
||||||
tree.matrix[Feature != "Leaf", .(From = abs.node.position, To = No)]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
edges.dt <- edges.dt[, .N, .(From, To)]
|
|
||||||
edges.dt[, N := NULL]
|
|
||||||
|
|
||||||
nodes <- DiagrammeR::create_node_df(
|
|
||||||
n = nrow(nodes.dt),
|
|
||||||
label = nodes.dt[, Text]
|
|
||||||
)
|
|
||||||
|
|
||||||
edges <- DiagrammeR::create_edge_df(
|
|
||||||
from = match(edges.dt[, From], nodes.dt[, abs.node.position]),
|
|
||||||
to = match(edges.dt[, To], nodes.dt[, abs.node.position]),
|
|
||||||
rel = "leading_to")
|
|
||||||
|
|
||||||
graph <- DiagrammeR::create_graph(
|
|
||||||
nodes_df = nodes,
|
|
||||||
edges_df = edges,
|
|
||||||
attr_theme = NULL
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "graph",
|
|
||||||
attr = c("layout", "rankdir"),
|
|
||||||
value = c("dot", "LR")
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "node",
|
|
||||||
attr = c("color", "fillcolor", "style", "shape", "fontname"),
|
|
||||||
value = c("DimGray", "beige", "filled", "rectangle", "Helvetica")
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "edge",
|
|
||||||
attr = c("color", "arrowsize", "arrowhead", "fontname"),
|
|
||||||
value = c("DimGray", "1.5", "vee", "Helvetica")
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!render) return(invisible(graph))
|
|
||||||
|
|
||||||
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,389 +0,0 @@
|
|||||||
#' SHAP dependence plots
|
|
||||||
#'
|
|
||||||
#' Visualizes SHAP values against feature values to gain an impression of feature effects.
|
|
||||||
#'
|
|
||||||
#' @param data The data to explain as a `matrix`, `dgCMatrix`, or `data.frame`.
|
|
||||||
#' @param shap_contrib Matrix of SHAP contributions of `data`.
|
|
||||||
#' The default (`NULL`) computes it from `model` and `data`.
|
|
||||||
#' @param features Vector of column indices or feature names to plot. When `NULL`
|
|
||||||
#' (default), the `top_n` most important features are selected by [xgb.importance()].
|
|
||||||
#' @param top_n How many of the most important features (<= 100) should be selected?
|
|
||||||
#' By default 1 for SHAP dependence and 10 for SHAP summary.
|
|
||||||
#' Only used when `features = NULL`.
|
|
||||||
#' @param model An `xgb.Booster` model. Only required when `shap_contrib = NULL` or
|
|
||||||
#' `features = NULL`.
|
|
||||||
#' @param trees Passed to [xgb.importance()] when `features = NULL`.
|
|
||||||
#' @param target_class Only relevant for multiclass models. The default (`NULL`)
|
|
||||||
#' averages the SHAP values over all classes. Pass a (0-based) class index
|
|
||||||
#' to show only SHAP values of that class.
|
|
||||||
#' @param approxcontrib Passed to `predict()` when `shap_contrib = NULL`.
|
|
||||||
#' @param subsample Fraction of data points randomly picked for plotting.
|
|
||||||
#' The default (`NULL`) will use up to 100k data points.
|
|
||||||
#' @param n_col Number of columns in a grid of plots.
|
|
||||||
#' @param col Color of the scatterplot markers.
|
|
||||||
#' @param pch Scatterplot marker.
|
|
||||||
#' @param discrete_n_uniq Maximal number of unique feature values to consider the
|
|
||||||
#' feature as discrete.
|
|
||||||
#' @param discrete_jitter Jitter amount added to the values of discrete features.
|
|
||||||
#' @param ylab The y-axis label in 1D plots.
|
|
||||||
#' @param plot_NA Should contributions of cases with missing values be plotted?
|
|
||||||
#' Default is `TRUE`.
|
|
||||||
#' @param col_NA Color of marker for missing value contributions.
|
|
||||||
#' @param pch_NA Marker type for `NA` values.
|
|
||||||
#' @param pos_NA Relative position of the x-location where `NA` values are shown:
|
|
||||||
#' `min(x) + (max(x) - min(x)) * pos_NA`.
|
|
||||||
#' @param plot_loess Should loess-smoothed curves be plotted? (Default is `TRUE`).
|
|
||||||
#' The smoothing is only done for features with more than 5 distinct values.
|
|
||||||
#' @param col_loess Color of loess curves.
|
|
||||||
#' @param span_loess The `span` parameter of [stats::loess()].
|
|
||||||
#' @param which Whether to do univariate or bivariate plotting. Currently, only "1d" is implemented.
|
|
||||||
#' @param plot Should the plot be drawn? (Default is `TRUE`).
|
|
||||||
#' If `FALSE`, only a list of matrices is returned.
|
|
||||||
#' @param ... Other parameters passed to [graphics::plot()].
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#'
|
|
||||||
#' These scatterplots represent how SHAP feature contributions depend of feature values.
|
|
||||||
#' The similarity to partial dependence plots is that they also give an idea for how feature values
|
|
||||||
#' affect predictions. However, in partial dependence plots, we see marginal dependencies
|
|
||||||
#' of model prediction on feature value, while SHAP dependence plots display the estimated
|
|
||||||
#' contributions of a feature to the prediction for each individual case.
|
|
||||||
#'
|
|
||||||
#' When `plot_loess = TRUE`, feature values are rounded to three significant digits and
|
|
||||||
#' weighted LOESS is computed and plotted, where the weights are the numbers of data points
|
|
||||||
#' at each rounded value.
|
|
||||||
#'
|
|
||||||
#' Note: SHAP contributions are on the scale of the model margin.
|
|
||||||
#' E.g., for a logistic binomial objective, the margin is on log-odds scale.
|
|
||||||
#' Also, since SHAP stands for "SHapley Additive exPlanation" (model prediction = sum of SHAP
|
|
||||||
#' contributions for all features + bias), depending on the objective used, transforming SHAP
|
|
||||||
#' contributions for a feature from the marginal to the prediction space is not necessarily
|
|
||||||
#' a meaningful thing to do.
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' In addition to producing plots (when `plot = TRUE`), it silently returns a list of two matrices:
|
|
||||||
#' - `data`: Feature value matrix.
|
|
||||||
#' - `shap_contrib`: Corresponding SHAP value matrix.
|
|
||||||
#'
|
|
||||||
#' @references
|
|
||||||
#' 1. Scott M. Lundberg, Su-In Lee, "A Unified Approach to Interpreting Model Predictions",
|
|
||||||
#' NIPS Proceedings 2017, <https://arxiv.org/abs/1705.07874>
|
|
||||||
#' 2. Scott M. Lundberg, Su-In Lee, "Consistent feature attribution for tree ensembles",
|
|
||||||
#' <https://arxiv.org/abs/1706.06060>
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#'
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#' nrounds <- 20
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, agaricus.train$label),
|
|
||||||
#' nrounds = nrounds,
|
|
||||||
#' eta = 0.1,
|
|
||||||
#' max_depth = 3,
|
|
||||||
#' subsample = 0.5,
|
|
||||||
#' objective = "binary:logistic",
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' verbose = 0
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.plot.shap(agaricus.test$data, model = bst, features = "odor=none")
|
|
||||||
#'
|
|
||||||
#' contr <- predict(bst, agaricus.test$data, predcontrib = TRUE)
|
|
||||||
#' xgb.plot.shap(agaricus.test$data, contr, model = bst, top_n = 12, n_col = 3)
|
|
||||||
#'
|
|
||||||
#' # Summary plot
|
|
||||||
#' xgb.ggplot.shap.summary(agaricus.test$data, contr, model = bst, top_n = 12)
|
|
||||||
#'
|
|
||||||
#' # Multiclass example - plots for each class separately:
|
|
||||||
#' nclass <- 3
|
|
||||||
#' x <- as.matrix(iris[, -5])
|
|
||||||
#' set.seed(123)
|
|
||||||
#' is.na(x[sample(nrow(x) * 4, 30)]) <- TRUE # introduce some missing values
|
|
||||||
#'
|
|
||||||
#' mbst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(x, label = as.numeric(iris$Species) - 1),
|
|
||||||
#' nrounds = nrounds,
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 0.3,
|
|
||||||
#' subsample = 0.5,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' objective = "multi:softprob",
|
|
||||||
#' num_class = nclass,
|
|
||||||
#' verbose = 0
|
|
||||||
#' )
|
|
||||||
#' trees0 <- seq(from = 0, by = nclass, length.out = nrounds)
|
|
||||||
#' col <- rgb(0, 0, 1, 0.5)
|
|
||||||
#'
|
|
||||||
#' xgb.plot.shap(
|
|
||||||
#' x,
|
|
||||||
#' model = mbst,
|
|
||||||
#' trees = trees0,
|
|
||||||
#' target_class = 0,
|
|
||||||
#' top_n = 4,
|
|
||||||
#' n_col = 2,
|
|
||||||
#' col = col,
|
|
||||||
#' pch = 16,
|
|
||||||
#' pch_NA = 17
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.plot.shap(
|
|
||||||
#' x,
|
|
||||||
#' model = mbst,
|
|
||||||
#' trees = trees0 + 1,
|
|
||||||
#' target_class = 1,
|
|
||||||
#' top_n = 4,
|
|
||||||
#' n_col = 2,
|
|
||||||
#' col = col,
|
|
||||||
#' pch = 16,
|
|
||||||
#' pch_NA = 17
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' xgb.plot.shap(
|
|
||||||
#' x,
|
|
||||||
#' model = mbst,
|
|
||||||
#' trees = trees0 + 2,
|
|
||||||
#' target_class = 2,
|
|
||||||
#' top_n = 4,
|
|
||||||
#' n_col = 2,
|
|
||||||
#' col = col,
|
|
||||||
#' pch = 16,
|
|
||||||
#' pch_NA = 17
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # Summary plot
|
|
||||||
#' xgb.ggplot.shap.summary(x, model = mbst, target_class = 0, top_n = 4)
|
|
||||||
#'
|
|
||||||
#' @rdname xgb.plot.shap
|
|
||||||
#' @export
|
|
||||||
xgb.plot.shap <- function(data, shap_contrib = NULL, features = NULL, top_n = 1, model = NULL,
|
|
||||||
trees = NULL, target_class = NULL, approxcontrib = FALSE,
|
|
||||||
subsample = NULL, n_col = 1, col = rgb(0, 0, 1, 0.2), pch = '.',
|
|
||||||
discrete_n_uniq = 5, discrete_jitter = 0.01, ylab = "SHAP",
|
|
||||||
plot_NA = TRUE, col_NA = rgb(0.7, 0, 1, 0.6), pch_NA = '.', pos_NA = 1.07,
|
|
||||||
plot_loess = TRUE, col_loess = 2, span_loess = 0.5,
|
|
||||||
which = c("1d", "2d"), plot = TRUE, ...) {
|
|
||||||
data_list <- xgb.shap.data(
|
|
||||||
data = data,
|
|
||||||
shap_contrib = shap_contrib,
|
|
||||||
features = features,
|
|
||||||
top_n = top_n,
|
|
||||||
model = model,
|
|
||||||
trees = trees,
|
|
||||||
target_class = target_class,
|
|
||||||
approxcontrib = approxcontrib,
|
|
||||||
subsample = subsample,
|
|
||||||
max_observations = 100000
|
|
||||||
)
|
|
||||||
data <- data_list[["data"]]
|
|
||||||
shap_contrib <- data_list[["shap_contrib"]]
|
|
||||||
features <- colnames(data)
|
|
||||||
|
|
||||||
which <- match.arg(which)
|
|
||||||
if (which == "2d")
|
|
||||||
stop("2D plots are not implemented yet")
|
|
||||||
|
|
||||||
if (n_col > length(features)) n_col <- length(features)
|
|
||||||
if (plot && which == "1d") {
|
|
||||||
op <- par(mfrow = c(ceiling(length(features) / n_col), n_col),
|
|
||||||
oma = c(0, 0, 0, 0) + 0.2,
|
|
||||||
mar = c(3.5, 3.5, 0, 0) + 0.1,
|
|
||||||
mgp = c(1.7, 0.6, 0))
|
|
||||||
for (f in features) {
|
|
||||||
ord <- order(data[, f])
|
|
||||||
x <- data[, f][ord]
|
|
||||||
y <- shap_contrib[, f][ord]
|
|
||||||
x_lim <- range(x, na.rm = TRUE)
|
|
||||||
y_lim <- range(y, na.rm = TRUE)
|
|
||||||
do_na <- plot_NA && anyNA(x)
|
|
||||||
if (do_na) {
|
|
||||||
x_range <- diff(x_lim)
|
|
||||||
loc_na <- min(x, na.rm = TRUE) + x_range * pos_NA
|
|
||||||
x_lim <- range(c(x_lim, loc_na))
|
|
||||||
}
|
|
||||||
x_uniq <- unique(x)
|
|
||||||
x2plot <- x
|
|
||||||
# add small jitter for discrete features with <= 5 distinct values
|
|
||||||
if (length(x_uniq) <= discrete_n_uniq)
|
|
||||||
x2plot <- jitter(x, amount = discrete_jitter * min(diff(x_uniq), na.rm = TRUE))
|
|
||||||
plot(x2plot, y, pch = pch, xlab = f, col = col, xlim = x_lim, ylim = y_lim, ylab = ylab, ...)
|
|
||||||
grid()
|
|
||||||
if (plot_loess) {
|
|
||||||
# compress x to 3 digits, and mean-aggregate y
|
|
||||||
zz <- data.table(x = signif(x, 3), y)[, .(.N, y = mean(y)), x]
|
|
||||||
if (nrow(zz) <= 5) {
|
|
||||||
lines(zz$x, zz$y, col = col_loess)
|
|
||||||
} else {
|
|
||||||
lo <- stats::loess(y ~ x, data = zz, weights = zz$N, span = span_loess)
|
|
||||||
zz$y_lo <- predict(lo, zz, type = "link")
|
|
||||||
lines(zz$x, zz$y_lo, col = col_loess)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (do_na) {
|
|
||||||
i_na <- which(is.na(x))
|
|
||||||
x_na <- rep(loc_na, length(i_na))
|
|
||||||
x_na <- jitter(x_na, amount = x_range * 0.01)
|
|
||||||
points(x_na, y[i_na], pch = pch_NA, col = col_NA)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
par(op)
|
|
||||||
}
|
|
||||||
if (plot && which == "2d") {
|
|
||||||
# TODO
|
|
||||||
warning("Bivariate plotting is currently not available.")
|
|
||||||
}
|
|
||||||
invisible(list(data = data, shap_contrib = shap_contrib))
|
|
||||||
}
|
|
||||||
|
|
||||||
#' SHAP summary plot
|
|
||||||
#'
|
|
||||||
#' Visualizes SHAP contributions of different features.
|
|
||||||
#'
|
|
||||||
#' A point plot (each point representing one observation from `data`) is
|
|
||||||
#' produced for each feature, with the points plotted on the SHAP value axis.
|
|
||||||
#' Each point (observation) is coloured based on its feature value.
|
|
||||||
#'
|
|
||||||
#' The plot allows to see which features have a negative / positive contribution
|
|
||||||
#' on the model prediction, and whether the contribution is different for larger
|
|
||||||
#' or smaller values of the feature. Inspired by the summary plot of
|
|
||||||
#' <https://github.com/shap/shap>.
|
|
||||||
#'
|
|
||||||
#' @inheritParams xgb.plot.shap
|
|
||||||
#'
|
|
||||||
#' @return A `ggplot2` object.
|
|
||||||
#' @export
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' # See examples in xgb.plot.shap()
|
|
||||||
#'
|
|
||||||
#' @seealso [xgb.plot.shap()], [xgb.ggplot.shap.summary()],
|
|
||||||
#' and the Python library <https://github.com/shap/shap>.
|
|
||||||
xgb.plot.shap.summary <- function(data, shap_contrib = NULL, features = NULL, top_n = 10, model = NULL,
|
|
||||||
trees = NULL, target_class = NULL, approxcontrib = FALSE, subsample = NULL) {
|
|
||||||
# Only ggplot implementation is available.
|
|
||||||
xgb.ggplot.shap.summary(data, shap_contrib, features, top_n, model, trees, target_class, approxcontrib, subsample)
|
|
||||||
}
|
|
||||||
|
|
||||||
#' Prepare data for SHAP plots
|
|
||||||
#'
|
|
||||||
#' Internal function used in [xgb.plot.shap()], [xgb.plot.shap.summary()], etc.
|
|
||||||
#'
|
|
||||||
#' @inheritParams xgb.plot.shap
|
|
||||||
#' @param max_observations Maximum number of observations to consider.
|
|
||||||
#' @keywords internal
|
|
||||||
#' @noRd
|
|
||||||
#'
|
|
||||||
#' @return
|
|
||||||
#' A list containing:
|
|
||||||
#' - `data`: The matrix of feature values.
|
|
||||||
#' - `shap_contrib`: The matrix with corresponding SHAP values.
|
|
||||||
xgb.shap.data <- function(data, shap_contrib = NULL, features = NULL, top_n = 1, model = NULL,
|
|
||||||
trees = NULL, target_class = NULL, approxcontrib = FALSE,
|
|
||||||
subsample = NULL, max_observations = 100000) {
|
|
||||||
if (!inherits(data, c("matrix", "dsparseMatrix", "data.frame")))
|
|
||||||
stop("data: must be matrix, sparse matrix, or data.frame.")
|
|
||||||
if (inherits(data, "data.frame") && length(class(data)) > 1L) {
|
|
||||||
data <- as.data.frame(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is.null(shap_contrib) && (is.null(model) || !inherits(model, "xgb.Booster")))
|
|
||||||
stop("when shap_contrib is not provided, one must provide an xgb.Booster model")
|
|
||||||
|
|
||||||
if (is.null(features) && (is.null(model) || !inherits(model, "xgb.Booster")))
|
|
||||||
stop("when features are not provided, one must provide an xgb.Booster model to rank the features")
|
|
||||||
|
|
||||||
last_dim <- function(v) dim(v)[length(dim(v))]
|
|
||||||
|
|
||||||
if (!is.null(shap_contrib) &&
|
|
||||||
(!is.array(shap_contrib) || nrow(shap_contrib) != nrow(data) || last_dim(shap_contrib) != ncol(data) + 1))
|
|
||||||
stop("shap_contrib is not compatible with the provided data")
|
|
||||||
|
|
||||||
if (is.character(features) && is.null(colnames(data)))
|
|
||||||
stop("either provide `data` with column names or provide `features` as column indices")
|
|
||||||
|
|
||||||
model_feature_names <- NULL
|
|
||||||
if (is.null(features) && !is.null(model)) {
|
|
||||||
model_feature_names <- xgb.feature_names(model)
|
|
||||||
}
|
|
||||||
if (is.null(model_feature_names) && xgb.num_feature(model) != ncol(data))
|
|
||||||
stop("if model has no feature_names, columns in `data` must match features in model")
|
|
||||||
|
|
||||||
if (!is.null(subsample)) {
|
|
||||||
if (subsample <= 0 || subsample >= 1) {
|
|
||||||
stop("'subsample' must be a number between zero and one (non-inclusive).")
|
|
||||||
}
|
|
||||||
sample_size <- as.integer(subsample * nrow(data))
|
|
||||||
if (sample_size < 2) {
|
|
||||||
stop("Sampling fraction involves less than 2 rows.")
|
|
||||||
}
|
|
||||||
idx <- sample(x = seq_len(nrow(data)), size = sample_size, replace = FALSE)
|
|
||||||
} else {
|
|
||||||
idx <- seq_len(min(nrow(data), max_observations))
|
|
||||||
}
|
|
||||||
data <- data[idx, ]
|
|
||||||
if (is.null(colnames(data))) {
|
|
||||||
colnames(data) <- paste0("X", seq_len(ncol(data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
reshape_3d_shap_contrib <- function(shap_contrib, target_class) {
|
|
||||||
# multiclass: either choose a class or merge
|
|
||||||
if (is.list(shap_contrib)) {
|
|
||||||
if (!is.null(target_class)) {
|
|
||||||
shap_contrib <- shap_contrib[[target_class + 1]]
|
|
||||||
} else {
|
|
||||||
shap_contrib <- Reduce("+", lapply(shap_contrib, abs))
|
|
||||||
}
|
|
||||||
} else if (length(dim(shap_contrib)) > 2) {
|
|
||||||
if (!is.null(target_class)) {
|
|
||||||
orig_shape <- dim(shap_contrib)
|
|
||||||
shap_contrib <- shap_contrib[, target_class + 1, , drop = TRUE]
|
|
||||||
if (!is.matrix(shap_contrib)) {
|
|
||||||
shap_contrib <- matrix(shap_contrib, orig_shape[c(1L, 3L)])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shap_contrib <- apply(abs(shap_contrib), c(1L, 3L), sum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(shap_contrib)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is.null(shap_contrib)) {
|
|
||||||
shap_contrib <- predict(
|
|
||||||
model,
|
|
||||||
newdata = data,
|
|
||||||
predcontrib = TRUE,
|
|
||||||
approxcontrib = approxcontrib
|
|
||||||
)
|
|
||||||
}
|
|
||||||
shap_contrib <- reshape_3d_shap_contrib(shap_contrib, target_class)
|
|
||||||
if (is.null(colnames(shap_contrib))) {
|
|
||||||
colnames(shap_contrib) <- paste0("X", seq_len(ncol(data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is.null(features)) {
|
|
||||||
if (!is.null(model_feature_names)) {
|
|
||||||
imp <- xgb.importance(model = model, trees = trees)
|
|
||||||
} else {
|
|
||||||
imp <- xgb.importance(model = model, trees = trees, feature_names = colnames(data))
|
|
||||||
}
|
|
||||||
top_n <- top_n[1]
|
|
||||||
if (top_n < 1 || top_n > 100) stop("top_n: must be an integer within [1, 100]")
|
|
||||||
features <- imp$Feature[seq_len(min(top_n, NROW(imp)))]
|
|
||||||
}
|
|
||||||
if (is.character(features)) {
|
|
||||||
features <- match(features, colnames(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
shap_contrib <- shap_contrib[, features, drop = FALSE]
|
|
||||||
data <- data[, features, drop = FALSE]
|
|
||||||
|
|
||||||
list(
|
|
||||||
data = data,
|
|
||||||
shap_contrib = shap_contrib
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
#' Plot boosted trees
|
|
||||||
#'
|
|
||||||
#' Read a tree model text dump and plot the model.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' When using `style="xgboost"`, the content of each node is visualized as follows:
|
|
||||||
#' - For non-terminal nodes, it will display the split condition (number or name if
|
|
||||||
#' available, and the condition that would decide to which node to go next).
|
|
||||||
#' - Those nodes will be connected to their children by arrows that indicate whether the
|
|
||||||
#' branch corresponds to the condition being met or not being met.
|
|
||||||
#' - Terminal (leaf) nodes contain the margin to add when ending there.
|
|
||||||
#'
|
|
||||||
#' When using `style="R"`, the content of each node is visualized like this:
|
|
||||||
#' - *Feature name*.
|
|
||||||
#' - *Cover:* The sum of second order gradients of training data.
|
|
||||||
#' For the squared loss, this simply corresponds to the number of instances in the node.
|
|
||||||
#' The deeper in the tree, the lower the value.
|
|
||||||
#' - *Gain* (for split nodes): Information gain metric of a split
|
|
||||||
#' (corresponds to the importance of the node in the model).
|
|
||||||
#' - *Value* (for leaves): Margin value that the leaf may contribute to the prediction.
|
|
||||||
#'
|
|
||||||
#' The tree root nodes also indicate the tree index (0-based).
|
|
||||||
#'
|
|
||||||
#' The "Yes" branches are marked by the "< split_value" label.
|
|
||||||
#' The branches also used for missing values are marked as bold
|
|
||||||
#' (as in "carrying extra capacity").
|
|
||||||
#'
|
|
||||||
#' This function uses [GraphViz](https://www.graphviz.org/) as DiagrammeR backend.
|
|
||||||
#'
|
|
||||||
#' @param model Object of class `xgb.Booster`. If it contains feature names (they can be set through
|
|
||||||
#' [setinfo()], they will be used in the output from this function.
|
|
||||||
#' @param trees An integer vector of tree indices that should be used.
|
|
||||||
#' The default (`NULL`) uses all trees.
|
|
||||||
#' Useful, e.g., in multiclass classification to get only
|
|
||||||
#' the trees of one class. *Important*: the tree index in XGBoost models
|
|
||||||
#' is zero-based (e.g., use `trees = 0:2` for the first three trees).
|
|
||||||
#' @param plot_width,plot_height Width and height of the graph in pixels.
|
|
||||||
#' The values are passed to `DiagrammeR::render_graph()`.
|
|
||||||
#' @param render Should the graph be rendered or not? The default is `TRUE`.
|
|
||||||
#' @param show_node_id a logical flag for whether to show node id's in the graph.
|
|
||||||
#' @param style Style to use for the plot:
|
|
||||||
#' - `"xgboost"`: will use the plot style defined in the core XGBoost library,
|
|
||||||
#' which is shared between different interfaces through the 'dot' format. This
|
|
||||||
#' style was not available before version 2.1.0 in R. It always plots the trees
|
|
||||||
#' vertically (from top to bottom).
|
|
||||||
#' - `"R"`: will use the style defined from XGBoost's R interface, which predates
|
|
||||||
#' the introducition of the standardized style from the core library. It might plot
|
|
||||||
#' the trees horizontally (from left to right).
|
|
||||||
#'
|
|
||||||
#' Note that `style="xgboost"` is only supported when all of the following conditions are met:
|
|
||||||
#' - Only a single tree is being plotted.
|
|
||||||
#' - Node IDs are not added to the graph.
|
|
||||||
#' - The graph is being returned as `htmlwidget` (`render=TRUE`).
|
|
||||||
#' @param ... Currently not used.
|
|
||||||
#' @return
|
|
||||||
#' The value depends on the `render` parameter:
|
|
||||||
#' - If `render = TRUE` (default): Rendered graph object which is an htmlwidget of
|
|
||||||
#' class `grViz`. Similar to "ggplot" objects, it needs to be printed when not
|
|
||||||
#' running from the command line.
|
|
||||||
#' - If `render = FALSE`: Graph object which is of DiagrammeR's class `dgr_graph`.
|
|
||||||
#' This could be useful if one wants to modify some of the graph attributes
|
|
||||||
#' before rendering the graph with `DiagrammeR::render_graph()`.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(agaricus.train$data, agaricus.train$label),
|
|
||||||
#' max_depth = 3,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = 2,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # plot the first tree, using the style from xgboost's core library
|
|
||||||
#' # (this plot should look identical to the ones generated from other
|
|
||||||
#' # interfaces like the python package for xgboost)
|
|
||||||
#' xgb.plot.tree(model = bst, trees = 1, style = "xgboost")
|
|
||||||
#'
|
|
||||||
#' # plot all the trees
|
|
||||||
#' xgb.plot.tree(model = bst, trees = NULL)
|
|
||||||
#'
|
|
||||||
#' # plot only the first tree and display the node ID:
|
|
||||||
#' xgb.plot.tree(model = bst, trees = 0, show_node_id = TRUE)
|
|
||||||
#'
|
|
||||||
#' \dontrun{
|
|
||||||
#' # Below is an example of how to save this plot to a file.
|
|
||||||
#' # Note that for export_graph() to work, the {DiagrammeRsvg}
|
|
||||||
#' # and {rsvg} packages must also be installed.
|
|
||||||
#'
|
|
||||||
#' library(DiagrammeR)
|
|
||||||
#'
|
|
||||||
#' gr <- xgb.plot.tree(model = bst, trees = 0:1, render = FALSE)
|
|
||||||
#' export_graph(gr, "tree.pdf", width = 1500, height = 1900)
|
|
||||||
#' export_graph(gr, "tree.png", width = 1500, height = 1900)
|
|
||||||
#' }
|
|
||||||
#'
|
|
||||||
#' @export
|
|
||||||
xgb.plot.tree <- function(model = NULL, trees = NULL, plot_width = NULL, plot_height = NULL,
|
|
||||||
render = TRUE, show_node_id = FALSE, style = c("R", "xgboost"), ...) {
|
|
||||||
check.deprecation(...)
|
|
||||||
if (!inherits(model, "xgb.Booster")) {
|
|
||||||
stop("model: Has to be an object of class xgb.Booster")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requireNamespace("DiagrammeR", quietly = TRUE)) {
|
|
||||||
stop("DiagrammeR package is required for xgb.plot.tree", call. = FALSE)
|
|
||||||
}
|
|
||||||
|
|
||||||
style <- as.character(head(style, 1L))
|
|
||||||
stopifnot(style %in% c("R", "xgboost"))
|
|
||||||
if (style == "xgboost") {
|
|
||||||
if (NROW(trees) != 1L || !render || show_node_id) {
|
|
||||||
stop("style='xgboost' is only supported for single, rendered tree, without node IDs.")
|
|
||||||
}
|
|
||||||
|
|
||||||
txt <- xgb.dump(model, dump_format = "dot")
|
|
||||||
return(DiagrammeR::grViz(txt[[trees + 1]], width = plot_width, height = plot_height))
|
|
||||||
}
|
|
||||||
|
|
||||||
dt <- xgb.model.dt.tree(model = model, trees = trees)
|
|
||||||
|
|
||||||
dt[, label := paste0(Feature, "\nCover: ", Cover, ifelse(Feature == "Leaf", "\nValue: ", "\nGain: "), Gain)]
|
|
||||||
if (show_node_id)
|
|
||||||
dt[, label := paste0(ID, ": ", label)]
|
|
||||||
dt[Node == 0, label := paste0("Tree ", Tree, "\n", label)]
|
|
||||||
dt[, shape := "rectangle"][Feature == "Leaf", shape := "oval"]
|
|
||||||
dt[, filledcolor := "Beige"][Feature == "Leaf", filledcolor := "Khaki"]
|
|
||||||
# in order to draw the first tree on top:
|
|
||||||
dt <- dt[order(-Tree)]
|
|
||||||
|
|
||||||
nodes <- DiagrammeR::create_node_df(
|
|
||||||
n = nrow(dt),
|
|
||||||
ID = dt$ID,
|
|
||||||
label = dt$label,
|
|
||||||
fillcolor = dt$filledcolor,
|
|
||||||
shape = dt$shape,
|
|
||||||
data = dt$Feature,
|
|
||||||
fontcolor = "black")
|
|
||||||
|
|
||||||
if (nrow(dt[Feature != "Leaf"]) != 0) {
|
|
||||||
edges <- DiagrammeR::create_edge_df(
|
|
||||||
from = match(rep(dt[Feature != "Leaf", c(ID)], 2), dt$ID),
|
|
||||||
to = match(dt[Feature != "Leaf", c(Yes, No)], dt$ID),
|
|
||||||
label = c(
|
|
||||||
dt[Feature != "Leaf", paste("<", Split)],
|
|
||||||
rep("", nrow(dt[Feature != "Leaf"]))
|
|
||||||
),
|
|
||||||
style = c(
|
|
||||||
dt[Feature != "Leaf", ifelse(Missing == Yes, "bold", "solid")],
|
|
||||||
dt[Feature != "Leaf", ifelse(Missing == No, "bold", "solid")]
|
|
||||||
),
|
|
||||||
rel = "leading_to")
|
|
||||||
} else {
|
|
||||||
edges <- NULL
|
|
||||||
}
|
|
||||||
|
|
||||||
graph <- DiagrammeR::create_graph(
|
|
||||||
nodes_df = nodes,
|
|
||||||
edges_df = edges,
|
|
||||||
attr_theme = NULL
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "graph",
|
|
||||||
attr = c("layout", "rankdir"),
|
|
||||||
value = c("dot", "LR")
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "node",
|
|
||||||
attr = c("color", "style", "fontname"),
|
|
||||||
value = c("DimGray", "filled", "Helvetica")
|
|
||||||
)
|
|
||||||
graph <- DiagrammeR::add_global_graph_attrs(
|
|
||||||
graph = graph,
|
|
||||||
attr_type = "edge",
|
|
||||||
attr = c("color", "arrowsize", "arrowhead", "fontname"),
|
|
||||||
value = c("DimGray", "1.5", "vee", "Helvetica")
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!render) return(invisible(graph))
|
|
||||||
|
|
||||||
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", "ID", "Cover", "Gain", "Split", "Yes", "No", "Missing", ".", "shape", "filledcolor", "label"))
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#' Save XGBoost model to binary file
|
|
||||||
#'
|
|
||||||
#' Save XGBoost model to a file in binary or JSON format.
|
|
||||||
#'
|
|
||||||
#' @param model Model object of `xgb.Booster` class.
|
|
||||||
#' @param fname Name of the file to write. Its extension determines the serialization format:
|
|
||||||
#' - ".ubj": Use the universal binary JSON format (recommended).
|
|
||||||
#' This format uses binary types for e.g. floating point numbers, thereby preventing any loss
|
|
||||||
#' of precision when converting to a human-readable JSON text or similar.
|
|
||||||
#' - ".json": Use plain JSON, which is a human-readable format.
|
|
||||||
#' - ".deprecated": Use **deprecated** binary format. This format will
|
|
||||||
#' not be able to save attributes introduced after v1 of XGBoost, such as the "best_iteration"
|
|
||||||
#' attribute that boosters might keep, nor feature names or user-specifiec attributes.
|
|
||||||
#' - If the format is not specified by passing one of the file extensions above, will
|
|
||||||
#' default to UBJ.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#'
|
|
||||||
#' This methods allows to save a model in an XGBoost-internal binary or text format which is universal
|
|
||||||
#' among the various xgboost interfaces. In R, the saved model file could be read later
|
|
||||||
#' using either the [xgb.load()] function or the `xgb_model` parameter of [xgb.train()].
|
|
||||||
#'
|
|
||||||
#' Note: a model can also be saved as an R object (e.g., by using [readRDS()]
|
|
||||||
#' or [save()]). However, it would then only be compatible with R, and
|
|
||||||
#' corresponding R methods would need to be used to load it. Moreover, persisting the model with
|
|
||||||
#' [readRDS()] or [save()] might cause compatibility problems in
|
|
||||||
#' future versions of XGBoost. Consult [a-compatibility-note-for-saveRDS-save] to learn
|
|
||||||
#' how to persist models in a future-proof way, i.e., to make the model accessible in future
|
|
||||||
#' releases of XGBoost.
|
|
||||||
#'
|
|
||||||
#' @seealso [xgb.load()]
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' \dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' train <- agaricus.train
|
|
||||||
#' test <- agaricus.test
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' fname <- file.path(tempdir(), "xgb.ubj")
|
|
||||||
#' xgb.save(bst, fname)
|
|
||||||
#' bst <- xgb.load(fname)
|
|
||||||
#' @export
|
|
||||||
xgb.save <- function(model, fname) {
|
|
||||||
if (typeof(fname) != "character")
|
|
||||||
stop("fname must be character")
|
|
||||||
if (!inherits(model, "xgb.Booster")) {
|
|
||||||
stop("model must be xgb.Booster.",
|
|
||||||
if (inherits(model, "xgb.DMatrix")) " Use xgb.DMatrix.save to save an xgb.DMatrix object." else "")
|
|
||||||
}
|
|
||||||
fname <- path.expand(fname)
|
|
||||||
.Call(XGBoosterSaveModel_R, xgb.get.handle(model), enc2utf8(fname[1]))
|
|
||||||
return(TRUE)
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#' Save XGBoost model to R's raw vector
|
|
||||||
#'
|
|
||||||
#' Save XGBoost model from [xgboost()] or [xgb.train()].
|
|
||||||
#' Call [xgb.load.raw()] to load the model back from raw vector.
|
|
||||||
#'
|
|
||||||
#' @param model The model object.
|
|
||||||
#' @param raw_format The format for encoding the booster:
|
|
||||||
#' - "json": Encode the booster into JSON text document.
|
|
||||||
#' - "ubj": Encode the booster into Universal Binary JSON.
|
|
||||||
#' - "deprecated": Encode the booster into old customized binary format.
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' \dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' train <- agaricus.train
|
|
||||||
#' test <- agaricus.test
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' objective = "binary:logistic"
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' raw <- xgb.save.raw(bst)
|
|
||||||
#' bst <- xgb.load.raw(raw)
|
|
||||||
#'
|
|
||||||
#' @export
|
|
||||||
xgb.save.raw <- function(model, raw_format = "ubj") {
|
|
||||||
handle <- xgb.get.handle(model)
|
|
||||||
args <- list(format = raw_format)
|
|
||||||
.Call(XGBoosterSaveModelToRaw_R, handle, jsonlite::toJSON(args, auto_unbox = TRUE))
|
|
||||||
}
|
|
||||||
@@ -1,514 +0,0 @@
|
|||||||
#' eXtreme Gradient Boosting Training
|
|
||||||
#'
|
|
||||||
#' `xgb.train()` is an advanced interface for training an xgboost model.
|
|
||||||
#' The [xgboost()] function is a simpler wrapper for `xgb.train()`.
|
|
||||||
#'
|
|
||||||
#' @param params the list of parameters. The complete list of parameters is
|
|
||||||
#' available in the [online documentation](http://xgboost.readthedocs.io/en/latest/parameter.html).
|
|
||||||
#' Below is a shorter summary:
|
|
||||||
#'
|
|
||||||
#' **1. General Parameters**
|
|
||||||
#'
|
|
||||||
#' - `booster`: Which booster to use, can be `gbtree` or `gblinear`. Default: `gbtree`.
|
|
||||||
#'
|
|
||||||
#' **2. Booster Parameters**
|
|
||||||
#'
|
|
||||||
#' **2.1. Parameters for Tree Booster**
|
|
||||||
#' - `eta`: The learning rate: scale the contribution of each tree by a factor of `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 `eta` implies larger value for `nrounds`: low `eta` value means model
|
|
||||||
#' more robust to overfitting but slower to compute. Default: 0.3.
|
|
||||||
#' - `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.
|
|
||||||
#' - `max_depth`: Maximum depth of a tree. Default: 6.
|
|
||||||
#' - `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.
|
|
||||||
#' - `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 `eta` and increase `nrounds`. Default: 1.
|
|
||||||
#' - `colsample_bytree`: Subsample ratio of columns when constructing each tree. Default: 1.
|
|
||||||
#' - `lambda`: L2 regularization term on weights. Default: 1.
|
|
||||||
#' - `alpha`: L1 regularization term on weights. (there is no L1 reg on bias because it is not important). Default: 0.
|
|
||||||
#' - `num_parallel_tree`: Experimental parameter. number of trees to grow per round.
|
|
||||||
#' Useful to test Random Forest through XGBoost.
|
|
||||||
#' (set `colsample_bytree < 1`, `subsample < 1` and `round = 1`) accordingly.
|
|
||||||
#' Default: 1.
|
|
||||||
#' - `monotone_constraints`: A numerical vector consists of `1`, `0` and `-1` with its length
|
|
||||||
#' equals to the number of features in the training data.
|
|
||||||
#' `1` is increasing, `-1` is decreasing and `0` is no constraint.
|
|
||||||
#' - `interaction_constraints`: A list of vectors specifying feature indices of permitted interactions.
|
|
||||||
#' Each item of the list represents one permitted interaction where specified features are allowed to interact with each other.
|
|
||||||
#' Feature index values should start from `0` (`0` references the first column).
|
|
||||||
#' Leave argument unspecified for no interaction constraints.
|
|
||||||
#'
|
|
||||||
#' **2.2. Parameters for Linear Booster**
|
|
||||||
#'
|
|
||||||
#' - `lambda`: L2 regularization term on weights. Default: 0.
|
|
||||||
#' - `lambda_bias`: L2 regularization term on bias. Default: 0.
|
|
||||||
#' - `alpha`: L1 regularization term on weights. (there is no L1 reg on bias because it is not important). Default: 0.
|
|
||||||
#'
|
|
||||||
#' **3. Task Parameters**
|
|
||||||
#'
|
|
||||||
#' - `objective`: Specifies the learning task and the corresponding learning objective.
|
|
||||||
#' users can pass a self-defined function to it. The default objective options are below:
|
|
||||||
#' - `reg:squarederror`: Regression with squared loss (default).
|
|
||||||
#' - `reg:squaredlogerror`: Regression with squared log loss \eqn{1/2 \cdot (\log(pred + 1) - \log(label + 1))^2}.
|
|
||||||
#' All inputs are required to be greater than -1.
|
|
||||||
#' Also, see metric rmsle for possible issue with this objective.
|
|
||||||
#' - `reg:logistic`: Logistic regression.
|
|
||||||
#' - `reg:pseudohubererror`: Regression with Pseudo Huber loss, a twice differentiable alternative to absolute loss.
|
|
||||||
#' - `binary:logistic`: Logistic regression for binary classification. Output probability.
|
|
||||||
#' - `binary:logitraw`: Logistic regression for binary classification, output score before logistic transformation.
|
|
||||||
#' - `binary:hinge`: Hinge loss for binary classification. This makes predictions of 0 or 1, rather than producing probabilities.
|
|
||||||
#' - `count:poisson`: Poisson regression for count data, output mean of Poisson distribution.
|
|
||||||
#' The parameter `max_delta_step` is set to 0.7 by default in poisson regression
|
|
||||||
#' (used to safeguard optimization).
|
|
||||||
#' - `survival:cox`: Cox regression for right censored survival time data (negative values are considered right censored).
|
|
||||||
#' Note that predictions are returned on the hazard ratio scale (i.e., as HR = exp(marginal_prediction) in the proportional
|
|
||||||
#' hazard function \eqn{h(t) = h_0(t) \cdot HR}.
|
|
||||||
#' - `survival:aft`: Accelerated failure time model for censored survival time data. See
|
|
||||||
#' [Survival Analysis with Accelerated Failure Time](https://xgboost.readthedocs.io/en/latest/tutorials/aft_survival_analysis.html)
|
|
||||||
#' for details.
|
|
||||||
#' The parameter `aft_loss_distribution` specifies the Probability Density Function
|
|
||||||
#' used by `survival:aft` and the `aft-nloglik` metric.
|
|
||||||
#' - `multi:softmax`: Set xgboost to do multiclass classification using the softmax objective.
|
|
||||||
#' Class is represented by a number and should be from 0 to `num_class - 1`.
|
|
||||||
#' - `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.
|
|
||||||
#' - `rank:pairwise`: Set XGBoost to do ranking task by minimizing the pairwise loss.
|
|
||||||
#' - `rank:ndcg`: Use LambdaMART to perform list-wise ranking where
|
|
||||||
#' [Normalized Discounted Cumulative Gain (NDCG)](https://en.wikipedia.org/wiki/Discounted_cumulative_gain) is maximized.
|
|
||||||
#' - `rank:map`: Use LambdaMART to perform list-wise ranking where
|
|
||||||
#' [Mean Average Precision (MAP)](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Mean_average_precision)
|
|
||||||
#' is maximized.
|
|
||||||
#' - `reg:gamma`: Gamma regression with log-link. Output is a mean of gamma distribution.
|
|
||||||
#' It might be useful, e.g., for modeling insurance claims severity, or for any outcome that might be
|
|
||||||
#' [gamma-distributed](https://en.wikipedia.org/wiki/Gamma_distribution#Applications).
|
|
||||||
#' - `reg:tweedie`: Tweedie regression with log-link.
|
|
||||||
#' It might be useful, e.g., for modeling total loss in insurance, or for any outcome that might be
|
|
||||||
#' [Tweedie-distributed](https://en.wikipedia.org/wiki/Tweedie_distribution#Applications).
|
|
||||||
#'
|
|
||||||
#' For custom objectives, one should pass a function taking as input the current predictions (as a numeric
|
|
||||||
#' vector or matrix) and the training data (as an `xgb.DMatrix` object) that will return a list with elements
|
|
||||||
#' `grad` and `hess`, which should be numeric vectors or matrices with number of rows matching to the numbers
|
|
||||||
#' of rows in the training data (same shape as the predictions that are passed as input to the function).
|
|
||||||
#' For multi-valued custom objectives, should have shape `[nrows, ntargets]`. Note that negative values of
|
|
||||||
#' the Hessian will be clipped, so one might consider using the expected Hessian (Fisher information) if the
|
|
||||||
#' objective is non-convex.
|
|
||||||
#'
|
|
||||||
#' See the tutorials [Custom Objective and Evaluation Metric](https://xgboost.readthedocs.io/en/stable/tutorials/custom_metric_obj.html)
|
|
||||||
#' and [Advanced Usage of Custom Objectives](https://xgboost.readthedocs.io/en/stable/tutorials/advanced_custom_obj)
|
|
||||||
#' for more information about custom objectives.
|
|
||||||
#'
|
|
||||||
#' - `base_score`: The initial prediction score of all instances, global bias. Default: 0.5.
|
|
||||||
#' - `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 Training dataset. `xgb.train()` accepts only an `xgb.DMatrix` as the input.
|
|
||||||
#' [xgboost()], in addition, also accepts `matrix`, `dgCMatrix`, or name of a local data file.
|
|
||||||
#' @param nrounds Max number of boosting iterations.
|
|
||||||
#' @param evals Named list of `xgb.DMatrix` datasets to use for evaluating model performance.
|
|
||||||
#' Metrics specified in either `eval_metric` or `feval` will be computed for each
|
|
||||||
#' of these datasets during each boosting iteration, and stored in the end as a field named
|
|
||||||
#' `evaluation_log` in the resulting object. When either `verbose>=1` or
|
|
||||||
#' [xgb.cb.print.evaluation()] callback is engaged, the performance results are continuously
|
|
||||||
#' printed out during the training.
|
|
||||||
#' E.g., specifying `evals=list(validation1=mat1, validation2=mat2)` allows to track
|
|
||||||
#' the performance of each round's model on mat1 and mat2.
|
|
||||||
#' @param obj Customized objective function. Should take two arguments: the first one will be the
|
|
||||||
#' current predictions (either a numeric vector or matrix depending on the number of targets / classes),
|
|
||||||
#' and the second one will be the `data` DMatrix object that is used for training.
|
|
||||||
#'
|
|
||||||
#' It should return a list with two elements `grad` and `hess` (in that order), as either
|
|
||||||
#' numeric vectors or numeric matrices depending on the number of targets / classes (same
|
|
||||||
#' dimension as the predictions that are passed as first argument).
|
|
||||||
#' @param feval Customized evaluation function. Just like `obj`, should take two arguments, with
|
|
||||||
#' the first one being the predictions and the second one the `data` DMatrix.
|
|
||||||
#'
|
|
||||||
#' Should return a list with two elements `metric` (name that will be displayed for this metric,
|
|
||||||
#' should be a string / character), and `value` (the number that the function calculates, should
|
|
||||||
#' be a numeric scalar).
|
|
||||||
#'
|
|
||||||
#' Note that even if passing `feval`, objectives also have an associated default metric that
|
|
||||||
#' will be evaluated in addition to it. In order to disable the built-in metric, one can pass
|
|
||||||
#' parameter `disable_default_eval_metric = TRUE`.
|
|
||||||
#' @param verbose If 0, xgboost will stay silent. If 1, it will print information about performance.
|
|
||||||
#' If 2, some additional information will be printed out.
|
|
||||||
#' Note that setting `verbose > 0` automatically engages the
|
|
||||||
#' `xgb.cb.print.evaluation(period=1)` callback function.
|
|
||||||
#' @param print_every_n Print each nth iteration evaluation messages when `verbose>0`.
|
|
||||||
#' Default is 1 which means all messages are printed. This parameter is passed to the
|
|
||||||
#' [xgb.cb.print.evaluation()] callback.
|
|
||||||
#' @param early_stopping_rounds If `NULL`, the early stopping function is not triggered.
|
|
||||||
#' If set to an integer `k`, training with a validation set will stop if the performance
|
|
||||||
#' doesn't improve for `k` rounds. Setting this parameter engages the [xgb.cb.early.stop()] callback.
|
|
||||||
#' @param maximize If `feval` and `early_stopping_rounds` are set, then this parameter must be set as well.
|
|
||||||
#' When it is `TRUE`, it means the larger the evaluation score the better.
|
|
||||||
#' This parameter is passed to the [xgb.cb.early.stop()] callback.
|
|
||||||
#' @param save_period When not `NULL`, model is saved to disk after every `save_period` rounds.
|
|
||||||
#' 0 means save at the end. The saving is handled by the [xgb.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 training from.
|
|
||||||
#' Could be either an object of class `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 [xgb.Callback()]. 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.
|
|
||||||
#'
|
|
||||||
#' Note that some callbacks might try to leave attributes in the resulting model object,
|
|
||||||
#' such as an evaluation log (a `data.table` object) - be aware that these objects are kept
|
|
||||||
#' as R attributes, and thus do not get saved when using XGBoost's own serializaters like
|
|
||||||
#' [xgb.save()] (but are kept when using R serializers like [saveRDS()]).
|
|
||||||
#' @param ... other parameters to pass to `params`.
|
|
||||||
#'
|
|
||||||
#' @return An object of class `xgb.Booster`.
|
|
||||||
#'
|
|
||||||
#' @details
|
|
||||||
#' These are the training functions for [xgboost()].
|
|
||||||
#'
|
|
||||||
#' The `xgb.train()` interface supports advanced features such as `evals`,
|
|
||||||
#' customized objective and evaluation metric functions, therefore it is more flexible
|
|
||||||
#' than the [xgboost()] interface.
|
|
||||||
#'
|
|
||||||
#' Parallelization is automatically enabled if OpenMP is present.
|
|
||||||
#' Number of threads can also be manually specified via the `nthread` parameter.
|
|
||||||
#'
|
|
||||||
#' While in other interfaces, the default random seed defaults to zero, in R, if a parameter `seed`
|
|
||||||
#' is not manually supplied, it will generate a random seed through R's own random number generator,
|
|
||||||
#' whose seed in turn is controllable through `set.seed`. If `seed` is passed, it will override the
|
|
||||||
#' RNG from R.
|
|
||||||
#'
|
|
||||||
#' The evaluation metric is chosen automatically by XGBoost (according to the objective)
|
|
||||||
#' when the `eval_metric` parameter is not provided.
|
|
||||||
#' User may set one or several `eval_metric` parameters.
|
|
||||||
#' Note that when using a customized metric, only this single metric can be used.
|
|
||||||
#' The following is the list of built-in metrics for which XGBoost provides optimized implementation:
|
|
||||||
#' - `rmse`: Root mean square error. \url{https://en.wikipedia.org/wiki/Root_mean_square_error}
|
|
||||||
#' - `logloss`: Negative log-likelihood. \url{https://en.wikipedia.org/wiki/Log-likelihood}
|
|
||||||
#' - `mlogloss`: Multiclass logloss. \url{https://scikit-learn.org/stable/modules/generated/sklearn.metrics.log_loss.html}
|
|
||||||
#' - `error`: Binary classification error rate. It is calculated as `(# 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`.
|
|
||||||
#' - `merror`: Multiclass classification error rate. It is calculated as `(# wrong cases) / (# all cases)`.
|
|
||||||
#' - `mae`: Mean absolute error.
|
|
||||||
#' - `mape`: Mean absolute percentage error.
|
|
||||||
#' - `auc`: Area under the curve.
|
|
||||||
#' \url{https://en.wikipedia.org/wiki/Receiver_operating_characteristic#'Area_under_curve} for ranking evaluation.
|
|
||||||
#' - `aucpr`: Area under the PR curve. \url{https://en.wikipedia.org/wiki/Precision_and_recall} for ranking evaluation.
|
|
||||||
#' - `ndcg`: Normalized Discounted Cumulative Gain (for ranking task). \url{https://en.wikipedia.org/wiki/NDCG}
|
|
||||||
#'
|
|
||||||
#' The following callbacks are automatically created when certain parameters are set:
|
|
||||||
#' - [xgb.cb.print.evaluation()] is turned on when `verbose > 0` and the `print_every_n`
|
|
||||||
#' parameter is passed to it.
|
|
||||||
#' - [xgb.cb.evaluation.log()] is on when `evals` is present.
|
|
||||||
#' - [xgb.cb.early.stop()]: When `early_stopping_rounds` is set.
|
|
||||||
#' - [xgb.cb.save.model()]: When `save_period > 0` is set.
|
|
||||||
#'
|
|
||||||
#' Note that objects of type `xgb.Booster` as returned by this function behave a bit differently
|
|
||||||
#' from typical R objects (it's an 'altrep' list class), and it makes a separation between
|
|
||||||
#' internal booster attributes (restricted to jsonifyable data), accessed through [xgb.attr()]
|
|
||||||
#' and shared between interfaces through serialization functions like [xgb.save()]; and
|
|
||||||
#' R-specific attributes (typically the result from a callback), accessed through [attributes()]
|
|
||||||
#' and [attr()], which are otherwise
|
|
||||||
#' only used in the R interface, only kept when using R's serializers like [saveRDS()], and
|
|
||||||
#' not anyhow used by functions like `predict.xgb.Booster()`.
|
|
||||||
#'
|
|
||||||
#' Be aware that one such R attribute that is automatically added is `params` - this attribute
|
|
||||||
#' is assigned from the `params` argument to this function, and is only meant to serve as a
|
|
||||||
#' reference for what went into the booster, but is not used in other methods that take a booster
|
|
||||||
#' object - so for example, changing the booster's configuration requires calling `xgb.config<-`
|
|
||||||
#' or `xgb.parameters<-`, while simply modifying `attributes(model)$params$<...>` will have no
|
|
||||||
#' effect elsewhere.
|
|
||||||
#'
|
|
||||||
#' @seealso [xgb.Callback()], [predict.xgb.Booster()], [xgb.cv()]
|
|
||||||
#'
|
|
||||||
#' @references
|
|
||||||
#' Tianqi Chen and Carlos Guestrin, "XGBoost: A Scalable Tree Boosting System",
|
|
||||||
#' 22nd SIGKDD Conference on Knowledge Discovery and Data Mining, 2016, \url{https://arxiv.org/abs/1603.02754}
|
|
||||||
#'
|
|
||||||
#' @examples
|
|
||||||
#' data(agaricus.train, package = "xgboost")
|
|
||||||
#' data(agaricus.test, package = "xgboost")
|
|
||||||
#'
|
|
||||||
#' ## Keep the number of threads to 1 for examples
|
|
||||||
#' nthread <- 1
|
|
||||||
#' data.table::setDTthreads(nthread)
|
|
||||||
#'
|
|
||||||
#' dtrain <- with(
|
|
||||||
#' agaricus.train, xgb.DMatrix(data, label = label, nthread = nthread)
|
|
||||||
#' )
|
|
||||||
#' dtest <- with(
|
|
||||||
#' agaricus.test, xgb.DMatrix(data, label = label, nthread = nthread)
|
|
||||||
#' )
|
|
||||||
#' evals <- list(train = dtrain, eval = dtest)
|
|
||||||
#'
|
|
||||||
#' ## A simple xgb.train example:
|
|
||||||
#' param <- list(
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' objective = "binary:logistic",
|
|
||||||
#' eval_metric = "auc"
|
|
||||||
#' )
|
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, evals = evals, verbose = 0)
|
|
||||||
#'
|
|
||||||
#' ## 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))
|
|
||||||
#' grad <- preds - labels
|
|
||||||
#' hess <- preds * (1 - preds)
|
|
||||||
#' return(list(grad = grad, hess = hess))
|
|
||||||
#' }
|
|
||||||
#' evalerror <- function(preds, dtrain) {
|
|
||||||
#' labels <- getinfo(dtrain, "label")
|
|
||||||
#' err <- as.numeric(sum(labels != (preds > 0)))/length(labels)
|
|
||||||
#' return(list(metric = "error", value = err))
|
|
||||||
#' }
|
|
||||||
#'
|
|
||||||
#' # These functions could be used by passing them either:
|
|
||||||
#' # as 'objective' and 'eval_metric' parameters in the params list:
|
|
||||||
#' param <- list(
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' objective = logregobj,
|
|
||||||
#' eval_metric = evalerror
|
|
||||||
#' )
|
|
||||||
#' bst <- xgb.train(param, dtrain, nrounds = 2, evals = evals, verbose = 0)
|
|
||||||
#'
|
|
||||||
#' # or through the ... arguments:
|
|
||||||
#' param <- list(max_depth = 2, eta = 1, nthread = nthread)
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' param,
|
|
||||||
#' dtrain,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' evals = evals,
|
|
||||||
#' verbose = 0,
|
|
||||||
#' objective = logregobj,
|
|
||||||
#' eval_metric = evalerror
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' # or as dedicated 'obj' and 'feval' parameters of xgb.train:
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' param, dtrain, nrounds = 2, evals = evals, obj = logregobj, feval = evalerror
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#'
|
|
||||||
#' ## An xgb.train example of using variable learning rates at each iteration:
|
|
||||||
#' param <- list(
|
|
||||||
#' max_depth = 2,
|
|
||||||
#' eta = 1,
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' objective = "binary:logistic",
|
|
||||||
#' eval_metric = "auc"
|
|
||||||
#' )
|
|
||||||
#' my_etas <- list(eta = c(0.5, 0.1))
|
|
||||||
#'
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' param,
|
|
||||||
#' dtrain,
|
|
||||||
#' nrounds = 2,
|
|
||||||
#' evals = evals,
|
|
||||||
#' verbose = 0,
|
|
||||||
#' callbacks = list(xgb.cb.reset.parameters(my_etas))
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' ## Early stopping:
|
|
||||||
#' bst <- xgb.train(
|
|
||||||
#' param, dtrain, nrounds = 25, evals = evals, early_stopping_rounds = 3
|
|
||||||
#' )
|
|
||||||
#'
|
|
||||||
#' ## An 'xgboost' interface example:
|
|
||||||
#' bst <- xgboost(
|
|
||||||
#' x = agaricus.train$data,
|
|
||||||
#' y = factor(agaricus.train$label),
|
|
||||||
#' params = list(max_depth = 2, eta = 1),
|
|
||||||
#' nthread = nthread,
|
|
||||||
#' nrounds = 2
|
|
||||||
#' )
|
|
||||||
#' pred <- predict(bst, agaricus.test$data)
|
|
||||||
#'
|
|
||||||
#' @export
|
|
||||||
xgb.train <- function(params = list(), data, nrounds, evals = 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 & evals checks
|
|
||||||
dtrain <- data
|
|
||||||
if (!inherits(dtrain, "xgb.DMatrix"))
|
|
||||||
stop("second argument dtrain must be xgb.DMatrix")
|
|
||||||
if (length(evals) > 0) {
|
|
||||||
if (typeof(evals) != "list" ||
|
|
||||||
!all(vapply(evals, inherits, logical(1), what = 'xgb.DMatrix')))
|
|
||||||
stop("'evals' must be a list of xgb.DMatrix elements")
|
|
||||||
evnames <- names(evals)
|
|
||||||
if (is.null(evnames) || any(evnames == ""))
|
|
||||||
stop("each element of 'evals' must have a name tag")
|
|
||||||
}
|
|
||||||
# Handle multiple evaluation metrics given as a list
|
|
||||||
for (m in params$eval_metric) {
|
|
||||||
params <- c(params, list(eval_metric = m))
|
|
||||||
}
|
|
||||||
|
|
||||||
params <- c(params)
|
|
||||||
params['validate_parameters'] <- TRUE
|
|
||||||
if (!("seed" %in% names(params))) {
|
|
||||||
params[["seed"]] <- sample(.Machine$integer.max, size = 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
# callbacks
|
|
||||||
tmp <- .process.callbacks(callbacks, is_cv = FALSE)
|
|
||||||
callbacks <- tmp$callbacks
|
|
||||||
cb_names <- tmp$cb_names
|
|
||||||
rm(tmp)
|
|
||||||
|
|
||||||
# Early stopping callback (should always come first)
|
|
||||||
if (!is.null(early_stopping_rounds) && !("early_stop" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(
|
|
||||||
callbacks,
|
|
||||||
xgb.cb.early.stop(
|
|
||||||
early_stopping_rounds,
|
|
||||||
maximize = maximize,
|
|
||||||
verbose = verbose
|
|
||||||
),
|
|
||||||
as_first_elt = TRUE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
# evaluation printing callback
|
|
||||||
print_every_n <- max(as.integer(print_every_n), 1L)
|
|
||||||
if (verbose && !("print_evaluation" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.print.evaluation(print_every_n))
|
|
||||||
}
|
|
||||||
# evaluation log callback: it is automatically enabled when 'evals' is provided
|
|
||||||
if (length(evals) && !("evaluation_log" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.evaluation.log())
|
|
||||||
}
|
|
||||||
# Model saving callback
|
|
||||||
if (!is.null(save_period) && !("save_model" %in% cb_names)) {
|
|
||||||
callbacks <- add.callback(callbacks, xgb.cb.save.model(save_period, save_name))
|
|
||||||
}
|
|
||||||
|
|
||||||
# The tree updating process would need slightly different handling
|
|
||||||
is_update <- NVL(params[['process_type']], '.') == 'update'
|
|
||||||
|
|
||||||
# Construct a booster (either a new one or load from xgb_model)
|
|
||||||
bst <- xgb.Booster(
|
|
||||||
params = params,
|
|
||||||
cachelist = append(evals, dtrain),
|
|
||||||
modelfile = xgb_model
|
|
||||||
)
|
|
||||||
niter_init <- bst$niter
|
|
||||||
bst <- bst$bst
|
|
||||||
.Call(
|
|
||||||
XGBoosterCopyInfoFromDMatrix_R,
|
|
||||||
xgb.get.handle(bst),
|
|
||||||
dtrain
|
|
||||||
)
|
|
||||||
|
|
||||||
if (is_update && nrounds > niter_init)
|
|
||||||
stop("nrounds cannot be larger than ", niter_init, " (nrounds of xgb_model)")
|
|
||||||
|
|
||||||
niter_skip <- ifelse(is_update, 0, niter_init)
|
|
||||||
begin_iteration <- niter_skip + 1
|
|
||||||
end_iteration <- niter_skip + nrounds
|
|
||||||
|
|
||||||
.execute.cb.before.training(
|
|
||||||
callbacks,
|
|
||||||
bst,
|
|
||||||
dtrain,
|
|
||||||
evals,
|
|
||||||
begin_iteration,
|
|
||||||
end_iteration
|
|
||||||
)
|
|
||||||
|
|
||||||
# the main loop for boosting iterations
|
|
||||||
for (iteration in begin_iteration:end_iteration) {
|
|
||||||
|
|
||||||
.execute.cb.before.iter(
|
|
||||||
callbacks,
|
|
||||||
bst,
|
|
||||||
dtrain,
|
|
||||||
evals,
|
|
||||||
iteration
|
|
||||||
)
|
|
||||||
|
|
||||||
xgb.iter.update(
|
|
||||||
bst = bst,
|
|
||||||
dtrain = dtrain,
|
|
||||||
iter = iteration - 1,
|
|
||||||
obj = obj
|
|
||||||
)
|
|
||||||
|
|
||||||
bst_evaluation <- NULL
|
|
||||||
if (length(evals) > 0) {
|
|
||||||
bst_evaluation <- xgb.iter.eval(
|
|
||||||
bst = bst,
|
|
||||||
evals = evals,
|
|
||||||
iter = iteration - 1,
|
|
||||||
feval = feval
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
should_stop <- .execute.cb.after.iter(
|
|
||||||
callbacks,
|
|
||||||
bst,
|
|
||||||
dtrain,
|
|
||||||
evals,
|
|
||||||
iteration,
|
|
||||||
bst_evaluation
|
|
||||||
)
|
|
||||||
|
|
||||||
if (should_stop) break
|
|
||||||
}
|
|
||||||
|
|
||||||
cb_outputs <- .execute.cb.after.training(
|
|
||||||
callbacks,
|
|
||||||
bst,
|
|
||||||
dtrain,
|
|
||||||
evals,
|
|
||||||
iteration,
|
|
||||||
bst_evaluation
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_attrs <- list(
|
|
||||||
call = match.call(),
|
|
||||||
params = params
|
|
||||||
)
|
|
||||||
|
|
||||||
curr_attrs <- attributes(bst)
|
|
||||||
if (NROW(curr_attrs)) {
|
|
||||||
curr_attrs <- curr_attrs[
|
|
||||||
setdiff(
|
|
||||||
names(curr_attrs),
|
|
||||||
c(names(extra_attrs), names(cb_outputs))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
curr_attrs <- c(extra_attrs, curr_attrs)
|
|
||||||
if (NROW(cb_outputs)) {
|
|
||||||
curr_attrs <- c(curr_attrs, cb_outputs)
|
|
||||||
}
|
|
||||||
attributes(bst) <- curr_attrs
|
|
||||||
|
|
||||||
return(bst)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
|||||||
XGBoost R Package for Scalable GBM
|
|
||||||
==================================
|
|
||||||
|
|
||||||
[](https://cran.r-project.org/web/packages/xgboost)
|
|
||||||
[](https://cran.rstudio.com/web/packages/xgboost/index.html)
|
|
||||||
[](http://xgboost.readthedocs.org/en/latest/R-package/index.html)
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
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')
|
|
||||||
```
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
Development
|
|
||||||
-----------
|
|
||||||
|
|
||||||
* See the [R Package section](https://xgboost.readthedocs.io/en/latest/contrib/coding_guide.html#r-coding-guideline) of the contributors guide.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
rm -f src/Makevars
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
|
||||||
|
|
||||||
/* Define if building universal (internal helper macro) */
|
|
||||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
||||||
#undef HAVE_INTTYPES_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
|
||||||
#undef HAVE_STDINT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdio.h> header file. */
|
|
||||||
#undef HAVE_STDIO_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
||||||
#undef HAVE_STDLIB_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
|
||||||
#undef HAVE_STRINGS_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <string.h> header file. */
|
|
||||||
#undef HAVE_STRING_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
||||||
#undef HAVE_SYS_STAT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
||||||
#undef HAVE_SYS_TYPES_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
|
||||||
#undef HAVE_UNISTD_H
|
|
||||||
|
|
||||||
/* Define to the address where bug reports for this package should be sent. */
|
|
||||||
#undef PACKAGE_BUGREPORT
|
|
||||||
|
|
||||||
/* Define to the full name of this package. */
|
|
||||||
#undef PACKAGE_NAME
|
|
||||||
|
|
||||||
/* Define to the full name and version of this package. */
|
|
||||||
#undef PACKAGE_STRING
|
|
||||||
|
|
||||||
/* Define to the one symbol short name of this package. */
|
|
||||||
#undef PACKAGE_TARNAME
|
|
||||||
|
|
||||||
/* Define to the home page for this package. */
|
|
||||||
#undef PACKAGE_URL
|
|
||||||
|
|
||||||
/* Define to the version of this package. */
|
|
||||||
#undef PACKAGE_VERSION
|
|
||||||
|
|
||||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
|
||||||
required in a freestanding environment). This macro is provided for
|
|
||||||
backward compatibility; new code need not use it. */
|
|
||||||
#undef STDC_HEADERS
|
|
||||||
|
|
||||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
|
||||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
|
||||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
|
||||||
# if defined __BIG_ENDIAN__
|
|
||||||
# define WORDS_BIGENDIAN 1
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# ifndef WORDS_BIGENDIAN
|
|
||||||
# undef WORDS_BIGENDIAN
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
4480
R-package/configure
vendored
4480
R-package/configure
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,88 +0,0 @@
|
|||||||
### configure.ac -*- Autoconf -*-
|
|
||||||
|
|
||||||
AC_PREREQ(2.69)
|
|
||||||
|
|
||||||
AC_INIT([xgboost],[2.2.0],[],[xgboost],[])
|
|
||||||
|
|
||||||
: ${R_HOME=`R RHOME`}
|
|
||||||
if test -z "${R_HOME}"; then
|
|
||||||
echo "could not determine R_HOME"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
CXX17=`"${R_HOME}/bin/R" CMD config CXX17`
|
|
||||||
CXX17STD=`"${R_HOME}/bin/R" CMD config CXX17STD`
|
|
||||||
CXX="${CXX17} ${CXX17STD}"
|
|
||||||
CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXXFLAGS`
|
|
||||||
|
|
||||||
CC=`"${R_HOME}/bin/R" CMD config CC`
|
|
||||||
CFLAGS=`"${R_HOME}/bin/R" CMD config CFLAGS`
|
|
||||||
CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS`
|
|
||||||
|
|
||||||
LDFLAGS=`"${R_HOME}/bin/R" CMD config LDFLAGS`
|
|
||||||
AC_LANG(C++)
|
|
||||||
|
|
||||||
### Check whether backtrace() is part of libc or the external lib libexecinfo
|
|
||||||
AC_MSG_CHECKING([Backtrace lib])
|
|
||||||
AC_MSG_RESULT([])
|
|
||||||
AC_CHECK_LIB([execinfo], [backtrace], [BACKTRACE_LIB=-lexecinfo], [BACKTRACE_LIB=''])
|
|
||||||
|
|
||||||
### Endian detection
|
|
||||||
AC_ARG_VAR(USE_LITTLE_ENDIAN, "Whether to build with little endian (checks at compile time if unset)")
|
|
||||||
AS_IF([test -z "${USE_LITTLE_ENDIAN+x}"], [
|
|
||||||
AC_MSG_NOTICE([Checking system endianness as USE_LITTLE_ENDIAN is unset])
|
|
||||||
AC_MSG_CHECKING([system endianness])
|
|
||||||
AC_C_BIGENDIAN(
|
|
||||||
[AC_MSG_RESULT([using big endian])
|
|
||||||
ENDIAN_FLAG="-DDMLC_CMAKE_LITTLE_ENDIAN=0"],
|
|
||||||
[AC_MSG_RESULT([using little endian])
|
|
||||||
ENDIAN_FLAG="-DDMLC_CMAKE_LITTLE_ENDIAN=1"],
|
|
||||||
[AC_MSG_RESULT([unknown])
|
|
||||||
AC_MSG_ERROR([Could not determine endianness. Please set USE_LITTLE_ENDIAN])]
|
|
||||||
)
|
|
||||||
], [
|
|
||||||
AC_MSG_NOTICE([Forcing endianness to: ${USE_LITTLE_ENDIAN}])
|
|
||||||
ENDIAN_FLAG="-DDMLC_CMAKE_LITTLE_ENDIAN=${USE_LITTLE_ENDIAN}"
|
|
||||||
])
|
|
||||||
|
|
||||||
OPENMP_CXXFLAGS=""
|
|
||||||
|
|
||||||
if test `uname -s` = "Linux"
|
|
||||||
then
|
|
||||||
OPENMP_CXXFLAGS="\$(SHLIB_OPENMP_CXXFLAGS)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test `uname -s` = "Darwin"
|
|
||||||
then
|
|
||||||
if command -v brew &> /dev/null
|
|
||||||
then
|
|
||||||
HOMEBREW_LIBOMP_PREFIX=`brew --prefix libomp`
|
|
||||||
else
|
|
||||||
# Homebrew not found
|
|
||||||
HOMEBREW_LIBOMP_PREFIX=''
|
|
||||||
fi
|
|
||||||
OPENMP_CXXFLAGS="-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PREFIX}/include"
|
|
||||||
OPENMP_LIB="-lomp -L${HOMEBREW_LIBOMP_PREFIX}/lib"
|
|
||||||
ac_pkg_openmp=no
|
|
||||||
AC_MSG_CHECKING([whether OpenMP will work in a package])
|
|
||||||
AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include <omp.h>]], [[ return (omp_get_max_threads() <= 1); ]])])
|
|
||||||
${CXX} -o conftest conftest.cpp ${CPPFLAGS} ${LDFLAGS} ${OPENMP_LIB} ${OPENMP_CXXFLAGS} 2>/dev/null && ./conftest && ac_pkg_openmp=yes
|
|
||||||
AC_MSG_RESULT([${ac_pkg_openmp}])
|
|
||||||
if test "${ac_pkg_openmp}" = no; then
|
|
||||||
OPENMP_CXXFLAGS=''
|
|
||||||
OPENMP_LIB=''
|
|
||||||
echo '*****************************************************************************************'
|
|
||||||
echo ' OpenMP is unavailable on this Mac OSX system. Training speed may be suboptimal.'
|
|
||||||
echo ' To use all CPU cores for training jobs, you should install OpenMP by running\n'
|
|
||||||
echo ' brew install libomp'
|
|
||||||
echo '*****************************************************************************************'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_SUBST(OPENMP_CXXFLAGS)
|
|
||||||
AC_SUBST(OPENMP_LIB)
|
|
||||||
AC_SUBST(ENDIAN_FLAG)
|
|
||||||
AC_SUBST(BACKTRACE_LIB)
|
|
||||||
AC_CONFIG_FILES([src/Makevars])
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
|
||||||
AC_OUTPUT
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,96 +0,0 @@
|
|||||||
# [description]
|
|
||||||
# Create a definition file (.def) from a .dll file, using objdump. This
|
|
||||||
# is used by FindLibR.cmake when building the R package with MSVC.
|
|
||||||
#
|
|
||||||
# [usage]
|
|
||||||
#
|
|
||||||
# Rscript make-r-def.R something.dll something.def
|
|
||||||
#
|
|
||||||
# [references]
|
|
||||||
# * https://www.cs.colorado.edu/~main/cs1300/doc/mingwfaq.html
|
|
||||||
|
|
||||||
args <- commandArgs(trailingOnly = TRUE)
|
|
||||||
|
|
||||||
IN_DLL_FILE <- args[[1L]]
|
|
||||||
OUT_DEF_FILE <- args[[2L]]
|
|
||||||
DLL_BASE_NAME <- basename(IN_DLL_FILE)
|
|
||||||
|
|
||||||
message(sprintf("Creating '%s' from '%s'", OUT_DEF_FILE, IN_DLL_FILE))
|
|
||||||
|
|
||||||
# system() will not raise an R exception if the process called
|
|
||||||
# fails. Wrapping it here to get that behavior.
|
|
||||||
#
|
|
||||||
# system() introduces a lot of overhead, at least on Windows,
|
|
||||||
# so trying processx if it is available
|
|
||||||
.pipe_shell_command_to_stdout <- function(command, args, out_file) {
|
|
||||||
has_processx <- suppressMessages({
|
|
||||||
suppressWarnings({
|
|
||||||
require("processx") # nolint
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (has_processx) {
|
|
||||||
p <- processx::process$new(
|
|
||||||
command = command
|
|
||||||
, args = args
|
|
||||||
, stdout = out_file
|
|
||||||
, windows_verbatim_args = FALSE
|
|
||||||
)
|
|
||||||
invisible(p$wait())
|
|
||||||
} else {
|
|
||||||
message(paste0(
|
|
||||||
"Using system2() to run shell commands. Installing "
|
|
||||||
, "'processx' with install.packages('processx') might "
|
|
||||||
, "make this faster."
|
|
||||||
))
|
|
||||||
exit_code <- system2(
|
|
||||||
command = command
|
|
||||||
, args = shQuote(args)
|
|
||||||
, stdout = out_file
|
|
||||||
)
|
|
||||||
if (exit_code != 0L) {
|
|
||||||
stop(paste0("Command failed with exit code: ", exit_code))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(invisible(NULL))
|
|
||||||
}
|
|
||||||
|
|
||||||
# use objdump to dump all the symbols
|
|
||||||
OBJDUMP_FILE <- file.path(tempdir(), "objdump-out.txt")
|
|
||||||
.pipe_shell_command_to_stdout(
|
|
||||||
command = "objdump"
|
|
||||||
, args = c("-p", IN_DLL_FILE)
|
|
||||||
, out_file = OBJDUMP_FILE
|
|
||||||
)
|
|
||||||
|
|
||||||
objdump_results <- readLines(OBJDUMP_FILE)
|
|
||||||
result <- file.remove(OBJDUMP_FILE)
|
|
||||||
|
|
||||||
# Only one table in the objdump results matters for our purposes,
|
|
||||||
# see https://www.cs.colorado.edu/~main/cs1300/doc/mingwfaq.html
|
|
||||||
start_index <- which(
|
|
||||||
grepl(
|
|
||||||
pattern = "[Ordinal/Name Pointer] Table"
|
|
||||||
, x = objdump_results
|
|
||||||
, fixed = TRUE
|
|
||||||
)
|
|
||||||
)
|
|
||||||
empty_lines <- which(objdump_results == "")
|
|
||||||
end_of_table <- empty_lines[empty_lines > start_index][1L]
|
|
||||||
|
|
||||||
# Read the contents of the table
|
|
||||||
exported_symbols <- objdump_results[(start_index + 1L):end_of_table]
|
|
||||||
exported_symbols <- gsub("\t", "", exported_symbols, fixed = TRUE)
|
|
||||||
exported_symbols <- gsub(".*\\] ", "", exported_symbols)
|
|
||||||
exported_symbols <- gsub(" ", "", exported_symbols, fixed = TRUE)
|
|
||||||
|
|
||||||
# Write R.def file
|
|
||||||
writeLines(
|
|
||||||
text = c(
|
|
||||||
paste0("LIBRARY \"", DLL_BASE_NAME, "\"")
|
|
||||||
, "EXPORTS"
|
|
||||||
, exported_symbols
|
|
||||||
)
|
|
||||||
, con = OUT_DEF_FILE
|
|
||||||
, sep = "\n"
|
|
||||||
)
|
|
||||||
message(sprintf("Successfully created '%s'", OUT_DEF_FILE))
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/utils.R
|
|
||||||
\name{a-compatibility-note-for-saveRDS-save}
|
|
||||||
\alias{a-compatibility-note-for-saveRDS-save}
|
|
||||||
\title{Model Serialization and Compatibility}
|
|
||||||
\description{
|
|
||||||
When it comes to serializing XGBoost models, it's possible to use R serializers such as
|
|
||||||
\code{\link[=save]{save()}} or \code{\link[=saveRDS]{saveRDS()}} to serialize an XGBoost R model, but XGBoost also provides
|
|
||||||
its own serializers with better compatibility guarantees, which allow loading
|
|
||||||
said models in other language bindings of XGBoost.
|
|
||||||
|
|
||||||
Note that an \code{xgb.Booster} object (\strong{as produced by \code{\link[=xgb.train]{xgb.train()}}}, see rest of the doc
|
|
||||||
for objects produced by \code{\link[=xgboost]{xgboost()}}), outside of its core components, might also keep:
|
|
||||||
\itemize{
|
|
||||||
\item Additional model configuration (accessible through \code{\link[=xgb.config]{xgb.config()}}), which includes
|
|
||||||
model fitting parameters like \code{max_depth} and runtime parameters like \code{nthread}.
|
|
||||||
These are not necessarily useful for prediction/importance/plotting.
|
|
||||||
\item Additional R specific attributes - e.g. results of callbacks, such as evaluation logs,
|
|
||||||
which are kept as a \code{data.table} object, accessible through
|
|
||||||
\code{attributes(model)$evaluation_log} if present.
|
|
||||||
}
|
|
||||||
|
|
||||||
The first one (configurations) does not have the same compatibility guarantees as
|
|
||||||
the model itself, including attributes that are set and accessed through
|
|
||||||
\code{\link[=xgb.attributes]{xgb.attributes()}} - that is, such configuration might be lost after loading the
|
|
||||||
booster in a different XGBoost version, regardless of the serializer that was used.
|
|
||||||
These are saved when using \code{\link[=saveRDS]{saveRDS()}}, but will be discarded if loaded into an
|
|
||||||
incompatible XGBoost version. They are not saved when using XGBoost's
|
|
||||||
serializers from its public interface including \code{\link[=xgb.save]{xgb.save()}} and \code{\link[=xgb.save.raw]{xgb.save.raw()}}.
|
|
||||||
|
|
||||||
The second ones (R attributes) are not part of the standard XGBoost model structure,
|
|
||||||
and thus are not saved when using XGBoost's own serializers. These attributes are
|
|
||||||
only used for informational purposes, such as keeping track of evaluation metrics as
|
|
||||||
the model was fit, or saving the R call that produced the model, but are otherwise
|
|
||||||
not used for prediction / importance / plotting / etc.
|
|
||||||
These R attributes are only preserved when using R's serializers.
|
|
||||||
|
|
||||||
In addition to the regular \code{xgb.Booster} objects producted by \code{\link[=xgb.train]{xgb.train()}}, the
|
|
||||||
function \code{\link[=xgboost]{xgboost()}} produces a different subclass \code{xgboost}, which keeps other
|
|
||||||
additional metadata as R attributes such as class names in classification problems,
|
|
||||||
and which has a dedicated \code{predict} method that uses different defaults. XGBoost's
|
|
||||||
own serializers can work with this \code{xgboost} class, but as they do not keep R
|
|
||||||
attributes, the resulting object, when deserialized, is downcasted to the regular
|
|
||||||
\code{xgb.Booster} class (i.e. it loses the metadata, and the resulting object will use
|
|
||||||
\code{predict.xgb.Booster} instead of \code{predict.xgboost}) - for these \code{xgboost} objects,
|
|
||||||
\code{saveRDS} might thus be a better option if the extra functionalities are needed.
|
|
||||||
|
|
||||||
Note that XGBoost models in R starting from version \verb{2.1.0} and onwards, and
|
|
||||||
XGBoost models before version \verb{2.1.0}; have a very different R object structure and
|
|
||||||
are incompatible with each other. Hence, models that were saved with R serializers
|
|
||||||
like \code{\link[=saveRDS]{saveRDS()}} or \code{\link[=save]{save()}} before version \verb{2.1.0} will not work with latter
|
|
||||||
\code{xgboost} versions and vice versa. Be aware that the structure of R model objects
|
|
||||||
could in theory change again in the future, so XGBoost's serializers
|
|
||||||
should be preferred for long-term storage.
|
|
||||||
|
|
||||||
Furthermore, note that using the package \code{qs} for serialization will require
|
|
||||||
version 0.26 or higher of said package, and will have the same compatibility
|
|
||||||
restrictions as R serializers.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Use \code{\link[=xgb.save]{xgb.save()}} to save the XGBoost model as a stand-alone file. You may opt into
|
|
||||||
the JSON format by specifying the JSON extension. To read the model back, use
|
|
||||||
\code{\link[=xgb.load]{xgb.load()}}.
|
|
||||||
|
|
||||||
Use \code{\link[=xgb.save.raw]{xgb.save.raw()}} to save the XGBoost model as a sequence (vector) of raw bytes
|
|
||||||
in a future-proof manner. Future releases of XGBoost will be able to read the raw bytes and
|
|
||||||
re-construct the corresponding model. To read the model back, use \code{\link[=xgb.load.raw]{xgb.load.raw()}}.
|
|
||||||
The \code{\link[=xgb.save.raw]{xgb.save.raw()}} function is useful if you would like to persist the XGBoost model
|
|
||||||
as part of another R object.
|
|
||||||
|
|
||||||
Use \code{\link[=saveRDS]{saveRDS()}} if you require the R-specific attributes that a booster might have, such
|
|
||||||
as evaluation logs or the model class \code{xgboost} instead of \code{xgb.Booster}, but note that
|
|
||||||
future compatibility of such objects is outside XGBoost's control as it relies on R's
|
|
||||||
serialization format (see e.g. the details section in \link{serialize} and \code{\link[=save]{save()}} from base R).
|
|
||||||
|
|
||||||
For more details and explanation about model persistence and archival, consult the page
|
|
||||||
\url{https://xgboost.readthedocs.io/en/latest/tutorials/saving_model.html}.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(agaricus.train$data, label = agaricus.train$label),
|
|
||||||
max_depth = 2,
|
|
||||||
eta = 1,
|
|
||||||
nthread = 2,
|
|
||||||
nrounds = 2,
|
|
||||||
objective = "binary:logistic"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Save as a stand-alone file; load it with xgb.load()
|
|
||||||
fname <- file.path(tempdir(), "xgb_model.ubj")
|
|
||||||
xgb.save(bst, fname)
|
|
||||||
bst2 <- xgb.load(fname)
|
|
||||||
|
|
||||||
# Save as a stand-alone file (JSON); load it with xgb.load()
|
|
||||||
fname <- file.path(tempdir(), "xgb_model.json")
|
|
||||||
xgb.save(bst, fname)
|
|
||||||
bst2 <- xgb.load(fname)
|
|
||||||
|
|
||||||
# Save as a raw byte vector; load it with xgb.load.raw()
|
|
||||||
xgb_bytes <- xgb.save.raw(bst)
|
|
||||||
bst2 <- xgb.load.raw(xgb_bytes)
|
|
||||||
|
|
||||||
# Persist XGBoost model as part of another R object
|
|
||||||
obj <- list(xgb_model_bytes = xgb.save.raw(bst), description = "My first XGBoost model")
|
|
||||||
# Persist the R object. Here, saveRDS() is okay, since it doesn't persist
|
|
||||||
# xgb.Booster directly. What's being persisted is the future-proof byte representation
|
|
||||||
# as given by xgb.save.raw().
|
|
||||||
fname <- file.path(tempdir(), "my_object.Rds")
|
|
||||||
saveRDS(obj, fname)
|
|
||||||
# Read back the R object
|
|
||||||
obj2 <- readRDS(fname)
|
|
||||||
# Re-construct xgb.Booster object from the bytes
|
|
||||||
bst2 <- xgb.load.raw(obj2$xgb_model_bytes)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
% 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
|
|
||||||
rows and 126 variables
|
|
||||||
}
|
|
||||||
\usage{
|
|
||||||
data(agaricus.test)
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
This data set is originally from the Mushroom data set,
|
|
||||||
UCI Machine Learning Repository.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
It includes the following fields:
|
|
||||||
\itemize{
|
|
||||||
\item \code{label}: The label for each record.
|
|
||||||
\item \code{data}: A sparse Matrix of 'dgCMatrix' class with 126 columns.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\references{
|
|
||||||
\url{https://archive.ics.uci.edu/ml/datasets/Mushroom}
|
|
||||||
|
|
||||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
|
||||||
\url{http://archive.ics.uci.edu/ml}. Irvine, CA: University of California,
|
|
||||||
School of Information and Computer Science.
|
|
||||||
}
|
|
||||||
\keyword{datasets}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
% 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
|
|
||||||
rows and 127 variables
|
|
||||||
}
|
|
||||||
\usage{
|
|
||||||
data(agaricus.train)
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
This data set is originally from the Mushroom data set,
|
|
||||||
UCI Machine Learning Repository.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
It includes the following fields:
|
|
||||||
\itemize{
|
|
||||||
\item \code{label}: The label for each record.
|
|
||||||
\item \code{data}: A sparse Matrix of 'dgCMatrix' class with 126 columns.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\references{
|
|
||||||
\url{https://archive.ics.uci.edu/ml/datasets/Mushroom}
|
|
||||||
|
|
||||||
Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
|
|
||||||
\url{http://archive.ics.uci.edu/ml}. Irvine, CA: University of California,
|
|
||||||
School of Information and Computer Science.
|
|
||||||
}
|
|
||||||
\keyword{datasets}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R
|
|
||||||
\name{coef.xgb.Booster}
|
|
||||||
\alias{coef.xgb.Booster}
|
|
||||||
\title{Extract coefficients from linear booster}
|
|
||||||
\usage{
|
|
||||||
\method{coef}{xgb.Booster}(object, ...)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{A fitted booster of 'gblinear' type.}
|
|
||||||
|
|
||||||
\item{...}{Not used.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
The extracted coefficients:
|
|
||||||
\itemize{
|
|
||||||
\item If there is only one coefficient per column in the data, will be returned as a
|
|
||||||
vector, potentially containing the feature names if available, with the intercept
|
|
||||||
as first column.
|
|
||||||
\item If there is more than one coefficient per column in the data (e.g. when using
|
|
||||||
\code{objective="multi:softmax"}), will be returned as a matrix with dimensions equal
|
|
||||||
to \verb{[num_features, num_cols]}, with the intercepts as first row. Note that the column
|
|
||||||
(classes in multi-class classification) dimension will not be named.
|
|
||||||
}
|
|
||||||
|
|
||||||
The intercept returned here will include the 'base_score' parameter (unlike the 'bias'
|
|
||||||
or the last coefficient in the model dump, which doesn't have 'base_score' added to it),
|
|
||||||
hence one should get the same values from calling \code{predict(..., outputmargin = TRUE)} and
|
|
||||||
from performing a matrix multiplication with \code{model.matrix(~., ...)}.
|
|
||||||
|
|
||||||
Be aware that the coefficients are obtained by first converting them to strings and
|
|
||||||
back, so there will always be some very small lose of precision compared to the actual
|
|
||||||
coefficients as used by \link{predict.xgb.Booster}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Extracts the coefficients from a 'gblinear' booster object,
|
|
||||||
as produced by \code{\link[=xgb.train]{xgb.train()}} when using parameter \code{booster="gblinear"}.
|
|
||||||
|
|
||||||
Note: this function will error out if passing a booster model
|
|
||||||
which is not of "gblinear" type.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
library(xgboost)
|
|
||||||
|
|
||||||
data(mtcars)
|
|
||||||
|
|
||||||
y <- mtcars[, 1]
|
|
||||||
x <- as.matrix(mtcars[, -1])
|
|
||||||
|
|
||||||
dm <- xgb.DMatrix(data = x, label = y, nthread = 1)
|
|
||||||
params <- list(booster = "gblinear", nthread = 1)
|
|
||||||
model <- xgb.train(data = dm, params = params, nrounds = 2)
|
|
||||||
coef(model)
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
% 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{\link[=nrow]{nrow()}} and \code{\link[=ncol]{ncol()}} internally use \code{\link[=dim]{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, nthread = 2)
|
|
||||||
|
|
||||||
stopifnot(nrow(dtrain) == nrow(train$data))
|
|
||||||
stopifnot(ncol(dtrain) == ncol(train$data))
|
|
||||||
stopifnot(all(dim(dtrain) == dim(train$data)))
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
% 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 returned row names would be \code{NULL}.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Generic \code{\link[=dimnames]{dimnames()}} methods are used by \code{\link[=colnames]{colnames()}}.
|
|
||||||
Since row names are irrelevant, it is recommended to use \code{\link[=colnames]{colnames()}} directly.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
train <- agaricus.train
|
|
||||||
dtrain <- xgb.DMatrix(train$data, label = train$label, nthread = 2)
|
|
||||||
dimnames(dtrain)
|
|
||||||
colnames(dtrain)
|
|
||||||
colnames(dtrain) <- make.names(1:ncol(train$data))
|
|
||||||
print(dtrain, verbose = TRUE)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R, R/xgb.DMatrix.R
|
|
||||||
\name{getinfo.xgb.Booster}
|
|
||||||
\alias{getinfo.xgb.Booster}
|
|
||||||
\alias{setinfo.xgb.Booster}
|
|
||||||
\alias{getinfo}
|
|
||||||
\alias{getinfo.xgb.DMatrix}
|
|
||||||
\alias{setinfo}
|
|
||||||
\alias{setinfo.xgb.DMatrix}
|
|
||||||
\title{Get or set information of xgb.DMatrix and xgb.Booster objects}
|
|
||||||
\usage{
|
|
||||||
\method{getinfo}{xgb.Booster}(object, name)
|
|
||||||
|
|
||||||
\method{setinfo}{xgb.Booster}(object, name, info)
|
|
||||||
|
|
||||||
getinfo(object, name)
|
|
||||||
|
|
||||||
\method{getinfo}{xgb.DMatrix}(object, name)
|
|
||||||
|
|
||||||
setinfo(object, name, info)
|
|
||||||
|
|
||||||
\method{setinfo}{xgb.DMatrix}(object, name, info)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{Object of class \code{xgb.DMatrix} or \code{xgb.Booster}.}
|
|
||||||
|
|
||||||
\item{name}{The name of the information field to get (see details).}
|
|
||||||
|
|
||||||
\item{info}{The specific field of information to set.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
For \code{getinfo()}, will return the requested field. For \code{setinfo()},
|
|
||||||
will always return value \code{TRUE} if it succeeds.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Get or set information of xgb.DMatrix and xgb.Booster objects
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
The \code{name} field can be one of the following for \code{xgb.DMatrix}:
|
|
||||||
\itemize{
|
|
||||||
\item label
|
|
||||||
\item weight
|
|
||||||
\item base_margin
|
|
||||||
\item label_lower_bound
|
|
||||||
\item label_upper_bound
|
|
||||||
\item group
|
|
||||||
\item feature_type
|
|
||||||
\item feature_name
|
|
||||||
\item nrow
|
|
||||||
}
|
|
||||||
|
|
||||||
See the documentation for \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} for more information about these fields.
|
|
||||||
|
|
||||||
For \code{xgb.Booster}, can be one of the following:
|
|
||||||
\itemize{
|
|
||||||
\item \code{feature_type}
|
|
||||||
\item \code{feature_name}
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that, while 'qid' cannot be retrieved, it is possible to get the equivalent 'group'
|
|
||||||
for a DMatrix that had 'qid' assigned.
|
|
||||||
|
|
||||||
\strong{Important}: when calling \code{\link[=setinfo]{setinfo()}}, the objects are modified in-place. See
|
|
||||||
\code{\link[=xgb.copy.Booster]{xgb.copy.Booster()}} for an idea of this in-place assignment works.
|
|
||||||
|
|
||||||
See the documentation for \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} for possible fields that can be set
|
|
||||||
(which correspond to arguments in that function).
|
|
||||||
|
|
||||||
Note that the following fields are allowed in the construction of an \code{xgb.DMatrix}
|
|
||||||
but \strong{are not} allowed here:
|
|
||||||
\itemize{
|
|
||||||
\item data
|
|
||||||
\item missing
|
|
||||||
\item silent
|
|
||||||
\item nthread
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
|
|
||||||
labels <- getinfo(dtrain, "label")
|
|
||||||
setinfo(dtrain, "label", 1 - labels)
|
|
||||||
|
|
||||||
labels2 <- getinfo(dtrain, "label")
|
|
||||||
stopifnot(all(labels2 == 1 - labels))
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
|
|
||||||
labels <- getinfo(dtrain, "label")
|
|
||||||
setinfo(dtrain, "label", 1 - labels)
|
|
||||||
|
|
||||||
labels2 <- getinfo(dtrain, "label")
|
|
||||||
stopifnot(all.equal(labels2, 1 - labels))
|
|
||||||
}
|
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R
|
|
||||||
\name{predict.xgb.Booster}
|
|
||||||
\alias{predict.xgb.Booster}
|
|
||||||
\title{Predict method for XGBoost model}
|
|
||||||
\usage{
|
|
||||||
\method{predict}{xgb.Booster}(
|
|
||||||
object,
|
|
||||||
newdata,
|
|
||||||
missing = NA,
|
|
||||||
outputmargin = FALSE,
|
|
||||||
predleaf = FALSE,
|
|
||||||
predcontrib = FALSE,
|
|
||||||
approxcontrib = FALSE,
|
|
||||||
predinteraction = FALSE,
|
|
||||||
training = FALSE,
|
|
||||||
iterationrange = NULL,
|
|
||||||
strict_shape = FALSE,
|
|
||||||
avoid_transpose = FALSE,
|
|
||||||
validate_features = FALSE,
|
|
||||||
base_margin = NULL,
|
|
||||||
...
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{Object of class \code{xgb.Booster}.}
|
|
||||||
|
|
||||||
\item{newdata}{Takes \code{data.frame}, \code{matrix}, \code{dgCMatrix}, \code{dgRMatrix}, \code{dsparseVector},
|
|
||||||
local data file, or \code{xgb.DMatrix}.
|
|
||||||
|
|
||||||
For single-row predictions on sparse data, it is recommended to use CSR format. If passing
|
|
||||||
a sparse vector, it will take it as a row vector.
|
|
||||||
|
|
||||||
Note that, for repeated predictions on the same data, one might want to create a DMatrix to
|
|
||||||
pass here instead of passing R types like matrices or data frames, as predictions will be
|
|
||||||
faster on DMatrix.
|
|
||||||
|
|
||||||
If \code{newdata} is a \code{data.frame}, be aware that:
|
|
||||||
\itemize{
|
|
||||||
\item Columns will be converted to numeric if they aren't already, which could potentially make
|
|
||||||
the operation slower than in an equivalent \code{matrix} object.
|
|
||||||
\item The order of the columns must match with that of the data from which the model was fitted
|
|
||||||
(i.e. columns will not be referenced by their names, just by their order in the data).
|
|
||||||
\item If the model was fitted to data with categorical columns, these columns must be of
|
|
||||||
\code{factor} type here, and must use the same encoding (i.e. have the same levels).
|
|
||||||
\item If \code{newdata} contains any \code{factor} columns, they will be converted to base-0
|
|
||||||
encoding (same as during DMatrix creation) - hence, one should not pass a \code{factor}
|
|
||||||
under a column which during training had a different type.
|
|
||||||
}}
|
|
||||||
|
|
||||||
\item{missing}{Float value that represents missing values in data
|
|
||||||
(e.g., 0 or some other extreme value).
|
|
||||||
|
|
||||||
This parameter is not used when \code{newdata} is an \code{xgb.DMatrix} - in such cases,
|
|
||||||
should pass this as an argument to the DMatrix constructor instead.}
|
|
||||||
|
|
||||||
\item{outputmargin}{Whether the prediction should be returned in the form of
|
|
||||||
original untransformed sum of predictions from boosting iterations' results.
|
|
||||||
E.g., setting \code{outputmargin = TRUE} for logistic regression would return log-odds
|
|
||||||
instead of probabilities.}
|
|
||||||
|
|
||||||
\item{predleaf}{Whether to predict per-tree leaf indices.}
|
|
||||||
|
|
||||||
\item{predcontrib}{Whether to return feature contributions to individual predictions (see Details).}
|
|
||||||
|
|
||||||
\item{approxcontrib}{Whether to use a fast approximation for feature contributions (see Details).}
|
|
||||||
|
|
||||||
\item{predinteraction}{Whether to return contributions of feature interactions to individual predictions (see Details).}
|
|
||||||
|
|
||||||
\item{training}{Whether the prediction result is used for training. For dart booster,
|
|
||||||
training predicting will perform dropout.}
|
|
||||||
|
|
||||||
\item{iterationrange}{Sequence of rounds/iterations from the model to use for prediction, specified by passing
|
|
||||||
a two-dimensional vector with the start and end numbers in the sequence (same format as R's \code{seq} - i.e.
|
|
||||||
base-1 indexing, and inclusive of both ends).
|
|
||||||
|
|
||||||
For example, passing \code{c(1,20)} will predict using the first twenty iterations, while passing \code{c(1,1)} will
|
|
||||||
predict using only the first one.
|
|
||||||
|
|
||||||
If passing \code{NULL}, will either stop at the best iteration if the model used early stopping, or use all
|
|
||||||
of the iterations (rounds) otherwise.
|
|
||||||
|
|
||||||
If passing "all", will use all of the rounds regardless of whether the model had early stopping or not.}
|
|
||||||
|
|
||||||
\item{strict_shape}{Whether to always return an array with the same dimensions for the given prediction mode
|
|
||||||
regardless of the model type - meaning that, for example, both a multi-class and a binary classification
|
|
||||||
model would generate output arrays with the same number of dimensions, with the 'class' dimension having
|
|
||||||
size equal to '1' for the binary model.
|
|
||||||
|
|
||||||
If passing \code{FALSE} (the default), dimensions will be simplified according to the model type, so that a
|
|
||||||
binary classification model for example would not have a redundant dimension for 'class'.
|
|
||||||
|
|
||||||
See documentation for the return type for the exact shape of the output arrays for each prediction mode.}
|
|
||||||
|
|
||||||
\item{avoid_transpose}{Whether to output the resulting predictions in the same memory layout in which they
|
|
||||||
are generated by the core XGBoost library, without transposing them to match the expected output shape.
|
|
||||||
|
|
||||||
Internally, XGBoost uses row-major order for the predictions it generates, while R arrays use column-major
|
|
||||||
order, hence the result needs to be transposed in order to have the expected shape when represented as
|
|
||||||
an R array or matrix, which might be a slow operation.
|
|
||||||
|
|
||||||
If passing \code{TRUE}, then the result will have dimensions in reverse order - for example, rows
|
|
||||||
will be the last dimensions instead of the first dimension.}
|
|
||||||
|
|
||||||
\item{validate_features}{When \code{TRUE}, validate that the Booster's and newdata's
|
|
||||||
feature_names match (only applicable when both \code{object} and \code{newdata} have feature names).
|
|
||||||
|
|
||||||
If the column names differ and \code{newdata} is not an \code{xgb.DMatrix}, will try to reorder
|
|
||||||
the columns in \code{newdata} to match with the booster's.
|
|
||||||
|
|
||||||
If the booster has feature types and \code{newdata} is either an \code{xgb.DMatrix} or
|
|
||||||
\code{data.frame}, will additionally verify that categorical columns are of the
|
|
||||||
correct type in \code{newdata}, throwing an error if they do not match.
|
|
||||||
|
|
||||||
If passing \code{FALSE}, it is assumed that the feature names and types are the same,
|
|
||||||
and come in the same order as in the training data.
|
|
||||||
|
|
||||||
Note that this check might add some sizable latency to the predictions, so it's
|
|
||||||
recommended to disable it for performance-sensitive applications.}
|
|
||||||
|
|
||||||
\item{base_margin}{Base margin used for boosting from existing model.
|
|
||||||
|
|
||||||
Note that, if \code{newdata} is an \code{xgb.DMatrix} object, this argument will
|
|
||||||
be ignored as it needs to be added to the DMatrix instead (e.g. by passing it as
|
|
||||||
an argument in its constructor, or by calling \code{\link[=setinfo.xgb.DMatrix]{setinfo.xgb.DMatrix()}}.}
|
|
||||||
|
|
||||||
\item{...}{Not used.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
A numeric vector or array, with corresponding dimensions depending on the prediction mode and on
|
|
||||||
parameter \code{strict_shape} as follows:
|
|
||||||
|
|
||||||
If passing \code{strict_shape=FALSE}:\itemize{
|
|
||||||
\item For regression or binary classification: a vector of length \code{nrows}.
|
|
||||||
\item For multi-class and multi-target objectives: a matrix of dimensions \verb{[nrows, ngroups]}.
|
|
||||||
|
|
||||||
Note that objective variant \code{multi:softmax} defaults towards predicting most likely class (a vector
|
|
||||||
\code{nrows}) instead of per-class probabilities.
|
|
||||||
\item For \code{predleaf}: a matrix with one column per tree.
|
|
||||||
|
|
||||||
For multi-class / multi-target, they will be arranged so that columns in the output will have
|
|
||||||
the leafs from one group followed by leafs of the other group (e.g. order will be \code{group1:feat1},
|
|
||||||
\code{group1:feat2}, ..., \code{group2:feat1}, \code{group2:feat2}, ...).
|
|
||||||
\item For \code{predcontrib}: when not multi-class / multi-target, a matrix with dimensions
|
|
||||||
\verb{[nrows, nfeats+1]}. The last "+ 1" column corresponds to the baseline value.
|
|
||||||
|
|
||||||
For multi-class and multi-target objectives, will be an array with dimensions \verb{[nrows, ngroups, nfeats+1]}.
|
|
||||||
|
|
||||||
The contribution values are on the scale of untransformed margin (e.g., for binary classification,
|
|
||||||
the values are log-odds deviations from the baseline).
|
|
||||||
\item For \code{predinteraction}: when not multi-class / multi-target, the output is a 3D array of
|
|
||||||
dimensions \verb{[nrows, nfeats+1, nfeats+1]}. The off-diagonal (in the last two dimensions)
|
|
||||||
elements represent different feature interaction contributions. The array is symmetric w.r.t. the last
|
|
||||||
two dimensions. The "+ 1" columns corresponds to the baselines. Summing this array along the last
|
|
||||||
dimension should produce practically the same result as \code{predcontrib = TRUE}.
|
|
||||||
|
|
||||||
For multi-class and multi-target, will be a 4D array with dimensions \verb{[nrows, ngroups, nfeats+1, nfeats+1]}
|
|
||||||
}
|
|
||||||
|
|
||||||
If passing \code{strict_shape=FALSE}, the result is always an array:
|
|
||||||
\itemize{
|
|
||||||
\item For normal predictions, the dimension is \verb{[nrows, ngroups]}.
|
|
||||||
\item For \code{predcontrib=TRUE}, the dimension is \verb{[nrows, ngroups, nfeats+1]}.
|
|
||||||
\item For \code{predinteraction=TRUE}, the dimension is \verb{[nrows, ngroups, nfeats+1, nfeats+1]}.
|
|
||||||
\item For \code{predleaf=TRUE}, the dimension is \verb{[nrows, niter, ngroups, num_parallel_tree]}.
|
|
||||||
}
|
|
||||||
|
|
||||||
If passing \code{avoid_transpose=TRUE}, then the dimensions in all cases will be in reverse order - for
|
|
||||||
example, for \code{predinteraction}, they will be \verb{[nfeats+1, nfeats+1, ngroups, nrows]}
|
|
||||||
instead of \verb{[nrows, ngroups, nfeats+1, nfeats+1]}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Predict values on data based on XGBoost model.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Note that \code{iterationrange} 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]{xgb.create.features()}}.
|
|
||||||
|
|
||||||
Setting \code{predcontrib = TRUE} allows to calculate contributions of each feature to
|
|
||||||
individual predictions. For "gblinear" booster, feature contributions are simply linear terms
|
|
||||||
(feature_beta * feature_value). For "gbtree" booster, feature contributions are SHAP
|
|
||||||
values (Lundberg 2017) that sum to the difference between the expected output
|
|
||||||
of the model and the current prediction (where the hessian weights are used to compute the expectations).
|
|
||||||
Setting \code{approxcontrib = TRUE} approximates these values following the idea explained
|
|
||||||
in \url{http://blog.datadive.net/interpreting-random-forests/}.
|
|
||||||
|
|
||||||
With \code{predinteraction = TRUE}, SHAP values of contributions of interaction of each pair of features
|
|
||||||
are computed. Note that this operation might be rather expensive in terms of compute and memory.
|
|
||||||
Since it quadratically depends on the number of features, it is recommended to perform selection
|
|
||||||
of the most important features first. See below about the format of the returned results.
|
|
||||||
|
|
||||||
The \code{predict()} method uses as many threads as defined in \code{xgb.Booster} object (all by default).
|
|
||||||
If you want to change their number, assign a new number to \code{nthread} using \code{\link[=xgb.parameters<-]{xgb.parameters<-()}}.
|
|
||||||
Note that converting a matrix to \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} uses multiple threads too.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
## binary classification:
|
|
||||||
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
data(agaricus.test, package = "xgboost")
|
|
||||||
|
|
||||||
## Keep the number of threads to 2 for examples
|
|
||||||
nthread <- 2
|
|
||||||
data.table::setDTthreads(nthread)
|
|
||||||
|
|
||||||
train <- agaricus.train
|
|
||||||
test <- agaricus.test
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
max_depth = 2,
|
|
||||||
eta = 0.5,
|
|
||||||
nthread = nthread,
|
|
||||||
nrounds = 5,
|
|
||||||
objective = "binary:logistic"
|
|
||||||
)
|
|
||||||
|
|
||||||
# use all trees by default
|
|
||||||
pred <- predict(bst, test$data)
|
|
||||||
# use only the 1st tree
|
|
||||||
pred1 <- predict(bst, test$data, iterationrange = c(1, 1))
|
|
||||||
|
|
||||||
# Predicting tree leafs:
|
|
||||||
# the result is an nsamples X ntrees matrix
|
|
||||||
pred_leaf <- predict(bst, test$data, predleaf = TRUE)
|
|
||||||
str(pred_leaf)
|
|
||||||
|
|
||||||
# Predicting feature contributions to predictions:
|
|
||||||
# the result is an nsamples X (nfeatures + 1) matrix
|
|
||||||
pred_contr <- predict(bst, test$data, predcontrib = TRUE)
|
|
||||||
str(pred_contr)
|
|
||||||
# verify that contributions' sums are equal to log-odds of predictions (up to float precision):
|
|
||||||
summary(rowSums(pred_contr) - qlogis(pred))
|
|
||||||
# for the 1st record, let's inspect its features that had non-zero contribution to prediction:
|
|
||||||
contr1 <- pred_contr[1,]
|
|
||||||
contr1 <- contr1[-length(contr1)] # drop intercept
|
|
||||||
contr1 <- contr1[contr1 != 0] # drop non-contributing features
|
|
||||||
contr1 <- contr1[order(abs(contr1))] # order by contribution magnitude
|
|
||||||
old_mar <- par("mar")
|
|
||||||
par(mar = old_mar + c(0,7,0,0))
|
|
||||||
barplot(contr1, horiz = TRUE, las = 2, xlab = "contribution to prediction in log-odds")
|
|
||||||
par(mar = old_mar)
|
|
||||||
|
|
||||||
|
|
||||||
## multiclass classification in iris dataset:
|
|
||||||
|
|
||||||
lb <- as.numeric(iris$Species) - 1
|
|
||||||
num_class <- 3
|
|
||||||
|
|
||||||
set.seed(11)
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(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)
|
|
||||||
# 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 with predictions from softmax:
|
|
||||||
set.seed(11)
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(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]), iterationrange = c(1, 5))
|
|
||||||
sum(pred5 != lb) / length(lb)
|
|
||||||
|
|
||||||
}
|
|
||||||
\references{
|
|
||||||
\enumerate{
|
|
||||||
\item Scott M. Lundberg, Su-In Lee, "A Unified Approach to Interpreting Model Predictions",
|
|
||||||
NIPS Proceedings 2017, \url{https://arxiv.org/abs/1705.07874}
|
|
||||||
\item Scott M. Lundberg, Su-In Lee, "Consistent feature attribution for tree ensembles",
|
|
||||||
\url{https://arxiv.org/abs/1706.06060}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.train]{xgb.train()}}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
% 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, ...)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{x}{An \code{xgb.Booster} object.}
|
|
||||||
|
|
||||||
\item{...}{Not used.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
The same \code{x} object, returned invisibly
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Print information about \code{xgb.Booster}.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
train <- agaricus.train
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
max_depth = 2,
|
|
||||||
eta = 1,
|
|
||||||
nthread = 2,
|
|
||||||
nrounds = 2,
|
|
||||||
objective = "binary:logistic"
|
|
||||||
)
|
|
||||||
|
|
||||||
attr(bst, "myattr") <- "memo"
|
|
||||||
|
|
||||||
print(bst)
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
% 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")
|
|
||||||
|
|
||||||
dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
dtrain
|
|
||||||
|
|
||||||
print(dtrain, verbose = TRUE)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
% 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{\link[=xgb.cv]{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 = xgb.DMatrix(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,22 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R
|
|
||||||
\name{variable.names.xgb.Booster}
|
|
||||||
\alias{variable.names.xgb.Booster}
|
|
||||||
\title{Get Features Names from Booster}
|
|
||||||
\usage{
|
|
||||||
\method{variable.names}{xgb.Booster}(object, ...)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{An \code{xgb.Booster} object.}
|
|
||||||
|
|
||||||
\item{...}{Not used.}
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Returns the feature / variable / column names from a fitted
|
|
||||||
booster object, which are set automatically during the call to \code{\link[=xgb.train]{xgb.train()}}
|
|
||||||
from the DMatrix names, or which can be set manually through \code{\link[=setinfo]{setinfo()}}.
|
|
||||||
|
|
||||||
If the object doesn't have feature names, will return \code{NULL}.
|
|
||||||
|
|
||||||
It is equivalent to calling \code{getinfo(object, "feature_name")}.
|
|
||||||
}
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.Callback}
|
|
||||||
\alias{xgb.Callback}
|
|
||||||
\title{XGBoost Callback Constructor}
|
|
||||||
\usage{
|
|
||||||
xgb.Callback(
|
|
||||||
cb_name = "custom_callback",
|
|
||||||
env = new.env(),
|
|
||||||
f_before_training = function(env, model, data, evals, begin_iteration, end_iteration)
|
|
||||||
NULL,
|
|
||||||
f_before_iter = function(env, model, data, evals, iteration) NULL,
|
|
||||||
f_after_iter = function(env, model, data, evals, iteration, iter_feval) NULL,
|
|
||||||
f_after_training = function(env, model, data, evals, iteration, final_feval,
|
|
||||||
prev_cb_res) NULL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{cb_name}{Name for the callback.
|
|
||||||
|
|
||||||
If the callback produces some non-NULL result (from executing the function passed under
|
|
||||||
\code{f_after_training}), that result will be added as an R attribute to the resulting booster
|
|
||||||
(or as a named element in the result of CV), with the attribute name specified here.
|
|
||||||
|
|
||||||
Names of callbacks must be unique - i.e. there cannot be two callbacks with the same name.}
|
|
||||||
|
|
||||||
\item{env}{An environment object that will be passed to the different functions in the callback.
|
|
||||||
Note that this environment will not be shared with other callbacks.}
|
|
||||||
|
|
||||||
\item{f_before_training}{A function that will be executed before the training has started.
|
|
||||||
|
|
||||||
If passing \code{NULL} for this or for the other function inputs, then no function will be executed.
|
|
||||||
|
|
||||||
If passing a function, it will be called with parameters supplied as non-named arguments
|
|
||||||
matching the function signatures that are shown in the default value for each function argument.}
|
|
||||||
|
|
||||||
\item{f_before_iter}{A function that will be executed before each boosting round.
|
|
||||||
|
|
||||||
This function can signal whether the training should be finalized or not, by outputting
|
|
||||||
a value that evaluates to \code{TRUE} - i.e. if the output from the function provided here at
|
|
||||||
a given round is \code{TRUE}, then training will be stopped before the current iteration happens.
|
|
||||||
|
|
||||||
Return values of \code{NULL} will be interpreted as \code{FALSE}.}
|
|
||||||
|
|
||||||
\item{f_after_iter}{A function that will be executed after each boosting round.
|
|
||||||
|
|
||||||
This function can signal whether the training should be finalized or not, by outputting
|
|
||||||
a value that evaluates to \code{TRUE} - i.e. if the output from the function provided here at
|
|
||||||
a given round is \code{TRUE}, then training will be stopped at that round.
|
|
||||||
|
|
||||||
Return values of \code{NULL} will be interpreted as \code{FALSE}.}
|
|
||||||
|
|
||||||
\item{f_after_training}{A function that will be executed after training is finished.
|
|
||||||
|
|
||||||
This function can optionally output something non-NULL, which will become part of the R
|
|
||||||
attributes of the booster (assuming one passes \code{keep_extra_attributes=TRUE} to \code{\link[=xgb.train]{xgb.train()}})
|
|
||||||
under the name supplied for parameter \code{cb_name} imn the case of \code{\link[=xgb.train]{xgb.train()}}; or a part
|
|
||||||
of the named elements in the result of \code{\link[=xgb.cv]{xgb.cv()}}.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Constructor for defining the structure of callback functions that can be executed
|
|
||||||
at different stages of model training (before / after training, before / after each boosting
|
|
||||||
iteration).
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Arguments that will be passed to the supplied functions are as follows:
|
|
||||||
\itemize{
|
|
||||||
\item env The same environment that is passed under argument \code{env}.
|
|
||||||
|
|
||||||
It may be modified by the functions in order to e.g. keep tracking of what happens
|
|
||||||
across iterations or similar.
|
|
||||||
|
|
||||||
This environment is only used by the functions supplied to the callback, and will
|
|
||||||
not be kept after the model fitting function terminates (see parameter \code{f_after_training}).
|
|
||||||
\item model The booster object when using \code{\link[=xgb.train]{xgb.train()}}, or the folds when using \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
|
|
||||||
For \code{\link[=xgb.cv]{xgb.cv()}}, folds are a list with a structure as follows:
|
|
||||||
\itemize{
|
|
||||||
\item \code{dtrain}: The training data for the fold (as an \code{xgb.DMatrix} object).
|
|
||||||
\item \code{bst}: Rhe \code{xgb.Booster} object for the fold.
|
|
||||||
\item \code{evals}: A list containing two DMatrices, with names \code{train} and \code{test}
|
|
||||||
(\code{test} is the held-out data for the fold).
|
|
||||||
\item \code{index}: The indices of the hold-out data for that fold (base-1 indexing),
|
|
||||||
from which the \code{test} entry in \code{evals} was obtained.
|
|
||||||
}
|
|
||||||
|
|
||||||
This object should \strong{not} be in-place modified in ways that conflict with the
|
|
||||||
training (e.g. resetting the parameters for a training update in a way that resets
|
|
||||||
the number of rounds to zero in order to overwrite rounds).
|
|
||||||
|
|
||||||
Note that any R attributes that are assigned to the booster during the callback functions,
|
|
||||||
will not be kept thereafter as the booster object variable is not re-assigned during
|
|
||||||
training. It is however possible to set C-level attributes of the booster through
|
|
||||||
\code{\link[=xgb.attr]{xgb.attr()}} or \code{\link[=xgb.attributes]{xgb.attributes()}}, which should remain available for the rest
|
|
||||||
of the iterations and after the training is done.
|
|
||||||
|
|
||||||
For keeping variables across iterations, it's recommended to use \code{env} instead.
|
|
||||||
\item data The data to which the model is being fit, as an \code{xgb.DMatrix} object.
|
|
||||||
|
|
||||||
Note that, for \code{\link[=xgb.cv]{xgb.cv()}}, this will be the full data, while data for the specific
|
|
||||||
folds can be found in the \code{model} object.
|
|
||||||
\item evals The evaluation data, as passed under argument \code{evals} to \code{\link[=xgb.train]{xgb.train()}}.
|
|
||||||
|
|
||||||
For \code{\link[=xgb.cv]{xgb.cv()}}, this will always be \code{NULL}.
|
|
||||||
\item begin_iteration Index of the first boosting iteration that will be executed (base-1 indexing).
|
|
||||||
|
|
||||||
This will typically be '1', but when using training continuation, depending on the
|
|
||||||
parameters for updates, boosting rounds will be continued from where the previous
|
|
||||||
model ended, in which case this will be larger than 1.
|
|
||||||
\item end_iteration Index of the last boostign iteration that will be executed
|
|
||||||
(base-1 indexing, inclusive of this end).
|
|
||||||
|
|
||||||
It should match with argument \code{nrounds} passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
|
|
||||||
Note that boosting might be interrupted before reaching this last iteration, for
|
|
||||||
example by using the early stopping callback \code{\link[=xgb.cb.early.stop]{xgb.cb.early.stop()}}.
|
|
||||||
\item iteration Index of the iteration number that is being executed (first iteration
|
|
||||||
will be the same as parameter \code{begin_iteration}, then next one will add +1, and so on).
|
|
||||||
\item iter_feval Evaluation metrics for \code{evals} that were supplied, either
|
|
||||||
determined by the objective, or by parameter \code{feval}.
|
|
||||||
|
|
||||||
For \code{\link[=xgb.train]{xgb.train()}}, this will be a named vector with one entry per element in
|
|
||||||
\code{evals}, where the names are determined as 'evals name' + '-' + 'metric name' - for
|
|
||||||
example, if \code{evals} contains an entry named "tr" and the metric is "rmse",
|
|
||||||
this will be a one-element vector with name "tr-rmse".
|
|
||||||
|
|
||||||
For \code{\link[=xgb.cv]{xgb.cv()}}, this will be a 2d matrix with dimensions \verb{[length(evals), nfolds]},
|
|
||||||
where the row names will follow the same naming logic as the one-dimensional vector
|
|
||||||
that is passed in \code{\link[=xgb.train]{xgb.train()}}.
|
|
||||||
|
|
||||||
Note that, internally, the built-in callbacks such as \link{xgb.cb.print.evaluation} summarize
|
|
||||||
this table by calculating the row-wise means and standard deviations.
|
|
||||||
\item final_feval The evaluation results after the last boosting round is executed
|
|
||||||
(same format as \code{iter_feval}, and will be the exact same input as passed under
|
|
||||||
\code{iter_feval} to the last round that is executed during model fitting).
|
|
||||||
\item prev_cb_res Result from a previous run of a callback sharing the same name
|
|
||||||
(as given by parameter \code{cb_name}) when conducting training continuation, if there
|
|
||||||
was any in the booster R attributes.
|
|
||||||
|
|
||||||
Sometimes, one might want to append the new results to the previous one, and this will
|
|
||||||
be done automatically by the built-in callbacks such as \link{xgb.cb.evaluation.log},
|
|
||||||
which will append the new rows to the previous table.
|
|
||||||
|
|
||||||
If no such previous callback result is available (which it never will when fitting
|
|
||||||
a model from start instead of updating an existing model), this will be \code{NULL}.
|
|
||||||
|
|
||||||
For \code{\link[=xgb.cv]{xgb.cv()}}, which doesn't support training continuation, this will always be \code{NULL}.
|
|
||||||
}
|
|
||||||
|
|
||||||
The following names (\code{cb_name} values) are reserved for internal callbacks:
|
|
||||||
\itemize{
|
|
||||||
\item print_evaluation
|
|
||||||
\item evaluation_log
|
|
||||||
\item reset_parameters
|
|
||||||
\item early_stop
|
|
||||||
\item save_model
|
|
||||||
\item cv_predict
|
|
||||||
\item gblinear_history
|
|
||||||
}
|
|
||||||
|
|
||||||
The following names are reserved for other non-callback attributes:
|
|
||||||
\itemize{
|
|
||||||
\item names
|
|
||||||
\item class
|
|
||||||
\item call
|
|
||||||
\item params
|
|
||||||
\item niter
|
|
||||||
\item nfeatures
|
|
||||||
\item folds
|
|
||||||
}
|
|
||||||
|
|
||||||
When using the built-in early stopping callback (\link{xgb.cb.early.stop}), said callback
|
|
||||||
will always be executed before the others, as it sets some booster C-level attributes
|
|
||||||
that other callbacks might also use. Otherwise, the order of execution will match with
|
|
||||||
the order in which the callbacks are passed to the model fitting function.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
# Example constructing a custom callback that calculates
|
|
||||||
# squared error on the training data (no separate test set),
|
|
||||||
# and outputs the per-iteration results.
|
|
||||||
ssq_callback <- xgb.Callback(
|
|
||||||
cb_name = "ssq",
|
|
||||||
f_before_training = function(env, model, data, evals,
|
|
||||||
begin_iteration, end_iteration) {
|
|
||||||
# A vector to keep track of a number at each iteration
|
|
||||||
env$logs <- rep(NA_real_, end_iteration - begin_iteration + 1)
|
|
||||||
},
|
|
||||||
f_after_iter = function(env, model, data, evals, iteration, iter_feval) {
|
|
||||||
# This calculates the sum of squared errors on the training data.
|
|
||||||
# Note that this can be better done by passing an 'evals' entry,
|
|
||||||
# but this demonstrates a way in which callbacks can be structured.
|
|
||||||
pred <- predict(model, data)
|
|
||||||
err <- pred - getinfo(data, "label")
|
|
||||||
sq_err <- sum(err^2)
|
|
||||||
env$logs[iteration] <- sq_err
|
|
||||||
cat(
|
|
||||||
sprintf(
|
|
||||||
"Squared error at iteration \%d: \%.2f\n",
|
|
||||||
iteration, sq_err
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# A return value of 'TRUE' here would signal to finalize the training
|
|
||||||
return(FALSE)
|
|
||||||
},
|
|
||||||
f_after_training = function(env, model, data, evals, iteration,
|
|
||||||
final_feval, prev_cb_res) {
|
|
||||||
return(env$logs)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
data(mtcars)
|
|
||||||
|
|
||||||
y <- mtcars$mpg
|
|
||||||
x <- as.matrix(mtcars[, -1])
|
|
||||||
|
|
||||||
dm <- xgb.DMatrix(x, label = y, nthread = 1)
|
|
||||||
model <- xgb.train(
|
|
||||||
data = dm,
|
|
||||||
params = list(objective = "reg:squarederror", nthread = 1),
|
|
||||||
nrounds = 5,
|
|
||||||
callbacks = list(ssq_callback),
|
|
||||||
keep_extra_attributes = TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
# Result from 'f_after_iter' will be available as an attribute
|
|
||||||
attributes(model)$ssq
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
Built-in callbacks:
|
|
||||||
\itemize{
|
|
||||||
\item \link{xgb.cb.print.evaluation}
|
|
||||||
\item \link{xgb.cb.evaluation.log}
|
|
||||||
\item \link{xgb.cb.reset.parameters}
|
|
||||||
\item \link{xgb.cb.early.stop}
|
|
||||||
\item \link{xgb.cb.save.model}
|
|
||||||
\item \link{xgb.cb.cv.predict}
|
|
||||||
\item \link{xgb.cb.gblinear.history}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.DMatrix}
|
|
||||||
\alias{xgb.DMatrix}
|
|
||||||
\alias{xgb.QuantileDMatrix}
|
|
||||||
\title{Construct xgb.DMatrix object}
|
|
||||||
\usage{
|
|
||||||
xgb.DMatrix(
|
|
||||||
data,
|
|
||||||
label = NULL,
|
|
||||||
weight = NULL,
|
|
||||||
base_margin = NULL,
|
|
||||||
missing = NA,
|
|
||||||
silent = FALSE,
|
|
||||||
feature_names = colnames(data),
|
|
||||||
feature_types = NULL,
|
|
||||||
nthread = NULL,
|
|
||||||
group = NULL,
|
|
||||||
qid = NULL,
|
|
||||||
label_lower_bound = NULL,
|
|
||||||
label_upper_bound = NULL,
|
|
||||||
feature_weights = NULL,
|
|
||||||
data_split_mode = "row"
|
|
||||||
)
|
|
||||||
|
|
||||||
xgb.QuantileDMatrix(
|
|
||||||
data,
|
|
||||||
label = NULL,
|
|
||||||
weight = NULL,
|
|
||||||
base_margin = NULL,
|
|
||||||
missing = NA,
|
|
||||||
feature_names = colnames(data),
|
|
||||||
feature_types = NULL,
|
|
||||||
nthread = NULL,
|
|
||||||
group = NULL,
|
|
||||||
qid = NULL,
|
|
||||||
label_lower_bound = NULL,
|
|
||||||
label_upper_bound = NULL,
|
|
||||||
feature_weights = NULL,
|
|
||||||
ref = NULL,
|
|
||||||
max_bin = NULL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{data}{Data from which to create a DMatrix, which can then be used for fitting models or
|
|
||||||
for getting predictions out of a fitted model.
|
|
||||||
|
|
||||||
Supported input types are as follows:\itemize{
|
|
||||||
\item \code{matrix} objects, with types \code{numeric}, \code{integer}, or \code{logical}.
|
|
||||||
\item \code{data.frame} objects, with columns of types \code{numeric}, \code{integer}, \code{logical}, or \code{factor}.
|
|
||||||
|
|
||||||
Note that xgboost uses base-0 encoding for categorical types, hence \code{factor} types (which use base-1
|
|
||||||
encoding') will be converted inside the function call. Be aware that the encoding used for \code{factor}
|
|
||||||
types is not kept as part of the model, so in subsequent calls to \code{predict}, it is the user's
|
|
||||||
responsibility to ensure that factor columns have the same levels as the ones from which the DMatrix
|
|
||||||
was constructed.
|
|
||||||
|
|
||||||
Other column types are not supported.
|
|
||||||
\item CSR matrices, as class \code{dgRMatrix} from package \code{Matrix}.
|
|
||||||
\item CSC matrices, as class \code{dgCMatrix} from package \code{Matrix}. These are \strong{not} supported for
|
|
||||||
'xgb.QuantileDMatrix'.
|
|
||||||
\item Single-row CSR matrices, as class \code{dsparseVector} from package \code{Matrix}, which is interpreted
|
|
||||||
as a single row (only when making predictions from a fitted model).
|
|
||||||
\item Text files in a supported format, passed as a \code{character} variable containing the URI path to
|
|
||||||
the file, with an optional format specifier.
|
|
||||||
|
|
||||||
These are \strong{not} supported for \code{xgb.QuantileDMatrix}. Supported formats are:\itemize{
|
|
||||||
\item XGBoost's own binary format for DMatrices, as produced by \code{\link[=xgb.DMatrix.save]{xgb.DMatrix.save()}}.
|
|
||||||
\item SVMLight (a.k.a. LibSVM) format for CSR matrices. This format can be signaled by suffix
|
|
||||||
\code{?format=libsvm} at the end of the file path. It will be the default format if not
|
|
||||||
otherwise specified.
|
|
||||||
\item CSV files (comma-separated values). This format can be specified by adding suffix
|
|
||||||
\code{?format=csv} at the end ofthe file path. It will \strong{not} be auto-deduced from file extensions.
|
|
||||||
}
|
|
||||||
|
|
||||||
Be aware that the format of the file will not be auto-deduced - for example, if a file is named 'file.csv',
|
|
||||||
it will not look at the extension or file contents to determine that it is a comma-separated value.
|
|
||||||
Instead, the format must be specified following the URI format, so the input to \code{data} should be passed
|
|
||||||
like this: \code{"file.csv?format=csv"} (or \code{"file.csv?format=csv&label_column=0"} if the first column
|
|
||||||
corresponds to the labels).
|
|
||||||
|
|
||||||
For more information about passing text files as input, see the articles
|
|
||||||
\href{https://xgboost.readthedocs.io/en/stable/tutorials/input_format.html}{Text Input Format of DMatrix} and
|
|
||||||
\href{https://xgboost.readthedocs.io/en/stable/python/python_intro.html#python-data-interface}{Data Interface}.
|
|
||||||
}}
|
|
||||||
|
|
||||||
\item{label}{Label of the training data. For classification problems, should be passed encoded as
|
|
||||||
integers with numeration starting at zero.}
|
|
||||||
|
|
||||||
\item{weight}{Weight for each instance.
|
|
||||||
|
|
||||||
Note that, for ranking task, weights are per-group. In ranking task, one weight
|
|
||||||
is assigned to each group (not each data point). This is because we
|
|
||||||
only care about the relative ordering of data points within each group,
|
|
||||||
so it doesn't make sense to assign weights to individual data points.}
|
|
||||||
|
|
||||||
\item{base_margin}{Base margin used for boosting from existing model.
|
|
||||||
|
|
||||||
In the case of multi-output models, one can also pass multi-dimensional base_margin.}
|
|
||||||
|
|
||||||
\item{missing}{A float value to represents missing values in data (not used when creating DMatrix
|
|
||||||
from text files). It is useful to change when a zero, infinite, or some other
|
|
||||||
extreme value represents missing values in data.}
|
|
||||||
|
|
||||||
\item{silent}{whether to suppress printing an informational message after loading from a file.}
|
|
||||||
|
|
||||||
\item{feature_names}{Set names for features. Overrides column names in data frame and matrix.
|
|
||||||
|
|
||||||
Note: columns are not referenced by name when calling \code{predict}, so the column order there
|
|
||||||
must be the same as in the DMatrix construction, regardless of the column names.}
|
|
||||||
|
|
||||||
\item{feature_types}{Set types for features.
|
|
||||||
|
|
||||||
If \code{data} is a \code{data.frame} and passing \code{feature_types} is not supplied,
|
|
||||||
feature types will be deduced automatically from the column types.
|
|
||||||
|
|
||||||
Otherwise, one can pass a character vector with the same length as number of columns in \code{data},
|
|
||||||
with the following possible values:
|
|
||||||
\itemize{
|
|
||||||
\item "c", which represents categorical columns.
|
|
||||||
\item "q", which represents numeric columns.
|
|
||||||
\item "int", which represents integer columns.
|
|
||||||
\item "i", which represents logical (boolean) columns.
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that, while categorical types are treated differently from the rest for model fitting
|
|
||||||
purposes, the other types do not influence the generated model, but have effects in other
|
|
||||||
functionalities such as feature importances.
|
|
||||||
|
|
||||||
\strong{Important}: Categorical features, if specified manually through \code{feature_types}, must
|
|
||||||
be encoded as integers with numeration starting at zero, and the same encoding needs to be
|
|
||||||
applied when passing data to \code{\link[=predict]{predict()}}. Even if passing \code{factor} types, the encoding will
|
|
||||||
not be saved, so make sure that \code{factor} columns passed to \code{predict} have the same \code{levels}.}
|
|
||||||
|
|
||||||
\item{nthread}{Number of threads used for creating DMatrix.}
|
|
||||||
|
|
||||||
\item{group}{Group size for all ranking group.}
|
|
||||||
|
|
||||||
\item{qid}{Query ID for data samples, used for ranking.}
|
|
||||||
|
|
||||||
\item{label_lower_bound}{Lower bound for survival training.}
|
|
||||||
|
|
||||||
\item{label_upper_bound}{Upper bound for survival training.}
|
|
||||||
|
|
||||||
\item{feature_weights}{Set feature weights for column sampling.}
|
|
||||||
|
|
||||||
\item{data_split_mode}{When passing a URI (as R \code{character}) as input, this signals
|
|
||||||
whether to split by row or column. Allowed values are \code{"row"} and \code{"col"}.
|
|
||||||
|
|
||||||
In distributed mode, the file is split accordingly; otherwise this is only an indicator on
|
|
||||||
how the file was split beforehand. Default to row.
|
|
||||||
|
|
||||||
This is not used when \code{data} is not a URI.}
|
|
||||||
|
|
||||||
\item{ref}{The training dataset that provides quantile information, needed when creating
|
|
||||||
validation/test dataset with \code{\link[=xgb.QuantileDMatrix]{xgb.QuantileDMatrix()}}. Supplying the training DMatrix
|
|
||||||
as a reference means that the same quantisation applied to the training data is
|
|
||||||
applied to the validation/test data}
|
|
||||||
|
|
||||||
\item{max_bin}{The number of histogram bin, should be consistent with the training parameter
|
|
||||||
\code{max_bin}.
|
|
||||||
|
|
||||||
This is only supported when constructing a QuantileDMatrix.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An 'xgb.DMatrix' object. If calling 'xgb.QuantileDMatrix', it will have additional
|
|
||||||
subclass 'xgb.QuantileDMatrix'.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Construct an 'xgb.DMatrix' object from a given data source, which can then be passed to functions
|
|
||||||
such as \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=predict]{predict()}}.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Function \code{xgb.QuantileDMatrix()} will construct a DMatrix with quantization for the histogram
|
|
||||||
method already applied to it, which can be used to reduce memory usage (compared to using a
|
|
||||||
a regular DMatrix first and then creating a quantization out of it) when using the histogram
|
|
||||||
method (\code{tree_method = "hist"}, which is the default algorithm), but is not usable for the
|
|
||||||
sorted-indices method (\code{tree_method = "exact"}), nor for the approximate method
|
|
||||||
(\code{tree_method = "approx"}).
|
|
||||||
|
|
||||||
Note that DMatrix objects are not serializable through R functions such as \code{\link[=saveRDS]{saveRDS()}} or \code{\link[=save]{save()}}.
|
|
||||||
If a DMatrix gets serialized and then de-serialized (for example, when saving data in an R session or caching
|
|
||||||
chunks in an Rmd file), the resulting object will not be usable anymore and will need to be reconstructed
|
|
||||||
from the original source of data.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
## Keep the number of threads to 1 for examples
|
|
||||||
nthread <- 1
|
|
||||||
data.table::setDTthreads(nthread)
|
|
||||||
dtrain <- with(
|
|
||||||
agaricus.train, xgb.DMatrix(data, label = label, nthread = nthread)
|
|
||||||
)
|
|
||||||
fname <- file.path(tempdir(), "xgb.DMatrix.data")
|
|
||||||
xgb.DMatrix.save(dtrain, fname)
|
|
||||||
dtrain <- xgb.DMatrix(fname)
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.DMatrix.hasinfo}
|
|
||||||
\alias{xgb.DMatrix.hasinfo}
|
|
||||||
\title{Check whether DMatrix object has a field}
|
|
||||||
\usage{
|
|
||||||
xgb.DMatrix.hasinfo(object, info)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{The DMatrix object to check for the given \code{info} field.}
|
|
||||||
|
|
||||||
\item{info}{The field to check for presence or absence in \code{object}.}
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Checks whether an xgb.DMatrix object has a given field assigned to
|
|
||||||
it, such as weights, labels, etc.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
x <- matrix(1:10, nrow = 5)
|
|
||||||
dm <- xgb.DMatrix(x, nthread = 1)
|
|
||||||
|
|
||||||
# 'dm' so far does not have any fields set
|
|
||||||
xgb.DMatrix.hasinfo(dm, "label")
|
|
||||||
|
|
||||||
# Fields can be added after construction
|
|
||||||
setinfo(dm, "label", 1:5)
|
|
||||||
xgb.DMatrix.hasinfo(dm, "label")
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.DMatrix]{xgb.DMatrix()}}, \code{\link[=getinfo.xgb.DMatrix]{getinfo.xgb.DMatrix()}}, \code{\link[=setinfo.xgb.DMatrix]{setinfo.xgb.DMatrix()}}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
% 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)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{dmatrix}{the \code{xgb.DMatrix} object}
|
|
||||||
|
|
||||||
\item{fname}{the name of the file to write.}
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Save xgb.DMatrix object to binary file
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
\dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
fname <- file.path(tempdir(), "xgb.DMatrix.data")
|
|
||||||
xgb.DMatrix.save(dtrain, fname)
|
|
||||||
dtrain <- xgb.DMatrix(fname)
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.DataBatch}
|
|
||||||
\alias{xgb.DataBatch}
|
|
||||||
\title{Structure for Data Batches}
|
|
||||||
\usage{
|
|
||||||
xgb.DataBatch(
|
|
||||||
data,
|
|
||||||
label = NULL,
|
|
||||||
weight = NULL,
|
|
||||||
base_margin = NULL,
|
|
||||||
feature_names = colnames(data),
|
|
||||||
feature_types = NULL,
|
|
||||||
group = NULL,
|
|
||||||
qid = NULL,
|
|
||||||
label_lower_bound = NULL,
|
|
||||||
label_upper_bound = NULL,
|
|
||||||
feature_weights = NULL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{data}{Batch of data belonging to this batch.
|
|
||||||
|
|
||||||
Note that not all of the input types supported by \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} are possible
|
|
||||||
to pass here. Supported types are:
|
|
||||||
\itemize{
|
|
||||||
\item \code{matrix}, with types \code{numeric}, \code{integer}, and \code{logical}. Note that for types
|
|
||||||
\code{integer} and \code{logical}, missing values might not be automatically recognized as
|
|
||||||
as such - see the documentation for parameter \code{missing} in \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}
|
|
||||||
for details on this.
|
|
||||||
\item \code{data.frame}, with the same types as supported by 'xgb.DMatrix' and same
|
|
||||||
conversions applied to it. See the documentation for parameter \code{data} in
|
|
||||||
\code{\link[=xgb.DMatrix]{xgb.DMatrix()}} for details on it.
|
|
||||||
\item CSR matrices, as class \code{dgRMatrix} from package "Matrix".
|
|
||||||
}}
|
|
||||||
|
|
||||||
\item{label}{Label of the training data. For classification problems, should be passed encoded as
|
|
||||||
integers with numeration starting at zero.}
|
|
||||||
|
|
||||||
\item{weight}{Weight for each instance.
|
|
||||||
|
|
||||||
Note that, for ranking task, weights are per-group. In ranking task, one weight
|
|
||||||
is assigned to each group (not each data point). This is because we
|
|
||||||
only care about the relative ordering of data points within each group,
|
|
||||||
so it doesn't make sense to assign weights to individual data points.}
|
|
||||||
|
|
||||||
\item{base_margin}{Base margin used for boosting from existing model.
|
|
||||||
|
|
||||||
In the case of multi-output models, one can also pass multi-dimensional base_margin.}
|
|
||||||
|
|
||||||
\item{feature_names}{Set names for features. Overrides column names in data frame and matrix.
|
|
||||||
|
|
||||||
Note: columns are not referenced by name when calling \code{predict}, so the column order there
|
|
||||||
must be the same as in the DMatrix construction, regardless of the column names.}
|
|
||||||
|
|
||||||
\item{feature_types}{Set types for features.
|
|
||||||
|
|
||||||
If \code{data} is a \code{data.frame} and passing \code{feature_types} is not supplied,
|
|
||||||
feature types will be deduced automatically from the column types.
|
|
||||||
|
|
||||||
Otherwise, one can pass a character vector with the same length as number of columns in \code{data},
|
|
||||||
with the following possible values:
|
|
||||||
\itemize{
|
|
||||||
\item "c", which represents categorical columns.
|
|
||||||
\item "q", which represents numeric columns.
|
|
||||||
\item "int", which represents integer columns.
|
|
||||||
\item "i", which represents logical (boolean) columns.
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that, while categorical types are treated differently from the rest for model fitting
|
|
||||||
purposes, the other types do not influence the generated model, but have effects in other
|
|
||||||
functionalities such as feature importances.
|
|
||||||
|
|
||||||
\strong{Important}: Categorical features, if specified manually through \code{feature_types}, must
|
|
||||||
be encoded as integers with numeration starting at zero, and the same encoding needs to be
|
|
||||||
applied when passing data to \code{\link[=predict]{predict()}}. Even if passing \code{factor} types, the encoding will
|
|
||||||
not be saved, so make sure that \code{factor} columns passed to \code{predict} have the same \code{levels}.}
|
|
||||||
|
|
||||||
\item{group}{Group size for all ranking group.}
|
|
||||||
|
|
||||||
\item{qid}{Query ID for data samples, used for ranking.}
|
|
||||||
|
|
||||||
\item{label_lower_bound}{Lower bound for survival training.}
|
|
||||||
|
|
||||||
\item{label_upper_bound}{Upper bound for survival training.}
|
|
||||||
|
|
||||||
\item{feature_weights}{Set feature weights for column sampling.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An object of class \code{xgb.DataBatch}, which is just a list containing the
|
|
||||||
data and parameters passed here. It does \strong{not} inherit from \code{xgb.DMatrix}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Helper function to supply data in batches of a data iterator when
|
|
||||||
constructing a DMatrix from external memory through \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}
|
|
||||||
or through \code{\link[=xgb.QuantileDMatrix.from_iterator]{xgb.QuantileDMatrix.from_iterator()}}.
|
|
||||||
|
|
||||||
This function is \strong{only} meant to be called inside of a callback function (which
|
|
||||||
is passed as argument to function \code{\link[=xgb.DataIter]{xgb.DataIter()}} to construct a data iterator)
|
|
||||||
when constructing a DMatrix through external memory - otherwise, one should call
|
|
||||||
\code{\link[=xgb.DMatrix]{xgb.DMatrix()}} or \code{\link[=xgb.QuantileDMatrix]{xgb.QuantileDMatrix()}}.
|
|
||||||
|
|
||||||
The object that results from calling this function directly is \strong{not} like
|
|
||||||
an \code{xgb.DMatrix} - i.e. cannot be used to train a model, nor to get predictions - only
|
|
||||||
possible usage is to supply data to an iterator, from which a DMatrix is then constructed.
|
|
||||||
|
|
||||||
For more information and for example usage, see the documentation for \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}.
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.DataIter]{xgb.DataIter()}}, \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}.
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.DataIter}
|
|
||||||
\alias{xgb.DataIter}
|
|
||||||
\title{XGBoost Data Iterator}
|
|
||||||
\usage{
|
|
||||||
xgb.DataIter(env = new.env(), f_next, f_reset)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{env}{An R environment to pass to the callback functions supplied here, which can be
|
|
||||||
used to keep track of variables to determine how to handle the batches.
|
|
||||||
|
|
||||||
For example, one might want to keep track of an iteration number in this environment in order
|
|
||||||
to know which part of the data to pass next.}
|
|
||||||
|
|
||||||
\item{f_next}{\verb{function(env)} which is responsible for:
|
|
||||||
\itemize{
|
|
||||||
\item Accessing or retrieving the next batch of data in the iterator.
|
|
||||||
\item Supplying this data by calling function \code{\link[=xgb.DataBatch]{xgb.DataBatch()}} on it and returning the result.
|
|
||||||
\item Keeping track of where in the iterator batch it is or will go next, which can for example
|
|
||||||
be done by modifiying variables in the \code{env} variable that is passed here.
|
|
||||||
\item Signaling whether there are more batches to be consumed or not, by returning \code{NULL}
|
|
||||||
when the stream of data ends (all batches in the iterator have been consumed), or the result from
|
|
||||||
calling \code{\link[=xgb.DataBatch]{xgb.DataBatch()}} when there are more batches in the line to be consumed.
|
|
||||||
}}
|
|
||||||
|
|
||||||
\item{f_reset}{\verb{function(env)} which is responsible for reseting the data iterator
|
|
||||||
(i.e. taking it back to the first batch, called before and after the sequence of batches
|
|
||||||
has been consumed).
|
|
||||||
|
|
||||||
Note that, after resetting the iterator, the batches will be accessed again, so the same data
|
|
||||||
(and in the same order) must be passed in subsequent iterations.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.DataIter} object, containing the same inputs supplied here, which can then
|
|
||||||
be passed to \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Interface to create a custom data iterator in order to construct a DMatrix
|
|
||||||
from external memory.
|
|
||||||
|
|
||||||
This function is responsible for generating an R object structure containing callback
|
|
||||||
functions and an environment shared with them.
|
|
||||||
|
|
||||||
The output structure from this function is then meant to be passed to \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}},
|
|
||||||
which will consume the data and create a DMatrix from it by executing the callback functions.
|
|
||||||
|
|
||||||
For more information, and for a usage example, see the documentation for \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}.
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}, \code{\link[=xgb.DataBatch]{xgb.DataBatch()}}.
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.ExtMemDMatrix}
|
|
||||||
\alias{xgb.ExtMemDMatrix}
|
|
||||||
\title{DMatrix from External Data}
|
|
||||||
\usage{
|
|
||||||
xgb.ExtMemDMatrix(
|
|
||||||
data_iterator,
|
|
||||||
cache_prefix = tempdir(),
|
|
||||||
missing = NA,
|
|
||||||
nthread = NULL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{data_iterator}{A data iterator structure as returned by \code{\link[=xgb.DataIter]{xgb.DataIter()}},
|
|
||||||
which includes an environment shared between function calls, and functions to access
|
|
||||||
the data in batches on-demand.}
|
|
||||||
|
|
||||||
\item{cache_prefix}{The path of cache file, caller must initialize all the directories in this path.}
|
|
||||||
|
|
||||||
\item{missing}{A float value to represents missing values in data.
|
|
||||||
|
|
||||||
Note that, while functions like \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} can take a generic \code{NA} and interpret it
|
|
||||||
correctly for different types like \code{numeric} and \code{integer}, if an \code{NA} value is passed here,
|
|
||||||
it will not be adapted for different input types.
|
|
||||||
|
|
||||||
For example, in R \code{integer} types, missing values are represented by integer number \code{-2147483648}
|
|
||||||
(since machine 'integer' types do not have an inherent 'NA' value) - hence, if one passes \code{NA},
|
|
||||||
which is interpreted as a floating-point NaN by \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}} and by
|
|
||||||
\code{\link[=xgb.QuantileDMatrix.from_iterator]{xgb.QuantileDMatrix.from_iterator()}}, these integer missing values will not be treated as missing.
|
|
||||||
This should not pose any problem for \code{numeric} types, since they do have an inheret NaN value.}
|
|
||||||
|
|
||||||
\item{nthread}{Number of threads used for creating DMatrix.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An 'xgb.DMatrix' object, with subclass 'xgb.ExtMemDMatrix', in which the data is not
|
|
||||||
held internally but accessed through the iterator when needed.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Create a special type of XGBoost 'DMatrix' object from external data
|
|
||||||
supplied by an \code{\link[=xgb.DataIter]{xgb.DataIter()}} object, potentially passed in batches from a
|
|
||||||
bigger set that might not fit entirely in memory.
|
|
||||||
|
|
||||||
The data supplied by the iterator is accessed on-demand as needed, multiple times,
|
|
||||||
without being concatenated, but note that fields like 'label' \strong{will} be
|
|
||||||
concatenated from multiple calls to the data iterator.
|
|
||||||
|
|
||||||
For more information, see the guide 'Using XGBoost External Memory Version':
|
|
||||||
\url{https://xgboost.readthedocs.io/en/stable/tutorials/external_memory.html}
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(mtcars)
|
|
||||||
|
|
||||||
# This custom environment will be passed to the iterator
|
|
||||||
# functions at each call. It is up to the user to keep
|
|
||||||
# track of the iteration number in this environment.
|
|
||||||
iterator_env <- as.environment(
|
|
||||||
list(
|
|
||||||
iter = 0,
|
|
||||||
x = mtcars[, -1],
|
|
||||||
y = mtcars[, 1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Data is passed in two batches.
|
|
||||||
# In this example, batches are obtained by subsetting the 'x' variable.
|
|
||||||
# This is not advantageous to do, since the data is already loaded in memory
|
|
||||||
# and can be passed in full in one go, but there can be situations in which
|
|
||||||
# only a subset of the data will fit in the computer's memory, and it can
|
|
||||||
# be loaded in batches that are accessed one-at-a-time only.
|
|
||||||
iterator_next <- function(iterator_env) {
|
|
||||||
curr_iter <- iterator_env[["iter"]]
|
|
||||||
if (curr_iter >= 2) {
|
|
||||||
# there are only two batches, so this signals end of the stream
|
|
||||||
return(NULL)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curr_iter == 0) {
|
|
||||||
x_batch <- iterator_env[["x"]][1:16, ]
|
|
||||||
y_batch <- iterator_env[["y"]][1:16]
|
|
||||||
} else {
|
|
||||||
x_batch <- iterator_env[["x"]][17:32, ]
|
|
||||||
y_batch <- iterator_env[["y"]][17:32]
|
|
||||||
}
|
|
||||||
on.exit({
|
|
||||||
iterator_env[["iter"]] <- curr_iter + 1
|
|
||||||
})
|
|
||||||
|
|
||||||
# Function 'xgb.DataBatch' must be called manually
|
|
||||||
# at each batch with all the appropriate attributes,
|
|
||||||
# such as feature names and feature types.
|
|
||||||
return(xgb.DataBatch(data = x_batch, label = y_batch))
|
|
||||||
}
|
|
||||||
|
|
||||||
# This moves the iterator back to its beginning
|
|
||||||
iterator_reset <- function(iterator_env) {
|
|
||||||
iterator_env[["iter"]] <- 0
|
|
||||||
}
|
|
||||||
|
|
||||||
data_iterator <- xgb.DataIter(
|
|
||||||
env = iterator_env,
|
|
||||||
f_next = iterator_next,
|
|
||||||
f_reset = iterator_reset
|
|
||||||
)
|
|
||||||
cache_prefix <- tempdir()
|
|
||||||
|
|
||||||
# DMatrix will be constructed from the iterator's batches
|
|
||||||
dm <- xgb.ExtMemDMatrix(data_iterator, cache_prefix, nthread = 1)
|
|
||||||
|
|
||||||
# After construction, can be used as a regular DMatrix
|
|
||||||
params <- list(nthread = 1, objective = "reg:squarederror")
|
|
||||||
model <- xgb.train(data = dm, nrounds = 2, params = params)
|
|
||||||
|
|
||||||
# Predictions can also be called on it, and should be the same
|
|
||||||
# as if the data were passed differently.
|
|
||||||
pred_dm <- predict(model, dm)
|
|
||||||
pred_mat <- predict(model, as.matrix(mtcars[, -1]))
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.DataIter]{xgb.DataIter()}}, \code{\link[=xgb.DataBatch]{xgb.DataBatch()}}, \code{\link[=xgb.QuantileDMatrix.from_iterator]{xgb.QuantileDMatrix.from_iterator()}}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.QuantileDMatrix.from_iterator}
|
|
||||||
\alias{xgb.QuantileDMatrix.from_iterator}
|
|
||||||
\title{QuantileDMatrix from External Data}
|
|
||||||
\usage{
|
|
||||||
xgb.QuantileDMatrix.from_iterator(
|
|
||||||
data_iterator,
|
|
||||||
missing = NA,
|
|
||||||
nthread = NULL,
|
|
||||||
ref = NULL,
|
|
||||||
max_bin = NULL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{data_iterator}{A data iterator structure as returned by \code{\link[=xgb.DataIter]{xgb.DataIter()}},
|
|
||||||
which includes an environment shared between function calls, and functions to access
|
|
||||||
the data in batches on-demand.}
|
|
||||||
|
|
||||||
\item{missing}{A float value to represents missing values in data.
|
|
||||||
|
|
||||||
Note that, while functions like \code{\link[=xgb.DMatrix]{xgb.DMatrix()}} can take a generic \code{NA} and interpret it
|
|
||||||
correctly for different types like \code{numeric} and \code{integer}, if an \code{NA} value is passed here,
|
|
||||||
it will not be adapted for different input types.
|
|
||||||
|
|
||||||
For example, in R \code{integer} types, missing values are represented by integer number \code{-2147483648}
|
|
||||||
(since machine 'integer' types do not have an inherent 'NA' value) - hence, if one passes \code{NA},
|
|
||||||
which is interpreted as a floating-point NaN by \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}} and by
|
|
||||||
\code{\link[=xgb.QuantileDMatrix.from_iterator]{xgb.QuantileDMatrix.from_iterator()}}, these integer missing values will not be treated as missing.
|
|
||||||
This should not pose any problem for \code{numeric} types, since they do have an inheret NaN value.}
|
|
||||||
|
|
||||||
\item{nthread}{Number of threads used for creating DMatrix.}
|
|
||||||
|
|
||||||
\item{ref}{The training dataset that provides quantile information, needed when creating
|
|
||||||
validation/test dataset with \code{\link[=xgb.QuantileDMatrix]{xgb.QuantileDMatrix()}}. Supplying the training DMatrix
|
|
||||||
as a reference means that the same quantisation applied to the training data is
|
|
||||||
applied to the validation/test data}
|
|
||||||
|
|
||||||
\item{max_bin}{The number of histogram bin, should be consistent with the training parameter
|
|
||||||
\code{max_bin}.
|
|
||||||
|
|
||||||
This is only supported when constructing a QuantileDMatrix.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An 'xgb.DMatrix' object, with subclass 'xgb.QuantileDMatrix'.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Create an \code{xgb.QuantileDMatrix} object (exact same class as would be returned by
|
|
||||||
calling function \code{\link[=xgb.QuantileDMatrix]{xgb.QuantileDMatrix()}}, with the same advantages and limitations) from
|
|
||||||
external data supplied by \code{\link[=xgb.DataIter]{xgb.DataIter()}}, potentially passed in batches from
|
|
||||||
a bigger set that might not fit entirely in memory, same way as \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}}.
|
|
||||||
|
|
||||||
Note that, while external data will only be loaded through the iterator (thus the full data
|
|
||||||
might not be held entirely in-memory), the quantized representation of the data will get
|
|
||||||
created in-memory, being concatenated from multiple calls to the data iterator. The quantized
|
|
||||||
version is typically lighter than the original data, so there might be cases in which this
|
|
||||||
representation could potentially fit in memory even if the full data does not.
|
|
||||||
|
|
||||||
For more information, see the guide 'Using XGBoost External Memory Version':
|
|
||||||
\url{https://xgboost.readthedocs.io/en/stable/tutorials/external_memory.html}
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\code{\link[=xgb.DataIter]{xgb.DataIter()}}, \code{\link[=xgb.DataBatch]{xgb.DataBatch()}}, \code{\link[=xgb.ExtMemDMatrix]{xgb.ExtMemDMatrix()}},
|
|
||||||
\code{\link[=xgb.QuantileDMatrix]{xgb.QuantileDMatrix()}}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
% 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}. \strong{Will be modified in-place} when assigning to it.}
|
|
||||||
|
|
||||||
\item{name}{A non-empty character string specifying which attribute is to be accessed.}
|
|
||||||
|
|
||||||
\item{value}{For \verb{xgb.attr<-}, a value of an attribute; for \verb{xgb.attributes<-},
|
|
||||||
it is 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 an attribute value is not a scalar, only the first index is used.
|
|
||||||
Use \code{NULL} to remove an attribute.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
\itemize{
|
|
||||||
\item \code{xgb.attr()} returns either a string value of an attribute
|
|
||||||
or \code{NULL} if an attribute wasn't stored in a model.
|
|
||||||
\item \code{xgb.attributes()} returns a list of all attributes 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{\link[=xgb.save]{xgb.save()}} because an XGBoost model is an external memory object
|
|
||||||
and its serialization is handled externally.
|
|
||||||
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<-]{xgb.parameters<-()}} to set or change model parameters.
|
|
||||||
|
|
||||||
The \verb{xgb.attributes<-} setter either updates the existing or adds one or several attributes,
|
|
||||||
but it doesn't delete the other existing attributes.
|
|
||||||
|
|
||||||
Important: since this modifies the booster's C object, semantics for assignment here
|
|
||||||
will differ from R's, as any object reference to the same booster will be modified
|
|
||||||
too, while assignment of R attributes through \verb{attributes(model)$<attr> <- <value>}
|
|
||||||
will follow the usual copy-on-write R semantics (see \code{\link[=xgb.copy.Booster]{xgb.copy.Booster()}} for an
|
|
||||||
example of these behaviors).
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
train <- agaricus.train
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(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")
|
|
||||||
|
|
||||||
fname <- file.path(tempdir(), "xgb.ubj")
|
|
||||||
xgb.save(bst, fname)
|
|
||||||
bst1 <- xgb.load(fname)
|
|
||||||
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))
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.cv.predict}
|
|
||||||
\alias{xgb.cb.cv.predict}
|
|
||||||
\title{Callback for returning cross-validation based predictions}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.cv.predict(save_models = FALSE, outputmargin = FALSE)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{save_models}{A flag for whether to save the folds' models.}
|
|
||||||
|
|
||||||
\item{outputmargin}{Whether to save margin predictions (same effect as passing this
|
|
||||||
parameter to \link{predict.xgb.Booster}).}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.cv]{xgb.cv()}},
|
|
||||||
but \strong{not} to \code{\link[=xgb.train]{xgb.train()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
This callback function saves predictions for all of the test folds,
|
|
||||||
and also allows to save the folds' models.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Predictions are saved 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{\link[=xgb.cv]{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-provided 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}.
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.early.stop}
|
|
||||||
\alias{xgb.cb.early.stop}
|
|
||||||
\title{Callback to activate early stopping}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.early.stop(
|
|
||||||
stopping_rounds,
|
|
||||||
maximize = FALSE,
|
|
||||||
metric_name = NULL,
|
|
||||||
verbose = TRUE,
|
|
||||||
keep_all_iter = 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{evals} 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{evals}, 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.}
|
|
||||||
|
|
||||||
\item{keep_all_iter}{Whether to keep all of the boosting rounds that were produced
|
|
||||||
in the resulting object. If passing \code{FALSE}, will only keep the boosting rounds
|
|
||||||
up to the detected best iteration, discarding the ones that come after.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
This callback function determines the condition for early stopping.
|
|
||||||
|
|
||||||
The following attributes are assigned to the booster's 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
|
|
||||||
(0-based index for interoperability of binary models)
|
|
||||||
}
|
|
||||||
|
|
||||||
The same values are also stored as R attributes as a result of the callback, plus an additional
|
|
||||||
attribute \code{stopped_by_max_rounds} which indicates whether an early stopping by the \code{stopping_rounds}
|
|
||||||
condition occurred. Note that the \code{best_iteration} that is stored under R attributes will follow
|
|
||||||
base-1 indexing, so it will be larger by '1' than the C-level 'best_iteration' that is accessed
|
|
||||||
through \code{\link[=xgb.attr]{xgb.attr()}} or \code{\link[=xgb.attributes]{xgb.attributes()}}.
|
|
||||||
|
|
||||||
At least one dataset is required in \code{evals} for early stopping to work.
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.evaluation.log}
|
|
||||||
\alias{xgb.cb.evaluation.log}
|
|
||||||
\title{Callback for logging the evaluation history}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.evaluation.log()
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Callback for logging the evaluation history
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
This callback creates a table with per-iteration evaluation metrics (see parameters
|
|
||||||
\code{evals} and \code{feval} in \code{\link[=xgb.train]{xgb.train()}}).
|
|
||||||
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\link{xgb.cb.print.evaluation}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.gblinear.history}
|
|
||||||
\alias{xgb.cb.gblinear.history}
|
|
||||||
\title{Callback for collecting coefficients history of a gblinear booster}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.gblinear.history(sparse = FALSE)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{sparse}{When set to \code{FALSE}/\code{TRUE}, a dense/sparse matrix is used to store the result.
|
|
||||||
Sparse format is useful when one expects only a subset of coefficients to be non-zero,
|
|
||||||
when using the "thrifty" feature selector with fairly small number of top features
|
|
||||||
selected per iteration.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Callback for collecting coefficients history of a gblinear booster
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
To keep things fast and simple, gblinear booster does not internally store the history of linear
|
|
||||||
model coefficients at each boosting iteration. This callback provides a workaround for storing
|
|
||||||
the coefficients' path, by extracting them after each training iteration.
|
|
||||||
|
|
||||||
This callback will construct a matrix where rows are boosting iterations and columns are
|
|
||||||
feature coefficients (same order as when calling \link{coef.xgb.Booster}, with the intercept
|
|
||||||
corresponding to the first column).
|
|
||||||
|
|
||||||
When there is more than one coefficient per feature (e.g. multi-class classification),
|
|
||||||
the result will be reshaped into a vector where coefficients are arranged first by features and
|
|
||||||
then by class (e.g. first 1 through N coefficients will be for the first class, then
|
|
||||||
coefficients N+1 through 2N for the second class, and so on).
|
|
||||||
|
|
||||||
If the result has only one coefficient per feature in the data, then the resulting matrix
|
|
||||||
will have column names matching with the feature names, otherwise (when there's more than
|
|
||||||
one coefficient per feature) the names will be composed as 'column name' + ':' + 'class index'
|
|
||||||
(so e.g. column 'c1' for class '0' will be named 'c1:0').
|
|
||||||
|
|
||||||
With \code{\link[=xgb.train]{xgb.train()}}, the output is either a dense or a sparse matrix.
|
|
||||||
With with \code{\link[=xgb.cv]{xgb.cv()}}, it is a list (one element per each fold) of such matrices.
|
|
||||||
|
|
||||||
Function \link{xgb.gblinear.history} provides an easy way to retrieve the
|
|
||||||
outputs from this callback.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
#### Binary classification:
|
|
||||||
|
|
||||||
## Keep the number of threads to 1 for examples
|
|
||||||
nthread <- 1
|
|
||||||
data.table::setDTthreads(nthread)
|
|
||||||
|
|
||||||
# In the iris dataset, it is hard to linearly separate Versicolor class from the rest
|
|
||||||
# without considering the 2nd order interactions:
|
|
||||||
x <- model.matrix(Species ~ .^2, iris)[, -1]
|
|
||||||
colnames(x)
|
|
||||||
dtrain <- xgb.DMatrix(
|
|
||||||
scale(x),
|
|
||||||
label = 1 * (iris$Species == "versicolor"),
|
|
||||||
nthread = nthread
|
|
||||||
)
|
|
||||||
param <- list(
|
|
||||||
booster = "gblinear",
|
|
||||||
objective = "reg:logistic",
|
|
||||||
eval_metric = "auc",
|
|
||||||
lambda = 0.0003,
|
|
||||||
alpha = 0.0003,
|
|
||||||
nthread = nthread
|
|
||||||
)
|
|
||||||
|
|
||||||
# For 'shotgun', which is a default linear updater, using high eta values may result in
|
|
||||||
# unstable behaviour in some datasets. With this simple dataset, however, the high learning
|
|
||||||
# rate does not break the convergence, but allows us to illustrate the typical pattern of
|
|
||||||
# "stochastic explosion" behaviour of this lock-free algorithm at early boosting iterations.
|
|
||||||
bst <- xgb.train(
|
|
||||||
param,
|
|
||||||
dtrain,
|
|
||||||
list(tr = dtrain),
|
|
||||||
nrounds = 200,
|
|
||||||
eta = 1.,
|
|
||||||
callbacks = list(xgb.cb.gblinear.history())
|
|
||||||
)
|
|
||||||
|
|
||||||
# Extract the coefficients' path and plot them vs boosting iteration number:
|
|
||||||
coef_path <- xgb.gblinear.history(bst)
|
|
||||||
matplot(coef_path, type = "l")
|
|
||||||
|
|
||||||
# With the deterministic coordinate descent updater, it is safer to use higher learning rates.
|
|
||||||
# Will try the classical componentwise boosting which selects a single best feature per round:
|
|
||||||
bst <- xgb.train(
|
|
||||||
param,
|
|
||||||
dtrain,
|
|
||||||
list(tr = dtrain),
|
|
||||||
nrounds = 200,
|
|
||||||
eta = 0.8,
|
|
||||||
updater = "coord_descent",
|
|
||||||
feature_selector = "thrifty",
|
|
||||||
top_k = 1,
|
|
||||||
callbacks = list(xgb.cb.gblinear.history())
|
|
||||||
)
|
|
||||||
matplot(xgb.gblinear.history(bst), type = "l")
|
|
||||||
# Componentwise boosting is known to have similar effect to Lasso regularization.
|
|
||||||
# Try experimenting with various values of top_k, eta, nrounds,
|
|
||||||
# as well as different feature_selectors.
|
|
||||||
|
|
||||||
# For xgb.cv:
|
|
||||||
bst <- xgb.cv(
|
|
||||||
param,
|
|
||||||
dtrain,
|
|
||||||
nfold = 5,
|
|
||||||
nrounds = 100,
|
|
||||||
eta = 0.8,
|
|
||||||
callbacks = list(xgb.cb.gblinear.history())
|
|
||||||
)
|
|
||||||
# coefficients in the CV fold #3
|
|
||||||
matplot(xgb.gblinear.history(bst)[[3]], type = "l")
|
|
||||||
|
|
||||||
|
|
||||||
#### Multiclass classification:
|
|
||||||
dtrain <- xgb.DMatrix(scale(x), label = as.numeric(iris$Species) - 1, nthread = nthread)
|
|
||||||
|
|
||||||
param <- list(
|
|
||||||
booster = "gblinear",
|
|
||||||
objective = "multi:softprob",
|
|
||||||
num_class = 3,
|
|
||||||
lambda = 0.0003,
|
|
||||||
alpha = 0.0003,
|
|
||||||
nthread = nthread
|
|
||||||
)
|
|
||||||
|
|
||||||
# For the default linear updater 'shotgun' it sometimes is helpful
|
|
||||||
# to use smaller eta to reduce instability
|
|
||||||
bst <- xgb.train(
|
|
||||||
param,
|
|
||||||
dtrain,
|
|
||||||
list(tr = dtrain),
|
|
||||||
nrounds = 50,
|
|
||||||
eta = 0.5,
|
|
||||||
callbacks = list(xgb.cb.gblinear.history())
|
|
||||||
)
|
|
||||||
|
|
||||||
# Will plot the coefficient paths separately for each class:
|
|
||||||
matplot(xgb.gblinear.history(bst, class_index = 0), type = "l")
|
|
||||||
matplot(xgb.gblinear.history(bst, class_index = 1), type = "l")
|
|
||||||
matplot(xgb.gblinear.history(bst, class_index = 2), type = "l")
|
|
||||||
|
|
||||||
# CV:
|
|
||||||
bst <- xgb.cv(
|
|
||||||
param,
|
|
||||||
dtrain,
|
|
||||||
nfold = 5,
|
|
||||||
nrounds = 70,
|
|
||||||
eta = 0.5,
|
|
||||||
callbacks = list(xgb.cb.gblinear.history(FALSE))
|
|
||||||
)
|
|
||||||
# 1st fold of 1st class
|
|
||||||
matplot(xgb.gblinear.history(bst, class_index = 0)[[1]], type = "l")
|
|
||||||
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\link{xgb.gblinear.history}, \link{coef.xgb.Booster}.
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.print.evaluation}
|
|
||||||
\alias{xgb.cb.print.evaluation}
|
|
||||||
\title{Callback for printing the result of evaluation}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.print.evaluation(period = 1, showsd = TRUE)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{period}{Results would be printed every number of periods.}
|
|
||||||
|
|
||||||
\item{showsd}{Whether standard deviations should be printed (when available).}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
The callback function prints the result of evaluation at every \code{period} iterations.
|
|
||||||
The initial and the last iteration's evaluations are always printed.
|
|
||||||
|
|
||||||
Does not leave any attribute in the booster (see \link{xgb.cb.evaluation.log} for that).
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\link{xgb.Callback}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.reset.parameters}
|
|
||||||
\alias{xgb.cb.reset.parameters}
|
|
||||||
\title{Callback for resetting booster parameters at each iteration}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.reset.parameters(new_params)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{new_params}{List of parameters needed 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.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}} or \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Callback for resetting booster parameters at each iteration
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Note that when training is resumed from some previous model, and a function is used to
|
|
||||||
reset a parameter value, the \code{nrounds} argument in this function would be the
|
|
||||||
the number of boosting rounds in the current training.
|
|
||||||
|
|
||||||
Does not leave any attribute in the booster.
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.cb.save.model}
|
|
||||||
\alias{xgb.cb.save.model}
|
|
||||||
\title{Callback for saving a model file}
|
|
||||||
\usage{
|
|
||||||
xgb.cb.save.model(save_period = 0, save_name = "xgboost.ubj")
|
|
||||||
}
|
|
||||||
\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[=sprintf]{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".}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
An \code{xgb.Callback} object, which can be passed to \code{\link[=xgb.train]{xgb.train()}},
|
|
||||||
but \strong{not} to \code{\link[=xgb.cv]{xgb.cv()}}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
This callback function allows to save an xgb-model file, either periodically
|
|
||||||
after each \code{save_period}'s or at the end.
|
|
||||||
|
|
||||||
Does not leave any attribute in the booster.
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R
|
|
||||||
\name{xgb.config}
|
|
||||||
\alias{xgb.config}
|
|
||||||
\alias{xgb.config<-}
|
|
||||||
\title{Accessors for model parameters as JSON string}
|
|
||||||
\usage{
|
|
||||||
xgb.config(object)
|
|
||||||
|
|
||||||
xgb.config(object) <- value
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{object}{Object of class \code{xgb.Booster}.\strong{Will be modified in-place} when assigning to it.}
|
|
||||||
|
|
||||||
\item{value}{A list.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
Parameters as a list.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Accessors for model parameters as JSON string
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Note that assignment is performed in-place on the booster C object, which unlike assignment
|
|
||||||
of R attributes, doesn't follow typical copy-on-write semantics for assignment - i.e. all references
|
|
||||||
to the same booster will also get updated.
|
|
||||||
|
|
||||||
See \code{\link[=xgb.copy.Booster]{xgb.copy.Booster()}} for an example of this behavior.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
## Keep the number of threads to 1 for examples
|
|
||||||
nthread <- 1
|
|
||||||
data.table::setDTthreads(nthread)
|
|
||||||
train <- agaricus.train
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(train$data, label = train$label),
|
|
||||||
max_depth = 2,
|
|
||||||
eta = 1,
|
|
||||||
nthread = nthread,
|
|
||||||
nrounds = 2,
|
|
||||||
objective = "binary:logistic"
|
|
||||||
)
|
|
||||||
|
|
||||||
config <- xgb.config(bst)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.Booster.R
|
|
||||||
\name{xgb.copy.Booster}
|
|
||||||
\alias{xgb.copy.Booster}
|
|
||||||
\title{Deep-copies a Booster Object}
|
|
||||||
\usage{
|
|
||||||
xgb.copy.Booster(model)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{model}{An 'xgb.Booster' object.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
A deep copy of \code{model} - it will be identical in every way, but C-level
|
|
||||||
functions called on that copy will not affect the \code{model} variable.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Creates a deep copy of an 'xgb.Booster' object, such that the
|
|
||||||
C object pointer contained will be a different object, and hence functions
|
|
||||||
like \code{\link[=xgb.attr]{xgb.attr()}} will not affect the object from which it was copied.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
library(xgboost)
|
|
||||||
|
|
||||||
data(mtcars)
|
|
||||||
|
|
||||||
y <- mtcars$mpg
|
|
||||||
x <- mtcars[, -1]
|
|
||||||
|
|
||||||
dm <- xgb.DMatrix(x, label = y, nthread = 1)
|
|
||||||
|
|
||||||
model <- xgb.train(
|
|
||||||
data = dm,
|
|
||||||
params = list(nthread = 1),
|
|
||||||
nround = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set an arbitrary attribute kept at the C level
|
|
||||||
xgb.attr(model, "my_attr") <- 100
|
|
||||||
print(xgb.attr(model, "my_attr"))
|
|
||||||
|
|
||||||
# Just assigning to a new variable will not create
|
|
||||||
# a deep copy - C object pointer is shared, and in-place
|
|
||||||
# modifications will affect both objects
|
|
||||||
model_shallow_copy <- model
|
|
||||||
xgb.attr(model_shallow_copy, "my_attr") <- 333
|
|
||||||
# 'model' was also affected by this change:
|
|
||||||
print(xgb.attr(model, "my_attr"))
|
|
||||||
|
|
||||||
model_deep_copy <- xgb.copy.Booster(model)
|
|
||||||
xgb.attr(model_deep_copy, "my_attr") <- 444
|
|
||||||
# 'model' was NOT affected by this change
|
|
||||||
# (keeps previous value that was assigned before)
|
|
||||||
print(xgb.attr(model, "my_attr"))
|
|
||||||
|
|
||||||
# Verify that the new object was actually modified
|
|
||||||
print(xgb.attr(model_deep_copy, "my_attr"))
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
% 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{
|
|
||||||
A \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/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 \verb{[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 <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
dtest <- with(agaricus.test, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
|
|
||||||
param <- list(max_depth = 2, eta = 1, objective = 'binary:logistic')
|
|
||||||
nrounds = 4
|
|
||||||
|
|
||||||
bst <- xgb.train(params = param, data = dtrain, nrounds = nrounds, 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, nthread = 2
|
|
||||||
)
|
|
||||||
new.dtest <- xgb.DMatrix(
|
|
||||||
data = new.features.test, label = agaricus.test$label, nthread = 2
|
|
||||||
)
|
|
||||||
bst <- xgb.train(params = param, data = new.dtrain, nrounds = nrounds, 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,193 +0,0 @@
|
|||||||
% 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,
|
|
||||||
prediction = FALSE,
|
|
||||||
showsd = TRUE,
|
|
||||||
metrics = list(),
|
|
||||||
obj = NULL,
|
|
||||||
feval = NULL,
|
|
||||||
stratified = "auto",
|
|
||||||
folds = NULL,
|
|
||||||
train_folds = NULL,
|
|
||||||
verbose = TRUE,
|
|
||||||
print_every_n = 1L,
|
|
||||||
early_stopping_rounds = NULL,
|
|
||||||
maximize = NULL,
|
|
||||||
callbacks = list(),
|
|
||||||
...
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{params}{The list of parameters. The complete list of parameters is available in the
|
|
||||||
\href{http://xgboost.readthedocs.io/en/latest/parameter.html}{online documentation}.
|
|
||||||
Below is a shorter summary:
|
|
||||||
\itemize{
|
|
||||||
\item \code{objective}: Objective function, common ones are
|
|
||||||
\itemize{
|
|
||||||
\item \code{reg:squarederror}: Regression with squared loss.
|
|
||||||
\item \code{binary:logistic}: Logistic regression for classification.
|
|
||||||
}
|
|
||||||
|
|
||||||
See \code{\link[=xgb.train]{xgb.train()}} for complete list of objectives.
|
|
||||||
\item \code{eta}: Step size of each boosting step
|
|
||||||
\item \code{max_depth}: Maximum depth of the tree
|
|
||||||
\item \code{nthread}: Number of threads used in training. If not set, all threads are used
|
|
||||||
}
|
|
||||||
|
|
||||||
See \code{\link[=xgb.train]{xgb.train()}} for further details.
|
|
||||||
See also demo for walkthrough example in R.
|
|
||||||
|
|
||||||
Note that, while \code{params} accepts a \code{seed} entry and will use such parameter for model training if
|
|
||||||
supplied, this seed is not used for creation of train-test splits, which instead rely on R's own RNG
|
|
||||||
system - thus, for reproducible results, one needs to call the \code{\link[=set.seed]{set.seed()}} function beforehand.}
|
|
||||||
|
|
||||||
\item{data}{An \code{xgb.DMatrix} object, with corresponding fields like \code{label} or bounds as required
|
|
||||||
for model training by the objective.
|
|
||||||
|
|
||||||
Note that only the basic \code{xgb.DMatrix} class is supported - variants such as \code{xgb.QuantileDMatrix}
|
|
||||||
or \code{xgb.ExtMemDMatrix} are not supported here.}
|
|
||||||
|
|
||||||
\item{nrounds}{The max number of iterations.}
|
|
||||||
|
|
||||||
\item{nfold}{The original dataset is randomly partitioned into \code{nfold} equal size subsamples.}
|
|
||||||
|
|
||||||
\item{prediction}{A logical value indicating whether to return the test fold predictions
|
|
||||||
from each CV model. This parameter engages the \code{\link[=xgb.cb.cv.predict]{xgb.cb.cv.predict()}} callback.}
|
|
||||||
|
|
||||||
\item{showsd}{Logical value whether to show standard deviation of cross 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{
|
|
||||||
\item \code{error}: Binary classification error rate
|
|
||||||
\item \code{rmse}: Root mean square error
|
|
||||||
\item \code{logloss}: Negative log-likelihood function
|
|
||||||
\item \code{mae}: Mean absolute error
|
|
||||||
\item \code{mape}: Mean absolute percentage error
|
|
||||||
\item \code{auc}: Area under curve
|
|
||||||
\item \code{aucpr}: Area under PR curve
|
|
||||||
\item \code{merror}: Exact matching error used to evaluate multi-class classification
|
|
||||||
}}
|
|
||||||
|
|
||||||
\item{obj}{Customized objective function. Returns gradient and second order
|
|
||||||
gradient with given prediction and dtrain.}
|
|
||||||
|
|
||||||
\item{feval}{Customized evaluation function. Returns
|
|
||||||
\code{list(metric='metric-name', value='metric-value')} with given prediction and dtrain.}
|
|
||||||
|
|
||||||
\item{stratified}{Logical flag indicating whether sampling of folds should be stratified
|
|
||||||
by the values of outcome labels. For real-valued labels in regression objectives,
|
|
||||||
stratification will be done by discretizing the labels into up to 5 buckets beforehand.
|
|
||||||
|
|
||||||
If passing "auto", will be set to \code{TRUE} if the objective in \code{params} is a classification
|
|
||||||
objective (from XGBoost's built-in objectives, doesn't apply to custom ones), and to
|
|
||||||
\code{FALSE} otherwise.
|
|
||||||
|
|
||||||
This parameter is ignored when \code{data} has a \code{group} field - in such case, the splitting
|
|
||||||
will be based on whole groups (note that this might make the folds have different sizes).
|
|
||||||
|
|
||||||
Value \code{TRUE} here is \strong{not} supported for custom objectives.}
|
|
||||||
|
|
||||||
\item{folds}{List with 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.
|
|
||||||
|
|
||||||
If \code{data} has a \code{group} field and the objective requires this field, each fold (list element)
|
|
||||||
must additionally have two attributes (retrievable through \code{attributes}) named \code{group_test}
|
|
||||||
and \code{group_train}, which should hold the \code{group} to assign through \code{\link[=setinfo.xgb.DMatrix]{setinfo.xgb.DMatrix()}} to
|
|
||||||
the resulting DMatrices.}
|
|
||||||
|
|
||||||
\item{train_folds}{List specifying which indices to use for training. If \code{NULL}
|
|
||||||
(the default) all indices not specified in \code{folds} will be used for training.
|
|
||||||
|
|
||||||
This is not supported when \code{data} has \code{group} field.}
|
|
||||||
|
|
||||||
\item{verbose}{Logical flag. Should statistics be printed during the process?}
|
|
||||||
|
|
||||||
\item{print_every_n}{Print each nth iteration evaluation messages when \code{verbose > 0}.
|
|
||||||
Default is 1 which means all messages are printed. This parameter is passed to the
|
|
||||||
\code{\link[=xgb.cb.print.evaluation]{xgb.cb.print.evaluation()}} callback.}
|
|
||||||
|
|
||||||
\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[=xgb.cb.early.stop]{xgb.cb.early.stop()}} callback.}
|
|
||||||
|
|
||||||
\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[=xgb.cb.early.stop]{xgb.cb.early.stop()}} callback.}
|
|
||||||
|
|
||||||
\item{callbacks}{A list of callback functions to perform various task during boosting.
|
|
||||||
See \code{\link[=xgb.Callback]{xgb.Callback()}}. 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{
|
|
||||||
An object of class 'xgb.cv.synchronous' with the following elements:
|
|
||||||
\itemize{
|
|
||||||
\item \code{call}: 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[=xgb.cb.reset.parameters]{xgb.cb.reset.parameters()}} callback.
|
|
||||||
\item \code{evaluation_log}: Evaluation history stored 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[=xgb.cb.evaluation.log]{xgb.cb.evaluation.log()}} callback.
|
|
||||||
\item \code{niter}: Number of boosting iterations.
|
|
||||||
\item \code{nfeatures}: Number of features in training data.
|
|
||||||
\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).
|
|
||||||
}
|
|
||||||
|
|
||||||
Plus other potential elements that are the result of callbacks, such as a list \code{cv_predict} with
|
|
||||||
a sub-element \code{pred} when passing \code{prediction = TRUE}, which is added by the \code{\link[=xgb.cb.cv.predict]{xgb.cb.cv.predict()}}
|
|
||||||
callback (note that one can also pass it manually under \code{callbacks} with different settings,
|
|
||||||
such as saving also the models created during cross validation); or a list \code{early_stop} which
|
|
||||||
will contain elements such as \code{best_iteration} when using the early stopping callback (\code{\link[=xgb.cb.early.stop]{xgb.cb.early.stop()}}).
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
The cross validation function of xgboost.
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
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.
|
|
||||||
|
|
||||||
The cross-validation process is then repeated \code{nrounds} times, with each of the
|
|
||||||
\code{nfold} subsamples used exactly once as the validation data.
|
|
||||||
|
|
||||||
All observations are used for both training and validation.
|
|
||||||
|
|
||||||
Adapted from \url{https://en.wikipedia.org/wiki/Cross-validation_\%28statistics\%29}
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
|
|
||||||
dtrain <- with(agaricus.train, xgb.DMatrix(data, label = label, nthread = 2))
|
|
||||||
|
|
||||||
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,76 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.dump.R
|
|
||||||
\name{xgb.dump}
|
|
||||||
\alias{xgb.dump}
|
|
||||||
\title{Dump an XGBoost model in text format.}
|
|
||||||
\usage{
|
|
||||||
xgb.dump(
|
|
||||||
model,
|
|
||||||
fname = NULL,
|
|
||||||
fmap = "",
|
|
||||||
with_stats = FALSE,
|
|
||||||
dump_format = c("text", "json", "dot"),
|
|
||||||
...
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\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 model is returned as a character vector.}
|
|
||||||
|
|
||||||
\item{fmap}{Feature map file representing feature types. See demo/ for a walkthrough
|
|
||||||
example in R, and \url{https://github.com/dmlc/xgboost/blob/master/demo/data/featmap.txt}
|
|
||||||
to see an example of the value.}
|
|
||||||
|
|
||||||
\item{with_stats}{Whether to dump some additional statistics about the splits.
|
|
||||||
When this option is on, the model dump contains two additional values:
|
|
||||||
gain is the approximate loss function gain we get in each split;
|
|
||||||
cover is the sum of second order gradient in each node.}
|
|
||||||
|
|
||||||
\item{dump_format}{Either 'text', 'json', or 'dot' (graphviz) format could be specified.
|
|
||||||
|
|
||||||
Format 'dot' for a single tree can be passed directly to packages that consume this format
|
|
||||||
for graph visualization, such as function \code{DiagrammeR::grViz()}}
|
|
||||||
|
|
||||||
\item{...}{Currently not used}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
If fname is not provided or set to \code{NULL} the function will return the model
|
|
||||||
as a character vector. Otherwise it will return \code{TRUE}.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Dump an XGBoost model in text format.
|
|
||||||
}
|
|
||||||
\examples{
|
|
||||||
\dontshow{RhpcBLASctl::omp_set_num_threads(1)}
|
|
||||||
data(agaricus.train, package = "xgboost")
|
|
||||||
data(agaricus.test, package = "xgboost")
|
|
||||||
|
|
||||||
train <- agaricus.train
|
|
||||||
test <- agaricus.test
|
|
||||||
|
|
||||||
bst <- xgb.train(
|
|
||||||
data = xgb.DMatrix(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'
|
|
||||||
dump_path = file.path(tempdir(), 'model.dump')
|
|
||||||
xgb.dump(bst, dump_path, with_stats = TRUE)
|
|
||||||
|
|
||||||
# print the model without saving it to a file
|
|
||||||
print(xgb.dump(bst, with_stats = TRUE))
|
|
||||||
|
|
||||||
# print in JSON format:
|
|
||||||
cat(xgb.dump(bst, with_stats = TRUE, dump_format = "json"))
|
|
||||||
|
|
||||||
# plot first tree leveraging the 'dot' format
|
|
||||||
if (requireNamespace('DiagrammeR', quietly = TRUE)) {
|
|
||||||
DiagrammeR::grViz(xgb.dump(bst, dump_format = "dot")[[1L]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/callbacks.R
|
|
||||||
\name{xgb.gblinear.history}
|
|
||||||
\alias{xgb.gblinear.history}
|
|
||||||
\title{Extract gblinear coefficients history}
|
|
||||||
\usage{
|
|
||||||
xgb.gblinear.history(model, class_index = NULL)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{model}{Either an \code{xgb.Booster} or a result of \code{\link[=xgb.cv]{xgb.cv()}}, trained
|
|
||||||
using the \link{xgb.cb.gblinear.history} callback, but \strong{not} a booster
|
|
||||||
loaded from \code{\link[=xgb.load]{xgb.load()}} or \code{\link[=xgb.load.raw]{xgb.load.raw()}}.}
|
|
||||||
|
|
||||||
\item{class_index}{zero-based class index to extract the coefficients for only that
|
|
||||||
specific class in a multinomial multiclass model. When it is \code{NULL}, all the
|
|
||||||
coefficients are returned. Has no effect in non-multiclass models.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
For an \code{\link[=xgb.train]{xgb.train()}} result, a matrix (either dense or sparse) with the columns
|
|
||||||
corresponding to iteration's coefficients and the rows corresponding to boosting iterations.
|
|
||||||
|
|
||||||
For an \code{\link[=xgb.cv]{xgb.cv()}} result, a list of such matrices is returned with the elements
|
|
||||||
corresponding to CV folds.
|
|
||||||
|
|
||||||
When there is more than one coefficient per feature (e.g. multi-class classification)
|
|
||||||
and \code{class_index} is not provided,
|
|
||||||
the result will be reshaped into a vector where coefficients are arranged first by features and
|
|
||||||
then by class (e.g. first 1 through N coefficients will be for the first class, then
|
|
||||||
coefficients N+1 through 2N for the second class, and so on).
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
A helper function to extract the matrix of linear coefficients' history
|
|
||||||
from a gblinear model created while using the \link{xgb.cb.gblinear.history}
|
|
||||||
callback (which must be added manually as by default it is not used).
|
|
||||||
}
|
|
||||||
\details{
|
|
||||||
Note that this is an R-specific function that relies on R attributes that
|
|
||||||
are not saved when using XGBoost's own serialization functions like \code{\link[=xgb.load]{xgb.load()}}
|
|
||||||
or \code{\link[=xgb.load.raw]{xgb.load.raw()}}.
|
|
||||||
|
|
||||||
In order for a serialized model to be accepted by this function, one must use R
|
|
||||||
serializers such as \code{\link[=saveRDS]{saveRDS()}}.
|
|
||||||
}
|
|
||||||
\seealso{
|
|
||||||
\link{xgb.cb.gblinear.history}, \link{coef.xgb.Booster}.
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.get.DMatrix.data}
|
|
||||||
\alias{xgb.get.DMatrix.data}
|
|
||||||
\title{Get DMatrix Data}
|
|
||||||
\usage{
|
|
||||||
xgb.get.DMatrix.data(dmat)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{dmat}{An \code{xgb.DMatrix} object, as returned by \code{\link[=xgb.DMatrix]{xgb.DMatrix()}}.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
The data held in the DMatrix, as a sparse CSR matrix (class \code{dgRMatrix}
|
|
||||||
from package \code{Matrix}). If it had feature names, these will be added as column names
|
|
||||||
in the output.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Get DMatrix Data
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
% Generated by roxygen2: do not edit by hand
|
|
||||||
% Please edit documentation in R/xgb.DMatrix.R
|
|
||||||
\name{xgb.get.DMatrix.num.non.missing}
|
|
||||||
\alias{xgb.get.DMatrix.num.non.missing}
|
|
||||||
\title{Get Number of Non-Missing Entries in DMatrix}
|
|
||||||
\usage{
|
|
||||||
xgb.get.DMatrix.num.non.missing(dmat)
|
|
||||||
}
|
|
||||||
\arguments{
|
|
||||||
\item{dmat}{An \code{xgb.DMatrix} object, as returned by \code{\link[=xgb.DMatrix]{xgb.DMatrix()}}.}
|
|
||||||
}
|
|
||||||
\value{
|
|
||||||
The number of non-missing entries in the DMatrix.
|
|
||||||
}
|
|
||||||
\description{
|
|
||||||
Get Number of Non-Missing Entries in DMatrix
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user