import pandas as pd
import numpy as np

from numpy.random import randn
np.random.seed(101)

df = pd.DataFrame(randn(5,4),index='A B C D E'.split(),columns='W X Y Z'.split())

df

"""
Explanation: <a href='http://www.pieriandata.com'> <img src='../Pierian_Data_Logo.png' /></a>

DataFrames
DataFrames are the workhorse of pandas and are directly inspired by the R programming language. We can think of a DataFrame as a bunch of Series objects put together to share the same index. Let's use pandas to explore this topic!
End of explanation
"""


df['W']

# Pass a list of column names
df[['W','Z']]

# SQL Syntax (NOT RECOMMENDED!)
df.W

"""
Explanation: Selection and Indexing
Let's learn the various methods to grab data from a DataFrame
End of explanation
"""


type(df['W'])

"""
Explanation: DataFrame Columns are just Series
End of explanation
"""


df['new'] = df['W'] + df['Y']

df

"""
Explanation: Creating a new column:
End of explanation
"""


df.drop('new',axis=1)

# Not inplace unless specified!
df

df.drop('new',axis=1,inplace=True)

df

"""
Explanation: Removing Columns
End of explanation
"""


df.drop('E',axis=0)

"""
Explanation: Can also drop rows this way:
End of explanation
"""


df.loc['A']

"""
Explanation: Selecting Rows
End of explanation
"""


df.iloc[2]

"""
Explanation: Or select based off of position instead of label
End of explanation
"""


df.loc['B','Y']

df.loc[['A','B'],['W','Y']]

"""
Explanation: Selecting subset of rows and columns
End of explanation
"""


df

df>0

df[df>0]

df[df['W']>0]

df[df['W']>0]['Y']

df[df['W']>0][['Y','X']]

"""
Explanation: Conditional Selection
An important feature of pandas is conditional selection using bracket notation, very similar to numpy:
End of explanation
"""


df[(df['W']>0) & (df['Y'] > 1)]

"""
Explanation: For two conditions you can use | and & with parenthesis:
End of explanation
"""


df

# Reset to default 0,1...n index
df.reset_index()

newind = 'CA NY WY OR CO'.split()

df['States'] = newind

df

df.set_index('States')

df

df.set_index('States',inplace=True)

df

"""
Explanation: More Index Details
Let's discuss some more features of indexing, including resetting the index or setting it something else. We'll also talk about index hierarchy!
End of explanation
"""


# Index Levels
outside = ['G1','G1','G1','G2','G2','G2']
inside = [1,2,3,1,2,3]
hier_index = list(zip(outside,inside))
hier_index = pd.MultiIndex.from_tuples(hier_index)

hier_index

df = pd.DataFrame(np.random.randn(6,2),index=hier_index,columns=['A','B'])
df

"""
Explanation: Multi-Index and Index Hierarchy
Let us go over how to work with Multi-Index, first we'll create a quick example of what a Multi-Indexed DataFrame would look like:
End of explanation
"""


df.loc['G1']

df.loc['G1'].loc[1]

df.index.names

df.index.names = ['Group','Num']

df

df.xs('G1')

df.xs(['G1',1])

df.xs(1,level='Num')

"""
Explanation: Now let's show how to index this! For index hierarchy we use df.loc[], if this was on the columns axis, you would just use normal bracket notation df[]. Calling one level of the index returns the sub-dataframe:
End of explanation
"""


