Repository: pandas-dev/pandas

Issue:
DataFrame.apply not working with datetimes
When you use apply on a DataFrame with datetimes in, the result is unexpected. This is a dataframe with just integers and strings and the result is that we get the market names back out.

``` python
positions = pd.DataFrame([[1, 'ABC', 50], [1, 'YUM', 20], 
                          [1, 'DEF', 20], [2, 'ABC', 50],
                          [2, 'YUM', 20], [2, 'DEF', 20]],
                         columns=['a', 'market', 'position'])
positions.apply(lambda r: r['market'], axis=1)
Out[210]: 
0    ABC
1    YUM
2    DEF
3    ABC
4    YUM
5    DEF
dtype: object
```

If we replace the data in column 'a' with datetimes, then we get the wrong result - the first value in the market column is repeated:

``` python
import datetime

positions = pd.DataFrame([[datetime.datetime(2013, 1, 1), 'ABC', 50], 
                           [datetime.datetime(2013, 1, 1), 'YUM', 20],
                           [datetime.datetime(2013, 1, 1), 'DEF', 20],
                           [datetime.datetime(2013, 1, 2), 'ABC', 50],
                           [datetime.datetime(2013, 1, 2), 'YUM', 20], 
                           [datetime.datetime(2013, 1, 2), 'DEF', 20]],
                          columns=['a', 'market', 'position'])
positions.apply(lambda r: r['market'], axis=1)
Out[213]: 
0    ABC
1    ABC
2    ABC
3    ABC
4    ABC
5    ABC
dtype: object
```

If you replace the lambda function with a function which prints the object passed in, then you can see that you only ever receive the first row of the dataframe:

``` python
def print_input(r):
    print r
    return 1

positions.apply(print_input, axis=1)
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 0, dtype: object
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 1, dtype: object
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 2, dtype: object
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 3, dtype: object
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 4, dtype: object
a           2013-01-01 00:00:00
market                      ABC
position                     50
Name: 5, dtype: object
Out[215]: 
0    1
1    1
2    1
3    1
4    1
5    1
dtype: int64
```

This is new in the master, I didn't see it in pandas 0.11.0 or 0.13.0. 



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -3341,10 +3341,16 @@ def _apply_raw(self, func, axis):
 
     def _apply_standard(self, func, axis, ignore_failures=False, reduce=True):
 
+        # skip if we are mixed datelike and trying reduce across axes
+        # GH6125
+        if reduce and axis==1 and self._is_mixed_type and self._is_datelike_mixed_type:
+            reduce=False
+
         # try to reduce first (by default)
         # this only matters if the reduction in values is of different dtype
         # e.g. if we want to apply to a SparseFrame, then can't directly reduce
         if reduce:
+
             try:
 
                 # the is the fast-path


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -9215,6 +9215,28 @@ def transform2(row):
             self.assertEqual(e.args[1], 'occurred at index 4')
             self.assertEqual(e.args[0], "'float' object has no attribute 'startswith'")
 
+    def test_apply_bug(self):
+
+        # GH 6125
+        import datetime
+        positions = pd.DataFrame([[1, 'ABC0', 50], [1, 'YUM0', 20],
+                                  [1, 'DEF0', 20], [2, 'ABC1', 50],
+                                  [2, 'YUM1', 20], [2, 'DEF1', 20]],
+                                 columns=['a', 'market', 'position'])
+        def f(r):
+            return r['market']
+        expected = positions.apply(f, axis=1)
+
+        positions = DataFrame([[datetime.datetime(2013, 1, 1), 'ABC0', 50],
+                               [datetime.datetime(2013, 1, 2), 'YUM0', 20],
+                               [datetime.datetime(2013, 1, 3), 'DEF0', 20],
+                               [datetime.datetime(2013, 1, 4), 'ABC1', 50],
+                               [datetime.datetime(2013, 1, 5), 'YUM1', 20],
+                               [datetime.datetime(2013, 1, 6), 'DEF1', 20]],
+                                                columns=['a', 'market', 'position'])
+        result = positions.apply(f, axis=1)
+        assert_series_equal(result,expected)
+
     def test_swapaxes(self):
         df = DataFrame(np.random.randn(10, 5))
         assert_frame_equal(df.T, df.swapaxes(0, 1))