Repository: blaze/blaze

Issue:
dshape of nunique not the same as the resulting object
``` python
In [14]: fx.date.nunique()
Out[14]: 5825.0

In [15]: fx.date.nunique().dshape
Out[15]: dshape("int32")
```



Discussion:

Resolving patch:
diff --git a/blaze/compute/numpy.py b/blaze/compute/numpy.py
--- a/blaze/compute/numpy.py
+++ b/blaze/compute/numpy.py
@@ -4,7 +4,7 @@
 
 import numpy as np
 from pandas import DataFrame, Series
-from datashape import to_numpy
+from datashape import to_numpy, to_numpy_dtype
 
 from ..expr import Reduction, Field, Projection, Broadcast, Selection, ndim
 from ..expr import Distinct, Sort, Head, Label, ReLabel, Expr, Slice
@@ -77,12 +77,19 @@ def compute_up(t, x, **kwargs):
     return -x
 
 
+inat = np.datetime64('NaT').view('int64')
+
+
 @dispatch(count, np.ndarray)
 def compute_up(t, x, **kwargs):
-    if np.issubdtype(x.dtype, np.float): # scalar dtype
+    if issubclass(x.dtype.type, (np.floating, np.object_)):
         return pd.notnull(x).sum(keepdims=t.keepdims, axis=t.axis)
+    elif issubclass(x.dtype.type, np.datetime64):
+        return (x.view('int64') != inat).sum(keepdims=t.keepdims, axis=t.axis)
     else:
-        return np.ones(x.shape).sum(keepdims=t.keepdims, axis=t.axis)
+        return np.ones(x.shape,
+                       dtype=to_numpy_dtype(t.dshape)).sum(keepdims=t.keepdims,
+                                                           axis=t.axis)
 
 
 @dispatch(nunique, np.ndarray)


Test patch:
diff --git a/blaze/compute/tests/test_bcolz_compute.py b/blaze/compute/tests/test_bcolz_compute.py
--- a/blaze/compute/tests/test_bcolz_compute.py
+++ b/blaze/compute/tests/test_bcolz_compute.py
@@ -12,10 +12,14 @@
 from blaze.compute.core import compute, pre_compute
 
 
-b = bcolz.ctable(np.array([(1, 1.), (2, 2.), (3, 3.)],
-                          dtype=[('a', 'i8'), ('b', 'f8')]))
+b = bcolz.ctable(np.array([(1, 1., np.datetime64('2010-01-01')),
+                           (2, 2., np.datetime64('NaT')),
+                           (3, 3., np.datetime64('2010-01-03'))],
+                          dtype=[('a', 'i8'),
+                                 ('b', 'f8'),
+                                 ('date', 'datetime64[D]')]))
 
-t = symbol('t', 'var * {a: int64, b: float64}')
+t = symbol('t', 'var * {a: int64, b: float64, date: ?date}')
 
 
 to = symbol('to', 'var * {a: int64, b: float64}')
@@ -24,7 +28,7 @@
 
 
 def test_discover():
-    assert discover(b) == dshape('3 * {a: int64, b: float64}')
+    assert discover(b) == dshape('3 * {a: int64, b: float64, date: date}')
     assert discover(b['a']) == dshape('3 * int64')
 
 
@@ -46,6 +50,19 @@ def test_reductions():
                                                            ddof=1)) < 1e-5
     assert len(list(compute(t.distinct(), b))) == 3
     assert len(list(compute(t.a.distinct(), b))) == 3
+
+    assert compute(t.a.nunique(), b) == 3
+    assert isinstance(compute(t.a.nunique(), b), np.integer)
+
+    assert compute(t.a.count(), b) == 3
+    assert isinstance(compute(t.date.count(), b), np.integer)
+
+    assert compute(t.date.nunique(), b) == 2
+    assert isinstance(compute(t.date.nunique(), b), np.integer)
+
+    assert compute(t.date.count(), b) == 2
+    assert isinstance(compute(t.a.count(), b), np.integer)
+
     assert compute(t.a[0], b) == 1
     assert compute(t.a[-1], b) == 3
     assert compute(t[0], b) == compute(t[0], b)
diff --git a/blaze/compute/tests/test_numpy_compute.py b/blaze/compute/tests/test_numpy_compute.py
--- a/blaze/compute/tests/test_numpy_compute.py
+++ b/blaze/compute/tests/test_numpy_compute.py
@@ -1,6 +1,7 @@
 from __future__ import absolute_import, division, print_function
 
 import numpy as np
+import numbers
 import pytest
 from datetime import datetime, date
 
@@ -81,6 +82,12 @@ def test_Reductions():
     assert compute(t['amount'][-1], x) == x['amount'][-1]
 
 
+def test_count_string():
+    s = symbol('name', 'var * ?string')
+    x = np.array(['Alice', np.nan, 'Bob', 'Denis', 'Edith'], dtype='object')
+    assert compute(s.count(), x) == 4
+
+
 def test_reductions_on_recarray():
     assert compute(t.count(), x) == len(x)