13
13
from pandas .util .compat import OrderedDict
14
14
import pandas .core .algorithms as algos
15
15
import pandas .core .common as com
16
- from pandas .core .common import _possibly_downcast_to_dtype
16
+ from pandas .core .common import _possibly_downcast_to_dtype , notnull
17
17
18
18
import pandas .lib as lib
19
19
import pandas .algos as _algos
@@ -75,7 +75,7 @@ def f(self):
75
75
def _first_compat (x , axis = 0 ):
76
76
def _first (x ):
77
77
x = np .asarray (x )
78
- x = x [com . notnull (x )]
78
+ x = x [notnull (x )]
79
79
if len (x ) == 0 :
80
80
return np .nan
81
81
return x [0 ]
@@ -89,7 +89,7 @@ def _first(x):
89
89
def _last_compat (x , axis = 0 ):
90
90
def _last (x ):
91
91
x = np .asarray (x )
92
- x = x [com . notnull (x )]
92
+ x = x [notnull (x )]
93
93
if len (x ) == 0 :
94
94
return np .nan
95
95
return x [- 1 ]
@@ -421,7 +421,7 @@ def ohlc(self):
421
421
422
422
def nth (self , n ):
423
423
def picker (arr ):
424
- arr = arr [com . notnull (arr )]
424
+ arr = arr [notnull (arr )]
425
425
if len (arr ) >= n + 1 :
426
426
return arr .iget (n )
427
427
else :
@@ -1897,19 +1897,46 @@ def transform(self, func, *args, **kwargs):
1897
1897
gen = self .grouper .get_iterator (obj , axis = self .axis )
1898
1898
1899
1899
if isinstance (func , basestring ):
1900
- wrapper = lambda x : getattr (x , func )(* args , ** kwargs )
1900
+ fast_path = lambda group : getattr (group , func )(* args , ** kwargs )
1901
+ slow_path = lambda group : group .apply (lambda x : getattr (x , func )(* args , ** kwargs ), axis = self .axis )
1901
1902
else :
1902
- wrapper = lambda x : func (x , * args , ** kwargs )
1903
+ fast_path = lambda group : func (group , * args , ** kwargs )
1904
+ slow_path = lambda group : group .apply (lambda x : func (x , * args , ** kwargs ), axis = self .axis )
1903
1905
1906
+ path = None
1904
1907
for name , group in gen :
1905
1908
object .__setattr__ (group , 'name' , name )
1906
1909
1907
- try :
1908
- res = group .apply (wrapper , axis = self .axis )
1909
- except TypeError :
1910
- return self ._transform_item_by_item (obj , wrapper )
1911
- except Exception : # pragma: no cover
1912
- res = wrapper (group )
1910
+ # decide on a fast path
1911
+ if path is None :
1912
+
1913
+ path = slow_path
1914
+ try :
1915
+ res = slow_path (group )
1916
+
1917
+ # if we make it here, test if we can use the fast path
1918
+ try :
1919
+ res_fast = fast_path (group )
1920
+
1921
+ # compare that we get the same results
1922
+ if res .shape == res_fast .shape :
1923
+ res_r = res .values .ravel ()
1924
+ res_fast_r = res_fast .values .ravel ()
1925
+ mask = notnull (res_r )
1926
+ if (res_r [mask ] == res_fast_r [mask ]).all ():
1927
+ path = fast_path
1928
+
1929
+ except :
1930
+ pass
1931
+ except TypeError :
1932
+ return self ._transform_item_by_item (obj , fast_path )
1933
+ except Exception : # pragma: no cover
1934
+ res = fast_path (group )
1935
+ path = fast_path
1936
+
1937
+ else :
1938
+
1939
+ res = path (group )
1913
1940
1914
1941
# broadcasting
1915
1942
if isinstance (res , Series ):
@@ -1925,7 +1952,8 @@ def transform(self, func, *args, **kwargs):
1925
1952
concat_index = obj .columns if self .axis == 0 else obj .index
1926
1953
concatenated = concat (applied , join_axes = [concat_index ],
1927
1954
axis = self .axis , verify_integrity = False )
1928
- return concatenated .reindex_like (obj )
1955
+ concatenated .sort_index (inplace = True )
1956
+ return concatenated
1929
1957
1930
1958
def _transform_item_by_item (self , obj , wrapper ):
1931
1959
# iterate through columns
0 commit comments