<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Series/Dataframes slicing and function application
Slicing
(from panda docs
Step1:  Slicing ranges
The most robust way to slice Dataframes is by using .loc and .iloc methods, however the following also holds
Step2:  Watchout... this is a rather incoherent use of the indexinf method over rows. That's why it is said that loc provides a more coherent use.
Step3:  The .loc attribute is the primary access method. The following are valid inputs
Step4:  Boolean accessing
Step5:  Accessing by position by .iloc
Step6:  Selection by callable
Step7:  Selection by isin
Step8:  The where() Method
Step9:  Applying Functions
Over series
Step10:  Over dataframes
<ASSISTANT_TASK:>
Python Code:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(8, 4), columns=['A', 'B', 'C', 'D'])
df["A"] #indexing
df.A #attribute
type(df.A)
df.A[0]
df[["A","B"]]
type(df[["A","B"]])
Explanation: Series/Dataframes slicing and function application
Slicing
(from panda docs: https://pandas.pydata.org/pandas-docs/stable/indexing.html)
The axis labeling information in pandas objects serves many purposes:
Identifies data (i.e. provides metadata) using known indicators, important for analysis, visualization, and interactive console display
Enables automatic and explicit data alignment
Allows intuitive getting and setting of subsets of the data set
 indexing operators: []
 attribute operators: .
Example:
End of explanation
s = df["A"]
s[:5]
s[::2]
s[::-1]
Explanation: Slicing ranges
The most robust way to slice Dataframes is by using .loc and .iloc methods, however the following also holds:
End of explanation
df[:3] # for convenience as it is a common use
df["A"]
Explanation: Watchout... this is a rather incoherent use of the indexinf method over rows. That's why it is said that loc provides a more coherent use.
End of explanation
df.loc[:,"B":]
df.loc[4:,"C":] = 0
df
Explanation: The .loc attribute is the primary access method. The following are valid inputs:
A single label, e.g. 5 or 'a', (note that 5 is interpreted as a label of the index. This use is not an integer position along the index)
A list or array of labels ['a', 'b', 'c']
A slice object with labels 'a':'f' (note that contrary to usual python slices, both the start and the stop are included!)
A boolean array
A callable, see Selection By Callable
End of explanation
df.loc[:,"A"]>0
df.loc[df.loc[:,"A"]>0]
Explanation: Boolean accessing
End of explanation
df.iloc[0,0]
df.iloc[3:,2:]
df.iloc[[0,1,3],[1,3]]
Explanation: Accessing by position by .iloc
End of explanation
df.loc[:,lambda df: df.columns == "A"]
Explanation: Selection by callable
End of explanation
df["X"] = range(0, df.shape[0])
df
df[df["X"].isin([0,2])]
Explanation: Selection by isin
End of explanation
df.where(df["A"]>0)
df.where(df["A"]>0,100)
Explanation: The where() Method
End of explanation
s * 2
s.max()
np.max(s)
s.apply(np.max)
def multiply_by_2(x):
    return x*2
s.apply(multiply_by_2)
s.apply(lambda x: x*2)
s.map(lambda x: x*2)
mydict={2:"a"}
df["X"].map(mydict)
Explanation: Applying Functions
Over series:
* Vectorized functions
* Apply/map
End of explanation
df.apply(np.max,axis=0)
df.apply(np.max,axis=1)
df.applymap(lambda x: x*2)
Explanation: Over dataframes:
* apply (we can decide which axis)
* applymap
End of explanation
<END_TASK>