54

I'm looking for an efficient way to convert a series to a tuple of its index with its values.

s = pd.Series([1, 2, 3], ['a', 'b', 'c'])

I want an array, list, series, some iterable:

[(1, 'a'), (2, 'b'), (3, 'c')]
smci
  • 32,567
  • 20
  • 113
  • 146
piRSquared
  • 285,575
  • 57
  • 475
  • 624
  • 2
    That `pd.Series()` call actually makes `['a', 'b', 'c']` the index and `[1, 2, 3]` the data, not what you might expect. But your example suggests you want 1,2,3 first hence to be the index. `list(s.items())` gives `[('a', 1), ('b', 2), ('c', 3)]`. So it seems to be what you need; maybe you just need to flip index and data in the declaration. – smci Dec 10 '20 at 01:10

3 Answers3

63

Well it seems simply zip(s,s.index) works too!

For Python-3.x, we need to wrap it with list -

list(zip(s,s.index))

To get a tuple of tuples, use tuple() : tuple(zip(s,s.index)).

Sample run -

In [8]: s
Out[8]: 
a    1
b    2
c    3
dtype: int64

In [9]: list(zip(s,s.index))
Out[9]: [(1, 'a'), (2, 'b'), (3, 'c')]

In [10]: tuple(zip(s,s.index))
Out[10]: ((1, 'a'), (2, 'b'), (3, 'c'))
Divakar
  • 218,885
  • 19
  • 262
  • 358
31

s.items() or s.iteritems() do this.

(If you want to get the output as a list rather than an iterator, do: list(s.items()))

smci
  • 32,567
  • 20
  • 113
  • 146
9

One possibility is to swap the order of the index elements and the values from iteritems:

res = [(val, idx) for idx, val in s.iteritems()]

EDIT: @Divakar's answer is faster by about a factor of 2. Building a series of random strings for testing:

N = 100000
str_len = 4
ints = range(N)
strs = [None]*N
for i in ints:
    strs[i] = ''.join(random.choice(string.ascii_letters) for _ in range(str_len))
s = pd.Series(ints, strs)

Timings:

%timeit res = zip(s,s.index)
>>> 100 loops, best of 3: 14.8 ms per loop

%timeit res = [(val, idx) for idx, val in s.iteritems()]
>>> 10 loops, best of 3: 26.7 ms per loop
abeboparebop
  • 7,396
  • 6
  • 37
  • 46