# Buggy code
def evaluate(tokenizer, textcat, texts, cats):
    docs = (tokenizer(text) for text in texts)
    tp = 1e-8  # True positives
    fp = 1e-8  # False positives
    fn = 1e-8  # False negatives
    tn = 1e-8  # True negatives
    for i, doc in enumerate(textcat.pipe(docs)):
        gold = cats[i]
        for label, score in doc.cats.items():
            if label not in gold:
                continue
            if score >= 0.5 and gold[label] >= 0.5:
                tp += 1.0
            elif score >= 0.5 and gold[label] < 0.5:
                fp += 1.0
            elif score < 0.5 and gold[label] < 0.5:
                tn += 1
            elif score < 0.5 and gold[label] >= 0.5:
                fn += 1
    precision = tp / (tp + fp)
    recall = tp / (tp + fn)
    f_score = 2 * (precision * recall) / (precision + recall)
    return {"textcat_p": precision, "textcat_r": recall, "textcat_f": f_score}


# Traceback (TypeError)
$ python scripts/train_textcat.py
Created blank 'en' model
Loading IMDB data...
Using 2000 examples (1600 training, 400 evaluation)
Training the model...
LOSS      P       R       F
Traceback (most recent call last):
File "scripts/train_textcat.py", line 133, in <module>
plac.call(main)
File "/home/motoki/aes/lib/python3.6/site-packages/plac_core.py", line 328, in call
cmd, result = parser.consume(arglist)
File "/home/motoki/aes/lib/python3.6/site-packages/plac_core.py", line 207, in consume
return cmd, self.func(*(args + varargs + extraopts), **kwargs)
File "scripts/train_textcat.py", line 68, in main
losses=losses)
File "/home/motoki/aes/lib/python3.6/site-packages/spacy/language.py", line 407, in update
proc.update(docs, golds, drop=drop, sgd=get_grads, losses=losses)
File "pipeline.pyx", line 817, in spacy.pipeline.TextCategorizer.update
File "/home/motoki/aes/lib/python3.6/site-packages/thinc/api.py", line 61, in begin_update
X, inc_layer_grad = layer.begin_update(X, drop=drop)
File "/home/motoki/aes/lib/python3.6/site-packages/thinc/api.py", line 176, in begin_update
values = [fwd(X, *a, **k) for fwd in forward]
File "/home/motoki/aes/lib/python3.6/site-packages/thinc/api.py", line 176, in <listcomp>
values = [fwd(X, *a, **k) for fwd in forward]
File "/home/motoki/aes/lib/python3.6/site-packages/thinc/api.py", line 258, in wrap
output = func(*args, **kwargs)
File "/home/motoki/aes/lib/python3.6/site-packages/thinc/api.py", line 61, in begin_update
X, inc_layer_grad = layer.begin_update(X, drop=drop)
File "/home/motoki/aes/lib/python3.6/site-packages/spacy/_ml.py", line 101, in _preprocess_doc
keys = ops.xp.concatenate(keys)
File "/home/motoki/aes/lib/python3.6/site-packages/cupy/manipulation/join.py", line 49, in concatenate
return core.concatenate_method(tup, axis)
File "cupy/core/core.pyx", line 2410, in cupy.core.core.concatenate_method
File "cupy/core/core.pyx", line 2422, in cupy.core.core.concatenate_method
TypeError: Only cupy arrays can be concatenated

# Fixed code
def evaluate(tokenizer, textcat, texts, cats):
    docs = (tokenizer(text) for text in texts)
    tp = 0.0  # True positives
    fp = 1e-8  # False positives
    fn = 1e-8  # False negatives
    tn = 0.0  # True negatives
    for i, doc in enumerate(textcat.pipe(docs)):
        gold = cats[i]
        for label, score in doc.cats.items():
            if label not in gold:
                continue
            if label == "NEGATIVE":
                continue
            if score >= 0.5 and gold[label] >= 0.5:
                tp += 1.0
            elif score >= 0.5 and gold[label] < 0.5:
                fp += 1.0
            elif score < 0.5 and gold[label] < 0.5:
                tn += 1
            elif score < 0.5 and gold[label] >= 0.5:
                fn += 1
    precision = tp / (tp + fp)
    recall = tp / (tp + fn)
    f_score = 2 * (precision * recall) / (precision + recall)
    return {"textcat_p": precision, "textcat_r": recall, "textcat_f": f_score}