Repository: piskvorky/gensim

Issue:
D2VTransformer.fit_transform doesn't work
The **X** parameter of the **fit_transform** method of **D2VTransformer** doesn't accept variables of any type, nor list of token lists (raises _AttributeError: 'list' object has no attribute 'words'_), nor list of TaggedDocument (raises _TypeError: sequence item 0: expected str instance, list found_).

Example:
```python
from gensim.sklearn_api import D2VTransformer
from gensim.models import doc2vec

class_dict = {'mathematics': 1, 'physics': 0}
train_data = [
    (['calculus', 'mathematical'], 'mathematics'), (['geometry', 'operations', 'curves'], 'mathematics'),
    (['natural', 'nuclear'], 'physics'), (['science', 'electromagnetism', 'natural'], 'physics')
]
d2v_sentences = [doc2vec.TaggedDocument(words[0], [i]) for i, words in enumerate(train_data)]
train_input = list(map(lambda x: x[0], train_data))
train_target = list(map(lambda x: class_dict[x[1]], train_data))

model = D2VTransformer(min_count=1)
model.fit_transform(train_input, train_target)
#model.fit_transform(d2v_sentences, train_target)
```
Versions:
Windows-10-10.0.16299-SP0
Python 3.6.4 | packaged by conda-forge | (default, Dec 24 2017, 10:11:43) [MSC v.1900 64 bit (AMD64)]
NumPy 1.13.3
SciPy 0.19.1
gensim 3.2.0
FAST_VERSION 1


Discussion:
Thanks for report @volj1!
@chinmayapancholi13 can you look into this? This looks really suspicious.
@menshikh-iv Sure Ivan. I'll try to look into the reason for this behavior.

Resolving patch:
diff --git a/gensim/sklearn_api/d2vmodel.py b/gensim/sklearn_api/d2vmodel.py
--- a/gensim/sklearn_api/d2vmodel.py
+++ b/gensim/sklearn_api/d2vmodel.py
@@ -15,6 +15,7 @@
 from sklearn.exceptions import NotFittedError
 
 from gensim import models
+from gensim.models import doc2vec
 
 
 class D2VTransformer(TransformerMixin, BaseEstimator):
@@ -63,8 +64,12 @@ def fit(self, X, y=None):
         Fit the model according to the given training data.
         Calls gensim.models.Doc2Vec
         """
+        if isinstance(X[0], doc2vec.TaggedDocument):
+            d2v_sentences = X
+        else:
+            d2v_sentences = [doc2vec.TaggedDocument(words, [i]) for i, words in enumerate(X)]
         self.gensim_model = models.Doc2Vec(
-            documents=X, dm_mean=self.dm_mean, dm=self.dm,
+            documents=d2v_sentences, dm_mean=self.dm_mean, dm=self.dm,
             dbow_words=self.dbow_words, dm_concat=self.dm_concat, dm_tag_count=self.dm_tag_count,
             docvecs=self.docvecs, docvecs_mapfile=self.docvecs_mapfile, comment=self.comment,
             trim_rule=self.trim_rule, size=self.size, alpha=self.alpha, window=self.window,


Test patch:
diff --git a/gensim/test/test_sklearn_api.py b/gensim/test/test_sklearn_api.py
--- a/gensim/test/test_sklearn_api.py
+++ b/gensim/test/test_sklearn_api.py
@@ -831,6 +831,21 @@ def testTransform(self):
         self.assertEqual(matrix.shape[0], 1)
         self.assertEqual(matrix.shape[1], self.model.size)
 
+    def testFitTransform(self):
+        model = D2VTransformer(min_count=1)
+
+        # fit and transform multiple documents
+        docs = [w2v_texts[0], w2v_texts[1], w2v_texts[2]]
+        matrix = model.fit_transform(docs)
+        self.assertEqual(matrix.shape[0], 3)
+        self.assertEqual(matrix.shape[1], model.size)
+
+        # fit and transform one document
+        doc = w2v_texts[0]
+        matrix = model.fit_transform(doc)
+        self.assertEqual(matrix.shape[0], 1)
+        self.assertEqual(matrix.shape[1], model.size)
+
     def testSetGetParams(self):
         # updating only one param
         self.model.set_params(negative=20)