7

I'm trying to return two different values from an apply method but I cant figure out how to get the results I need.

With a function as:

def fun(row):
    s = [sum(row[i:i+2]) for i in range (len(row) -1)]
    ps = s.index(max(s))
    return max(s),ps

and df as:

    6:00    6:15    6:30    
0   3       8       9       
1   60      62      116     

I'm trying to return the max value of the row, but i also need to get the index of the first value that produces the max combination.

df["phour"] = t.apply(fun, axis=1)

I can get the output I need, but I don't know how I can get the index in a new column.So far im getting both answer in a tuple

    6:00    6:15    6:30    phour
0   3       8       9       (17, 1)
1   60      62      116     (178, 1)

How can I get the index value in its own column?

Daniel
  • 5,095
  • 5
  • 35
  • 48
  • Possible duplicate of [Returning multiple values from pandas apply on a DataFrame](http://stackoverflow.com/questions/10751127/returning-multiple-values-from-pandas-apply-on-a-dataframe) – Gordon Bean Apr 13 '17 at 17:29

5 Answers5

8

You can get the index in a separate column like this:

df[['phour','index']] = df.apply(lambda row: pd.Series(list(fun(row))), axis=1)

Or if you modify fun slightly:

def fun(row):
    s = [sum(row[i:i+2]) for i in range (len(row) -1)]
    ps = s.index(max(s))
    return [max(s),ps]

Then the code becomes a little less convoluted:

 df[['phour','index']] = df.apply(lambda row: pd.Series(fun(row)), axis=1)
Dmytro Bugayev
  • 606
  • 9
  • 13
7

You can apply pd.Series

df.drop('Double', 1).join(df.Double.apply(pd.Series, index=['D1', 'D2']))

   A  B  C  D1  D2
0  1  2  3   1   2
1  2  3  2   3   4
2  3  4  4   5   6
3  4  1  1   7   8

Equivalently

df.drop('Double', 1).join(
    pd.DataFrame(np.array(df.Double.values.tolist()), columns=['D1', 'D2'])
)

setup
using @GordonBean's df

df = pd.DataFrame({'A':[1,2,3,4], 'B':[2,3,4,1], 'C':[3,2,4,1], 'Double': [(1,2), (3,4), (5,6), (7,8)]})
piRSquared
  • 285,575
  • 57
  • 475
  • 624
2

If you are just trying to get the max and argmax, I recommend using the pandas API:

DataFrame.idxmax

So:

df = pd.DataFrame({'A':[1,2,3,4], 'B':[2,3,4,1], 'C':[3,2,4,1]})
df

    A   B   C
0   1   2   3
1   2   3   2
2   3   4   4
3   4   1   1

df['Max'] = df.max(axis=1)
df['ArgMax'] = df.idxmax(axis=1)
df    

    A   B   C   Max ArgMax
0   1   2   3   3   C
1   2   3   2   3   B
2   3   4   4   4   B
3   4   1   1   4   A

Update:
And if you need the actual index value, you can use numpy.ndarray.argmax:

df['ArgMaxNum'] = df[['A','B','C']].values.argmax(axis=1)


    A   B   C   Max ArgMax  ArgMaxNum
0   1   2   3   3   C   2
1   2   3   2   3   B   1
2   3   4   4   4   B   1
3   4   1   1   4   A   0
Gordon Bean
  • 4,272
  • 1
  • 32
  • 47
  • I need to get the max of the consecutive values of each row. Using the first row as an example I need to pick between 11 and 17, and know where the index from the max sequence started – Daniel Apr 13 '17 at 17:14
  • Ah, I see. I'll add another answer. – Gordon Bean Apr 13 '17 at 17:16
2

One way to split out the tuples into separate columns could be with tuple unpacking:

df = pd.DataFrame({'A':[1,2,3,4], 'B':[2,3,4,1], 'C':[3,2,4,1], 'Double': [(1,2), (3,4), (5,6), (7,8)]})
df


    A   B   C   Double
0   1   2   3   (1, 2)
1   2   3   2   (3, 4)
2   3   4   4   (5, 6)
3   4   1   1   (7, 8)

df['D1'] = [d[0] for d in df.Double]
df['D2'] = [d[1] for d in df.Double]
df


    A   B   C   Double  D1  D2
0   1   2   3   (1, 2)  1   2
1   2   3   2   (3, 4)  3   4
2   3   4   4   (5, 6)  5   6
3   4   1   1   (7, 8)  7   8
Gordon Bean
  • 4,272
  • 1
  • 32
  • 47
  • Thanks this works. It might not be the best and more recommended approach, but it will suffice for what i need. – Daniel Apr 13 '17 at 17:24
1

There's got to be a better way but you can do:

df.merge(pd.DataFrame(((i,j) for 
                       i,j in df.apply(lambda x: fun(x)).values),
                      columns=['phour','index']),
         left_index=True,right_index=True)
mechanical_meat
  • 163,903
  • 24
  • 228
  • 223
  • Thanks for the answer, this works as well, but honestly i cant understand exactly whats going on with the code. I can follow @Gordon Bean a lot better. – Daniel Apr 13 '17 at 17:23