3

Is there a Series method that acts like update but returns the updated series instead of updating in place?

Put another way, is there a better way to do this:

# Original series
ser1 = Series([10, 9, 8, 7], index=[1,2,3,4])

# I want to change ser1 to be [10, 1, 2, 7]
adj_ser = Series([1, 2], index=[2,3])

adjusted = my_method(ser1, adj_ser)

# Is there a builtin that does this already?
def my_method(current_series, adjustments):
    x = current_series.copy()
    x.update(adjustments)
    return(x)
CodeJockey
  • 1,922
  • 1
  • 15
  • 20
  • 1
    I think the most easy is to use `x.iloc[1:3] = [1,2]` – yatu Dec 07 '18 at 15:18
  • 2
    nope, op doesn't want to modify the original series, but instead have a new Series with updated values. I'm afraid you will need to to the copy and the update –  Dec 07 '18 at 15:21
  • Yes that's why I specified `x`, so in the copied series. What's wrong with doing `x = ser1.copy()` and update `x` using `iloc`? – yatu Dec 07 '18 at 15:22
  • I should add that in the use case, I have two series already and want to return a third series containing the original updated with the new (this makes update a better choice than loc imho). Also this example happends to have a numerical index (so x.iloc is appropriate). In practice, the index is actually a datetime index. – CodeJockey Dec 07 '18 at 15:27
  • Well in that case you can use `loc`, but its the same – yatu Dec 07 '18 at 15:27
  • As per above. I have two series already, so to using loc looks like `x.loc[adjustments.index] = adjustments` which is not as nice as `x.update(adjustments)` unless it comes with some performance benefit etc. – CodeJockey Dec 07 '18 at 15:52

4 Answers4

1

One possible solution should be combine_first, but it update adj_ser by ser1, also it cast integers to floats:

adjusted = adj_ser.combine_first(ser1)
print (adjusted)
1    10.0
2     1.0
3     2.0
4     7.0
dtype: float64
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
0

@nixon is right that iloc and loc are good for this kind of thing

import pandas as pd
# Original series
ser1 = pd.Series([10, 9, 8, 7], index=[1,2,3,4])
ser2 = ser1.copy()
ser3 = ser1.copy()

# I want to change ser1 to be [10, 1, 2, 7]

# One way
ser2.iloc[1:3] = [1,2]
ser2 # [10, 1, 2, 7]


# Another way
ser3.loc[2, 3] = [1,2]
ser3 # [10, 1, 2, 7]

Why two different methods?

As this post explains quite well, the major difference between loc and iloc is labels vs position. My personal shorthand is if you're trying to make adjustments based on the zero-index position of a value use iloc otherwise loc. YMMV

Charles Landau
  • 4,187
  • 1
  • 8
  • 24
0

No built-in function other than update, but you can use mask with a Boolean series:

def my_method(current_series, adjustments):
    bools = current_series.index.isin(adjustments.index)
    return current_series.mask(bools, adjustments)

However, as the masking process introduces intermediary NaN values, your series will be upcasted to float. So your update solution is best.

jpp
  • 159,742
  • 34
  • 281
  • 339
0

Here is another way:

adjusted = ser1.mask(ser1.index.isin(adj_ser.index), adj_ser)
adjusted

Output:

1    10
2     1
3     2
4     7
dtype: int64
Scott Boston
  • 147,308
  • 15
  • 139
  • 187