{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/machinelearning/pulls/comments/233694799","pull_request_review_id":175169538,"id":233694799,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzMzY5NDc5OQ==","diff_hunk":"@@ -607,101 +438,438 @@ private static NgramIdFinder GetNgramIdFinderAdd(int[] counts, int[] lims, Seque\n                 };\n         }\n \n-        private NgramIdFinder GetNgramIdFinder(int iinfo)\n+        // Factory method for SignatureLoadDataTransform.\n+        private static IDataTransform Create(IHostEnvironment env, ModelLoadContext ctx, IDataView input)\n+            => Create(env, ctx).MakeDataTransform(input);\n+\n+        // Factory method for SignatureLoadRowMapper.\n+        private static IRowMapper Create(IHostEnvironment env, ModelLoadContext ctx, ISchema inputSchema)\n+            => Create(env, ctx).MakeRowMapper(Schema.Create(inputSchema));\n+\n+        private NgramTransformer(IHost host, ModelLoadContext ctx) :\n+            base(host, ctx)\n         {\n-            return\n-                (uint[] ngram, int lim, int icol, ref bool more) =>\n+            var columnsLength = ColumnPairs.Length;\n+            // *** Binary format ***\n+            // <prefix handled in static Create method>\n+            // <base>\n+            // for each column\n+            //   _transformInfo\n+            //   the ngram SequencePool\n+            //   the ngram inverse document frequencies\n+            _transformInfos = new TransformInfo[columnsLength];\n+            _ngramMaps = new SequencePool[columnsLength];\n+            _invDocFreqs = new double[columnsLength][];\n+            for (int i = 0; i < columnsLength; i++)\n+            {\n+                _transformInfos[i] = new TransformInfo(ctx, ctx.Header.ModelVerWritten >= VerTfIdfSupported);\n+                _ngramMaps[i] = new SequencePool(ctx.Reader);\n+\n+                if (ctx.Header.ModelVerWritten >= VerTfIdfSupported)\n                 {\n-                    Host.Assert(0 < lim && lim <= Utils.Size(ngram));\n-                    Host.Assert(lim <= Utils.Size(_exes[iinfo].NonEmptyLevels));\n+                    _invDocFreqs[i] = ctx.Reader.ReadDoubleArray();\n+                    for (int j = 0; j < Utils.Size(_invDocFreqs[i]); j++)\n+                        Host.CheckDecode(_invDocFreqs[i][j] >= 0);\n+                }\n+            }\n+        }\n+\n+        // Factory method for SignatureDataTransform.\n+        internal static IDataTransform Create(IHostEnvironment env, Arguments args, IDataView input)\n+        {\n+            Contracts.CheckValue(env, nameof(env));\n+            env.CheckValue(args, nameof(args));\n+            env.CheckValue(input, nameof(input));\n \n-                    if (!_exes[iinfo].NonEmptyLevels[lim - 1])\n-                        return -1;\n-                    return _ngramMaps[iinfo].Get(ngram, 0, lim);\n+            env.CheckValue(args.Column, nameof(args.Column));\n+            var cols = new ColumnInfo[args.Column.Length];\n+            using (var ch = env.Start(\"ValidateArgs\"))\n+            {\n+\n+                for (int i = 0; i < cols.Length; i++)\n+                {\n+                    var item = args.Column[i];\n+                    var maxNumTerms = Utils.Size(item.MaxNumTerms) > 0 ? item.MaxNumTerms : args.MaxNumTerms;\n+                    cols[i] = new ColumnInfo(item.Source ?? item.Name,\n+                        item.Name,\n+                        item.NgramLength ?? args.NgramLength,\n+                        item.SkipLength ?? args.SkipLength,\n+                        item.AllLengths ?? args.AllLengths,\n+                        item.Weighting ?? args.Weighting,\n+                        maxNumTerms);\n                 };\n+            }\n+            return new NgramTransformer(env, input, cols).MakeDataTransform(input);\n+        }\n+\n+        // Factory method for SignatureLoadModel.\n+        private static NgramTransformer Create(IHostEnvironment env, ModelLoadContext ctx)\n+        {\n+            Contracts.CheckValue(env, nameof(env));\n+            var host = env.Register(nameof(NgramTransformer));\n+\n+            host.CheckValue(ctx, nameof(ctx));\n+            ctx.CheckAtModel(GetVersionInfo());\n+            if (ctx.Header.ModelVerWritten < 0x00010003)\n+            {\n+                int cbFloat = ctx.Reader.ReadInt32();\n+                env.CheckDecode(cbFloat == sizeof(float));\n+            }\n+            return new NgramTransformer(host, ctx);\n         }\n \n-        protected override ColumnType GetColumnTypeCore(int iinfo)\n+        public override void Save(ModelSaveContext ctx)\n         {\n-            Host.Check(0 <= iinfo & iinfo < Infos.Length);\n-            return _types[iinfo];\n+            Host.CheckValue(ctx, nameof(ctx));\n+            ctx.CheckAtModel();\n+            ctx.SetVersionInfo(GetVersionInfo());\n+            // *** Binary format ***\n+            // <base>\n+            // for each added column\n+            //   _transformInfo\n+            //   the ngram SequencePool\n+            //   the ngram inverse document frequencies\n+            SaveColumns(ctx);\n+            for (int i = 0; i < _transformInfos.Length; i++)\n+            {\n+                _transformInfos[i].Save(ctx);\n+                _ngramMaps[i].Save(ctx.Writer);\n+                ctx.Writer.WriteDoubleArray(_invDocFreqs[i]);\n+            }\n         }\n \n-        protected override Delegate GetGetterCore(IChannel ch, IRow input, int iinfo, out Action disposer)\n+        protected override IRowMapper MakeRowMapper(Schema schema) => new Mapper(this, schema);\n+\n+        private sealed class Mapper : MapperBase\n         {\n-            Host.AssertValueOrNull(ch);\n-            Host.AssertValue(input);\n-            Host.Assert(0 <= iinfo && iinfo < Infos.Length);\n-            Host.Assert(Infos[iinfo].TypeSrc.IsVector);\n-            Host.Assert(Infos[iinfo].TypeSrc.ItemType.IsKey);\n-\n-            disposer = null;\n-\n-            var getSrc = RowCursorUtils.GetVecGetterAs<uint>(NumberType.U4, input, Infos[iinfo].Source);\n-            var src = default(VBuffer<uint>);\n-            var bldr = new NgramBufferBuilder(_exes[iinfo].NgramLength, _exes[iinfo].SkipLength,\n-                _ngramMaps[iinfo].Count, GetNgramIdFinder(iinfo));\n-            var keyCount = (uint)Infos[iinfo].TypeSrc.ItemType.KeyCount;\n-            if (keyCount == 0)\n-                keyCount = uint.MaxValue;\n-\n-            ValueGetter<VBuffer<Float>> del;\n-            switch (_exes[iinfo].Weighting)\n+            private readonly ColumnType[] _srcTypes;\n+            private readonly int[] _srcCols;\n+            private readonly ColumnType[] _types;\n+            private readonly NgramTransformer _parent;\n+\n+            public Mapper(NgramTransformer parent, Schema inputSchema)\n+               : base(parent.Host.Register(nameof(Mapper)), parent, inputSchema)\n             {\n-                case WeightingCriteria.TfIdf:\n-                    Host.AssertValue(_invDocFreqs[iinfo]);\n-                    del =\n-                        (ref VBuffer<Float> dst) =>\n-                        {\n-                            getSrc(ref src);\n-                            if (!bldr.IsEmpty)\n+                _parent = parent;\n+                _types = new ColumnType[_parent.ColumnPairs.Length];\n+                _srcTypes = new ColumnType[_parent.ColumnPairs.Length];\n+                _srcCols = new int[_parent.ColumnPairs.Length];\n+                for (int i = 0; i < _parent.ColumnPairs.Length; i++)\n+                {\n+                    _types[i] = new VectorType(NumberType.Float, _parent._ngramMaps[i].Count);\n+                    inputSchema.TryGetColumnIndex(_parent.ColumnPairs[i].input, out _srcCols[i]);\n+                    _srcTypes[i] = inputSchema.GetColumnType(_srcCols[i]);\n+                }\n+            }\n+\n+            public override Schema.Column[] GetOutputColumns()\n+            {\n+                var result = new Schema.Column[_parent.ColumnPairs.Length];\n+                for (int i = 0; i < _parent.ColumnPairs.Length; i++)\n+                {\n+                    var builder = new Schema.Metadata.Builder();\n+                    AddMetadata(i, builder);\n+\n+                    result[i] = new Schema.Column(_parent.ColumnPairs[i].output, _types[i], builder.GetMetadata());\n+                }\n+                return result;\n+            }\n+\n+            private void AddMetadata(int iinfo, Schema.Metadata.Builder builder)\n+            {\n+                if (InputSchema.HasKeyNames(_srcCols[iinfo], _srcTypes[iinfo].ItemType.KeyCount))\n+                {\n+                    ValueGetter<VBuffer<ReadOnlyMemory<char>>> getter = (ref VBuffer<ReadOnlyMemory<char>> dst) =>\n+                    {\n+                        GetSlotNames(iinfo, _parent._ngramMaps[iinfo].Count, ref dst);\n+                    };\n+\n+                    var slotNamesType = new VectorType(TextType.Instance, _parent._ngramMaps[iinfo].Count);\n+                    builder.AddSlotNames(_parent._ngramMaps[iinfo].Count, getter);\n+                }\n+            }\n+\n+            private void GetSlotNames(int iinfo, int size, ref VBuffer<ReadOnlyMemory<char>> dst)\n+            {\n+                Host.Assert(0 <= iinfo && iinfo < _parent.ColumnPairs.Length);\n+\n+                var keyCount = _srcTypes[iinfo].ItemType.KeyCount;\n+                Host.Assert(InputSchema.HasKeyNames(_srcCols[iinfo], keyCount));\n+\n+                var unigramNames = new VBuffer<ReadOnlyMemory<char>>();\n+\n+                // Get the key values of the unigrams.\n+                InputSchema.GetMetadata(MetadataUtils.Kinds.KeyValues, _srcCols[iinfo], ref unigramNames);\n+                Host.Check(unigramNames.Length == keyCount);\n+\n+                var pool = _parent._ngramMaps[iinfo];\n+                var values = dst.Values;\n+\n+                var ngramCount = pool.Count;\n+                if (Utils.Size(values) < ngramCount)\n+                    Array.Resize(ref values, ngramCount);\n+\n+                StringBuilder sb = new StringBuilder();\n+                uint[] ngram = new uint[_parent._transformInfos[iinfo].NgramLength];\n+                for (int slot = 0; slot < pool.Count; slot++)\n+                {\n+                    var n = pool.GetById(slot, ref ngram);\n+                    Host.Assert(n >= 0);\n+\n+                    // Get the unigrams composing the current ngram.\n+                    ComposeNgramString(ngram, n, sb, keyCount,\n+                        unigramNames.GetItemOrDefault);\n+                    values[slot] = sb.ToString().AsMemory();\n+                }\n+\n+                dst = new VBuffer<ReadOnlyMemory<char>>(ngramCount, values, dst.Indices);\n+            }\n+\n+            private delegate void TermGetter(int index, ref ReadOnlyMemory<char> term);\n+\n+            private void ComposeNgramString(uint[] ngram, int count, StringBuilder sb, int keyCount, TermGetter termGetter)\n+            {\n+                Host.AssertValue(sb);\n+                Host.AssertValue(ngram);\n+                Host.Assert(keyCount > 0);\n+\n+                sb.Clear();\n+                ReadOnlyMemory<char> term = default;\n+                string sep = \"\";\n+                for (int iterm = 0; iterm < count; iterm++)\n+                {\n+                    sb.Append(sep);\n+                    sep = \"|\";\n+                    var unigram = ngram[iterm];\n+                    if (unigram <= 0 || unigram > keyCount)\n+                        sb.Append(\"*\");\n+                    else\n+                    {\n+                        termGetter((int)unigram - 1, ref term);\n+                        sb.AppendMemory(term);\n+                    }\n+                }\n+            }\n+\n+            private NgramIdFinder GetNgramIdFinder(int iinfo)\n+            {\n+                return\n+                    (uint[] ngram, int lim, int icol, ref bool more) =>\n+                    {\n+                        Host.Assert(0 < lim && lim <= Utils.Size(ngram));\n+                        Host.Assert(lim <= Utils.Size(_parent._transformInfos[iinfo].NonEmptyLevels));\n+\n+                        if (!_parent._transformInfos[iinfo].NonEmptyLevels[lim - 1])\n+                            return -1;\n+                        return _parent._ngramMaps[iinfo].Get(ngram, 0, lim);\n+                    };\n+            }\n+\n+            protected override Delegate MakeGetter(IRow input, int iinfo, out Action disposer)\n+            {\n+                Contracts.AssertValue(input);\n+                Contracts.Assert(0 <= iinfo && iinfo < _parent.ColumnPairs.Length);\n+                disposer = null;\n+\n+                var getSrc = RowCursorUtils.GetVecGetterAs<uint>(NumberType.U4, input, _srcCols[iinfo]);\n+                var src = default(VBuffer<uint>);\n+                var bldr = new NgramBufferBuilder(_parent._transformInfos[iinfo].NgramLength, _parent._transformInfos[iinfo].SkipLength,\n+                    _parent._ngramMaps[iinfo].Count, GetNgramIdFinder(iinfo));\n+                var keyCount = (uint)_srcTypes[iinfo].ItemType.KeyCount;\n+                if (keyCount == 0)\n+                    keyCount = uint.MaxValue;\n+\n+                ValueGetter<VBuffer<float>> del;\n+                switch (_parent._transformInfos[iinfo].Weighting)\n+                {\n+                    case NgramEstimator.WeightingCriteria.TfIdf:\n+                        Host.AssertValue(_parent._invDocFreqs[iinfo]);\n+                        del =\n+                            (ref VBuffer<float> dst) =>\n                             {\n-                                bldr.Reset();\n-                                bldr.AddNgrams(in src, 0, keyCount);\n-                                bldr.GetResult(ref dst);\n-                                VBufferUtils.Apply(ref dst, (int i, ref Float v) => v = (Float)(v * _invDocFreqs[iinfo][i]));\n-                            }\n-                            else\n-                                dst = new VBuffer<Float>(0, dst.Values, dst.Indices);\n-                        };\n-                    break;\n-                case WeightingCriteria.Idf:\n-                    Host.AssertValue(_invDocFreqs[iinfo]);\n-                    del =\n-                        (ref VBuffer<Float> dst) =>\n-                        {\n-                            getSrc(ref src);\n-                            if (!bldr.IsEmpty)\n+                                getSrc(ref src);\n+                                if (!bldr.IsEmpty)\n+                                {\n+                                    bldr.Reset();\n+                                    bldr.AddNgrams(in src, 0, keyCount);\n+                                    bldr.GetResult(ref dst);\n+                                    VBufferUtils.Apply(ref dst, (int i, ref float v) => v = (float)(v * _parent._invDocFreqs[iinfo][i]));\n+                                }\n+                                else\n+                                    dst = new VBuffer<float>(0, dst.Values, dst.Indices);\n+                            };\n+                        break;\n+                    case NgramEstimator.WeightingCriteria.Idf:\n+                        Host.AssertValue(_parent._invDocFreqs[iinfo]);\n+                        del =\n+                            (ref VBuffer<float> dst) =>\n                             {\n-                                bldr.Reset();\n-                                bldr.AddNgrams(in src, 0, keyCount);\n-                                bldr.GetResult(ref dst);\n-                                VBufferUtils.Apply(ref dst, (int i, ref Float v) => v = v >= 1 ? (Float)_invDocFreqs[iinfo][i] : 0);\n-                            }\n-                            else\n-                                dst = new VBuffer<Float>(0, dst.Values, dst.Indices);\n-                        };\n-                    break;\n-                case WeightingCriteria.Tf:\n-                    del =\n-                        (ref VBuffer<Float> dst) =>\n-                        {\n-                            getSrc(ref src);\n-                            if (!bldr.IsEmpty)\n+                                getSrc(ref src);\n+                                if (!bldr.IsEmpty)\n+                                {\n+                                    bldr.Reset();\n+                                    bldr.AddNgrams(in src, 0, keyCount);\n+                                    bldr.GetResult(ref dst);\n+                                    VBufferUtils.Apply(ref dst, (int i, ref float v) => v = v >= 1 ? (float)_parent._invDocFreqs[iinfo][i] : 0);\n+                                }\n+                                else\n+                                    dst = new VBuffer<float>(0, dst.Values, dst.Indices);\n+                            };\n+                        break;\n+                    case NgramEstimator.WeightingCriteria.Tf:\n+                        del =\n+                            (ref VBuffer<float> dst) =>\n                             {\n-                                bldr.Reset();\n-                                bldr.AddNgrams(in src, 0, keyCount);\n-                                bldr.GetResult(ref dst);\n-                            }\n-                            else\n-                                dst = new VBuffer<Float>(0, dst.Values, dst.Indices);\n-                        };\n-                    break;\n-                default:\n-                    throw Host.Except(\"Unsupported weighting criteria\");\n+                                getSrc(ref src);\n+                                if (!bldr.IsEmpty)\n+                                {\n+                                    bldr.Reset();\n+                                    bldr.AddNgrams(in src, 0, keyCount);\n+                                    bldr.GetResult(ref dst);\n+                                }\n+                                else\n+                                    dst = new VBuffer<float>(0, dst.Values, dst.Indices);\n+                            };\n+                        break;\n+                    default:\n+                        throw Host.Except(\"Unsupported weighting criteria\");\n+                }\n+                return del;\n             }\n+        }\n+    }\n \n-            return del;\n+    /// <summary>\n+    /// Produces a bag of counts of ngrams(sequences of consecutive values of length 1-n) in a given vector of keys.\n+    /// It does so by building a dictionary of ngrams and using the id in the dictionary as the index in the bag.\n+    /// </summary>\n+    public sealed class NgramEstimator : IEstimator<NgramTransformer>\n+    {\n+        /// <summary>\n+        /// Weighting criteria: a statistical measure used to evaluate how important a word is to a document in a corpus.\n+        /// This enumeration is serialized.\n+        /// </summary>\n+        public enum WeightingCriteria\n+        {\n+            [EnumValueDisplay(\"TF (Term Frequency)\")]\n+            Tf = 0,\n+\n+            [EnumValueDisplay(\"IDF (Inverse Document Frequency)\")]\n+            Idf = 1,\n+\n+            [EnumValueDisplay(\"TF-IDF\")]\n+            TfIdf = 2\n+        }\n+\n+        internal static class Defaults\n+        {\n+            public const int NgramLength = 2;\n+            public const bool AllLength = true;\n+            public const int SkipLength = 0;\n+            public const int MaxNumTerms = 10000000;\n+            public const WeightingCriteria Weighting = WeightingCriteria.Tf;\n+        }\n+\n+        private readonly IHost _host;\n+        private readonly NgramTransformer.ColumnInfo[] _columns;\n+\n+        /// <summary>\n+        /// Produces a bag of counts of ngrams (sequences of consecutive words) in <paramref name=\"inputColumn\"/>\n+        /// and outputs bag of word vector as <paramref name=\"outputColumn\"/>\n+        /// </summary>\n+        /// <param name=\"env\">The environment.</param>\n+        /// <param name=\"inputColumn\">The column containing text to compute bag of word vector.</param>\n+        /// <param name=\"outputColumn\">The column containing bag of word vector. Null means <paramref name=\"inputColumn\"/> is replaced.</param>\n+        /// <param name=\"ngramLength\">Ngram length.</param>\n+        /// <param name=\"skipLength\">Maximum number of tokens to skip when constructing an ngram.</param>\n+        /// <param name=\"allLengths\">Whether to include all ngram lengths up to <paramref name=\"ngramLength\"/> or only <paramref name=\"ngramLength\"/>.</param>\n+        /// <param name=\"maxNumTerms\">Maximum number of ngrams to store in the dictionary.</param>\n+        /// <param name=\"weighting\">Statistical measure used to evaluate how important a word is to a document in a corpus.</param>\n+        public NgramEstimator(IHostEnvironment env,\n+            string inputColumn,\n+            string outputColumn = null,\n+            int ngramLength = Defaults.NgramLength,\n+            int skipLength = Defaults.SkipLength,\n+            bool allLengths = Defaults.AllLength,\n+            int maxNumTerms = Defaults.MaxNumTerms,\n+            WeightingCriteria weighting = Defaults.Weighting)\n+            : this(env, new[] { (inputColumn, outputColumn ?? inputColumn) }, ngramLength, skipLength, allLengths, maxNumTerms, weighting)\n+        {\n+        }\n+\n+        /// <summary>\n+        /// Produces a bag of counts of ngrams (sequences of consecutive words) in <paramref name=\"columns.inputs\"/>\n+        /// and outputs bag of word vector for each output in <paramref name=\"columns.output\"/>\n+        /// </summary>\n+        /// <param name=\"env\">The environment.</param>\n+        /// <param name=\"columns\">Pairs of columns to compute bag of word vector.</param>\n+        /// <param name=\"ngramLength\">Ngram length.</param>\n+        /// <param name=\"skipLength\">Maximum number of tokens to skip when constructing an ngram.</param>\n+        /// <param name=\"allLengths\">Whether to include all ngram lengths up to <paramref name=\"ngramLength\"/> or only <paramref name=\"ngramLength\"/>.</param>\n+        /// <param name=\"maxNumTerms\">Maximum number of ngrams to store in the dictionary.</param>\n+        /// <param name=\"weighting\">Statistical measure used to evaluate how important a word is to a document in a corpus.</param>\n+        public NgramEstimator(IHostEnvironment env,\n+            (string input, string output)[] columns,\n+            int ngramLength = Defaults.NgramLength,\n+            int skipLength = Defaults.SkipLength,\n+            bool allLengths = Defaults.AllLength,\n+            int maxNumTerms = Defaults.MaxNumTerms,\n+            WeightingCriteria weighting = Defaults.Weighting)\n+            : this(env, columns.Select(x => new NgramTransformer.ColumnInfo(x.input, x.output, ngramLength, skipLength, allLengths, weighting, maxNumTerms)).ToArray())\n+        {\n+        }\n+\n+        public NgramEstimator(IHostEnvironment env, params NgramTransformer.ColumnInfo[] columns)","path":"src/Microsoft.ML.Transforms/Text/NgramTransform.cs","position":1145,"original_position":1145,"commit_id":"6b72e67726e916a27465b0a74ecf1d067eef466f","original_commit_id":"6b72e67726e916a27465b0a74ecf1d067eef466f","user":{"login":"Zruty0","id":41337831,"node_id":"MDQ6VXNlcjQxMzM3ODMx","avatar_url":"https://avatars1.githubusercontent.com/u/41337831?v=4","gravatar_id":"","url":"https://api.github.com/users/Zruty0","html_url":"https://github.com/Zruty0","followers_url":"https://api.github.com/users/Zruty0/followers","following_url":"https://api.github.com/users/Zruty0/following{/other_user}","gists_url":"https://api.github.com/users/Zruty0/gists{/gist_id}","starred_url":"https://api.github.com/users/Zruty0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zruty0/subscriptions","organizations_url":"https://api.github.com/users/Zruty0/orgs","repos_url":"https://api.github.com/users/Zruty0/repos","events_url":"https://api.github.com/users/Zruty0/events{/privacy}","received_events_url":"https://api.github.com/users/Zruty0/received_events","type":"User","site_admin":false},"body":">public [](start = 8, length = 6)\r\n\r\nneeds a summary comment","created_at":"2018-11-15T02:36:22Z","updated_at":"2018-11-15T02:36:22Z","html_url":"https://github.com/dotnet/machinelearning/pull/1592#discussion_r233694799","pull_request_url":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/comments/233694799"},"html":{"href":"https://github.com/dotnet/machinelearning/pull/1592#discussion_r233694799"},"pull_request":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592","id":229831967,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI5ODMxOTY3","html_url":"https://github.com/dotnet/machinelearning/pull/1592","diff_url":"https://github.com/dotnet/machinelearning/pull/1592.diff","patch_url":"https://github.com/dotnet/machinelearning/pull/1592.patch","issue_url":"https://api.github.com/repos/dotnet/machinelearning/issues/1592","number":1592,"state":"open","locked":false,"title":"Convert Ngram transform to estimator/transformer","user":{"login":"Ivanidzo4ka","id":1523833,"node_id":"MDQ6VXNlcjE1MjM4MzM=","avatar_url":"https://avatars3.githubusercontent.com/u/1523833?v=4","gravatar_id":"","url":"https://api.github.com/users/Ivanidzo4ka","html_url":"https://github.com/Ivanidzo4ka","followers_url":"https://api.github.com/users/Ivanidzo4ka/followers","following_url":"https://api.github.com/users/Ivanidzo4ka/following{/other_user}","gists_url":"https://api.github.com/users/Ivanidzo4ka/gists{/gist_id}","starred_url":"https://api.github.com/users/Ivanidzo4ka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ivanidzo4ka/subscriptions","organizations_url":"https://api.github.com/users/Ivanidzo4ka/orgs","repos_url":"https://api.github.com/users/Ivanidzo4ka/repos","events_url":"https://api.github.com/users/Ivanidzo4ka/events{/privacy}","received_events_url":"https://api.github.com/users/Ivanidzo4ka/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-11-09T22:04:31Z","updated_at":"2018-11-15T02:36:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dbc6fd5a28742eca7f082c6f9afbd990660eea05","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592/commits","review_comments_url":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592/comments","review_comment_url":"https://api.github.com/repos/dotnet/machinelearning/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/machinelearning/issues/1592/comments","statuses_url":"https://api.github.com/repos/dotnet/machinelearning/statuses/6b72e67726e916a27465b0a74ecf1d067eef466f","head":{"label":"Ivanidzo4ka:Ivanidze/NgramEstimator","ref":"Ivanidze/NgramEstimator","sha":"6b72e67726e916a27465b0a74ecf1d067eef466f","user":{"login":"Ivanidzo4ka","id":1523833,"node_id":"MDQ6VXNlcjE1MjM4MzM=","avatar_url":"https://avatars3.githubusercontent.com/u/1523833?v=4","gravatar_id":"","url":"https://api.github.com/users/Ivanidzo4ka","html_url":"https://github.com/Ivanidzo4ka","followers_url":"https://api.github.com/users/Ivanidzo4ka/followers","following_url":"https://api.github.com/users/Ivanidzo4ka/following{/other_user}","gists_url":"https://api.github.com/users/Ivanidzo4ka/gists{/gist_id}","starred_url":"https://api.github.com/users/Ivanidzo4ka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ivanidzo4ka/subscriptions","organizations_url":"https://api.github.com/users/Ivanidzo4ka/orgs","repos_url":"https://api.github.com/users/Ivanidzo4ka/repos","events_url":"https://api.github.com/users/Ivanidzo4ka/events{/privacy}","received_events_url":"https://api.github.com/users/Ivanidzo4ka/received_events","type":"User","site_admin":false},"repo":{"id":132816008,"node_id":"MDEwOlJlcG9zaXRvcnkxMzI4MTYwMDg=","name":"machinelearning","full_name":"Ivanidzo4ka/machinelearning","private":false,"owner":{"login":"Ivanidzo4ka","id":1523833,"node_id":"MDQ6VXNlcjE1MjM4MzM=","avatar_url":"https://avatars3.githubusercontent.com/u/1523833?v=4","gravatar_id":"","url":"https://api.github.com/users/Ivanidzo4ka","html_url":"https://github.com/Ivanidzo4ka","followers_url":"https://api.github.com/users/Ivanidzo4ka/followers","following_url":"https://api.github.com/users/Ivanidzo4ka/following{/other_user}","gists_url":"https://api.github.com/users/Ivanidzo4ka/gists{/gist_id}","starred_url":"https://api.github.com/users/Ivanidzo4ka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ivanidzo4ka/subscriptions","organizations_url":"https://api.github.com/users/Ivanidzo4ka/orgs","repos_url":"https://api.github.com/users/Ivanidzo4ka/repos","events_url":"https://api.github.com/users/Ivanidzo4ka/events{/privacy}","received_events_url":"https://api.github.com/users/Ivanidzo4ka/received_events","type":"User","site_admin":false},"html_url":"https://github.com/Ivanidzo4ka/machinelearning","description":"ML.NET is an open source and cross-platform machine learning framework for .NET.","fork":true,"url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning","forks_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/forks","keys_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/teams","hooks_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/hooks","issue_events_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/issues/events{/number}","events_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/events","assignees_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/assignees{/user}","branches_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/branches{/branch}","tags_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/tags","blobs_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/git/refs{/sha}","trees_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/statuses/{sha}","languages_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/languages","stargazers_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/stargazers","contributors_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/contributors","subscribers_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/subscribers","subscription_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/subscription","commits_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/commits{/sha}","git_commits_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/git/commits{/sha}","comments_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/comments{/number}","issue_comment_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/issues/comments{/number}","contents_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/contents/{+path}","compare_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/merges","archive_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/downloads","issues_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/issues{/number}","pulls_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/pulls{/number}","milestones_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/milestones{/number}","notifications_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/labels{/name}","releases_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/releases{/id}","deployments_url":"https://api.github.com/repos/Ivanidzo4ka/machinelearning/deployments","created_at":"2018-05-09T21:45:41Z","updated_at":"2018-11-15T01:23:58Z","pushed_at":"2018-11-15T02:30:50Z","git_url":"git://github.com/Ivanidzo4ka/machinelearning.git","ssh_url":"git@github.com:Ivanidzo4ka/machinelearning.git","clone_url":"https://github.com/Ivanidzo4ka/machinelearning.git","svn_url":"https://github.com/Ivanidzo4ka/machinelearning","homepage":"http://dot.net/ml","size":29162,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"057c4b97bb4fab09b8f88db2300644660f46aa5d","user":{"login":"dotnet","id":9141961,"node_id":"MDEyOk9yZ2FuaXphdGlvbjkxNDE5NjE=","avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":132021166,"node_id":"MDEwOlJlcG9zaXRvcnkxMzIwMjExNjY=","name":"machinelearning","full_name":"dotnet/machinelearning","private":false,"owner":{"login":"dotnet","id":9141961,"node_id":"MDEyOk9yZ2FuaXphdGlvbjkxNDE5NjE=","avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/dotnet/machinelearning","description":"ML.NET is an open source and cross-platform machine learning framework for .NET.","fork":false,"url":"https://api.github.com/repos/dotnet/machinelearning","forks_url":"https://api.github.com/repos/dotnet/machinelearning/forks","keys_url":"https://api.github.com/repos/dotnet/machinelearning/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/machinelearning/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/machinelearning/teams","hooks_url":"https://api.github.com/repos/dotnet/machinelearning/hooks","issue_events_url":"https://api.github.com/repos/dotnet/machinelearning/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/machinelearning/events","assignees_url":"https://api.github.com/repos/dotnet/machinelearning/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/machinelearning/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/machinelearning/tags","blobs_url":"https://api.github.com/repos/dotnet/machinelearning/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/machinelearning/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/machinelearning/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/machinelearning/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/machinelearning/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/machinelearning/languages","stargazers_url":"https://api.github.com/repos/dotnet/machinelearning/stargazers","contributors_url":"https://api.github.com/repos/dotnet/machinelearning/contributors","subscribers_url":"https://api.github.com/repos/dotnet/machinelearning/subscribers","subscription_url":"https://api.github.com/repos/dotnet/machinelearning/subscription","commits_url":"https://api.github.com/repos/dotnet/machinelearning/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/machinelearning/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/machinelearning/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/machinelearning/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/machinelearning/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/machinelearning/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/machinelearning/merges","archive_url":"https://api.github.com/repos/dotnet/machinelearning/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/machinelearning/downloads","issues_url":"https://api.github.com/repos/dotnet/machinelearning/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/machinelearning/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/machinelearning/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/machinelearning/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/machinelearning/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/machinelearning/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/machinelearning/deployments","created_at":"2018-05-03T16:20:42Z","updated_at":"2018-11-15T01:19:23Z","pushed_at":"2018-11-15T02:31:01Z","git_url":"git://github.com/dotnet/machinelearning.git","ssh_url":"git@github.com:dotnet/machinelearning.git","clone_url":"https://github.com/dotnet/machinelearning.git","svn_url":"https://github.com/dotnet/machinelearning","homepage":"https://dot.net/ml","size":28113,"stargazers_count":4131,"watchers_count":4131,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":774,"mirror_url":null,"archived":false,"open_issues_count":367,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":774,"open_issues":367,"watchers":4131,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592"},"html":{"href":"https://github.com/dotnet/machinelearning/pull/1592"},"issue":{"href":"https://api.github.com/repos/dotnet/machinelearning/issues/1592"},"comments":{"href":"https://api.github.com/repos/dotnet/machinelearning/issues/1592/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/machinelearning/pulls/1592/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/machinelearning/statuses/6b72e67726e916a27465b0a74ecf1d067eef466f"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"Zruty0"}}