<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 pandas Series Reindexing, filling, mutating, copying, and maps
Step1:  Now NaN values are treated differently in numpy than in pandas. In numpy, as we saw earlier if you’ve got an array with a NaN value, things like summary statistics are calculated as NaN.
Step2:  Pandas Series treat them differently, it just ignores that empty value. We’ll cover filling in those empty values at a later time.
Step3:  Sometimes you're going to have to make some new indexes. For example we've got two Series.
Step4:  Now at times you’re going to want to reindex a Series. What does this mean? Basically that you want to destroy the index you have currently and reset it. Let’s walk through a practical example.
Step5:  When we concatenate them, we can see we’ve got repeated index values. We can query just like we would normally by these index values, but in all likelihood we’ll want to replace them with a new one.
Step6:  However this is rather limited in what you can achieve. It just overwrites the index we have now. What happens if we’re looking to fill in missing data with nan values? We have to use reindex which will return a new Series.
Step7:  We can specify how to handle nan values with fill_value. or we can specify a method by which they should be filled. This can performed during the reindexing using the method parameter (like we did with fill_value), or we can do it after the fact.
Step8:  Here’s an example of fill which is forward fill
Step9:  and bfill or backward fill
Step10:  Fillna just fills the blanks with whatever value you specify.
Step11:  Now lastly I want to cover how we can merge different Series’ on certain values and perform simple arithmetic operations.
When s1 and s2 have the same index it’s easy to say add them together and get what we expect.
Step12:  However things get more complicated when they have different indices. Now when we try and add them it only does so on the overlapping index labels. Often times this may be what we want when we’re analyzing data but other times it’s not. In order to handle that we’ve got to do some reindexing and use fill values.
Step13:  Finally when we have multiple labels on an index that are the same and we try to bring these Series together with some sort of operation. We’re going to get some multiple. For example multiplying them is equal to performing a cartesian product or the two Series on those specific labels, in this example A.
Step14:  Adding them together means each one is added to each one.
Step15:  Lastly sometime you’re going to want to experiment with modification to Series or data frames. That can be done with the copy method which returns a copy of the data. That makes it easy to experiment with the data.
Step16:  There are a couple more methods I want to touch on, most specifically map.
Step17:  Maps are going to feel familiar from our raw python section, except we can do something a bit more special with the pandas Series Version. We can map it to a dictionary as well. This will perform a look up in the dictionary and return whatever is there.
Step18:  If it doesn't find the value there, it will return NaN
<ASSISTANT_TASK:>
Python Code:
%matplotlib inline
import sys
print(sys.version)
import numpy as np
print(np.__version__)
import pandas as pd
print(pd.__version__)
import matplotlib.pyplot as plt
Explanation: pandas Series Reindexing, filling, mutating, copying, and maps
End of explanation
np_array = np.array([1,2,3,np.nan])
np_array
np_array.mean()
pd_series = pd.Series([1,2,3,np.nan])
pd_series
Explanation: Now NaN values are treated differently in numpy than in pandas. In numpy, as we saw earlier if you’ve got an array with a NaN value, things like summary statistics are calculated as NaN.
End of explanation
pd_series.mean()
np.random.seed(567)
Explanation: Pandas Series treat them differently, it just ignores that empty value. We’ll cover filling in those empty values at a later time.
End of explanation
s1 = pd.Series(np.random.randn(5))
s1
s2 = pd.Series(np.random.randn(5))
s2
Explanation: Sometimes you're going to have to make some new indexes. For example we've got two Series.
End of explanation
combo = pd.concat([s1, s2])
combo
Explanation: Now at times you’re going to want to reindex a Series. What does this mean? Basically that you want to destroy the index you have currently and reset it. Let’s walk through a practical example.
End of explanation
combo[0]
combo.index = range(combo.count())
combo
Explanation: When we concatenate them, we can see we’ve got repeated index values. We can query just like we would normally by these index values, but in all likelihood we’ll want to replace them with a new one.
End of explanation
new_combo = combo.reindex([0,2,15,21])
new_combo
Explanation: However this is rather limited in what you can achieve. It just overwrites the index we have now. What happens if we’re looking to fill in missing data with nan values? We have to use reindex which will return a new Series.
End of explanation
combo.reindex([0,2,15,21], fill_value=0)
new_combo
Explanation: We can specify how to handle nan values with fill_value. or we can specify a method by which they should be filled. This can performed during the reindexing using the method parameter (like we did with fill_value), or we can do it after the fact.
End of explanation
new_combo.ffill()
Explanation: Here’s an example of fill which is forward fill
End of explanation
new_combo.bfill()
new_combo[21] = 5
new_combo
new_combo.bfill()
new_combo
Explanation: and bfill or backward fill
End of explanation
new_combo.fillna(12)
Explanation: Fillna just fills the blanks with whatever value you specify.
End of explanation
s1
s2
s1 + s2
Explanation: Now lastly I want to cover how we can merge different Series’ on certain values and perform simple arithmetic operations.
When s1 and s2 have the same index it’s easy to say add them together and get what we expect.
End of explanation
s2.index = list(range(3,8))
s2
s1 + s2
s1.reindex(range(10),fill_value=0) + s2.reindex(range(10),fill_value=0)
s2.index = range(5)
s1 = pd.Series(range(1,4), index= ['a','a','c'])
s1
s2 = pd.Series(range(1,4), index=['a','a','b'])
s2
Explanation: However things get more complicated when they have different indices. Now when we try and add them it only does so on the overlapping index labels. Often times this may be what we want when we’re analyzing data but other times it’s not. In order to handle that we’ve got to do some reindexing and use fill values.
End of explanation
s1 * s2
Explanation: Finally when we have multiple labels on an index that are the same and we try to bring these Series together with some sort of operation. We’re going to get some multiple. For example multiplying them is equal to performing a cartesian product or the two Series on those specific labels, in this example A.
End of explanation
s1 + s2
s1
Explanation: Adding them together means each one is added to each one.
End of explanation
s1_copy = s1.copy()
s1_copy['a'] = 3
s1_copy
s1
Explanation: Lastly sometime you’re going to want to experiment with modification to Series or data frames. That can be done with the copy method which returns a copy of the data. That makes it easy to experiment with the data.
End of explanation
s1.map(lambda x: x ** 2)
Explanation: There are a couple more methods I want to touch on, most specifically map.
End of explanation
s1.map({1:2,2:3,3:12})
Explanation: Maps are going to feel familiar from our raw python section, except we can do something a bit more special with the pandas Series Version. We can map it to a dictionary as well. This will perform a look up in the dictionary and return whatever is there.
End of explanation
s1.map({2:3,3:12})
Explanation: If it doesn't find the value there, it will return NaN
End of explanation
<END_TASK>