<jupyter_start><jupyter_text><jupyter_code>import pandas as pd
import numpy as np<jupyter_output><empty_output><jupyter_text>**Tratando dados ausentes** **NaN** = Não é um número**NA** = Não avaliável (indisponível)<jupyter_code>string_data = pd.Series(['aardvark', 'artichoke', np.nan,'avocado'])
string_data
string_data.isnull()
string_data[0] = None
string_data.isnull()<jupyter_output><empty_output><jupyter_text>**Filtrando dados ausentes**<jupyter_code>from numpy import nan as NA
data = pd.Series([1,NA, 3.5,NA,7])
data.dropna()
#mesma coisa que o anterior
data[data.notnull()]
#descarta qualquer linha contendo valor ausente
data = pd.DataFrame([[1., 6.5, 3.],[1.,NA,NA],[NA,NA,NA],[NA,6.5,3.]])

cleaned = data.dropna()
data
cleaned
#descartar apenas as colunas que contenham NAs
data.dropna(how='all')

data[4] = NA
data
data.dropna(axis=1, how='all')
df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1] = NA
df.iloc[:2,2] = NA
df
df.dropna()
#deixar somente as linhas que tenham menos de 2 NaN
df.dropna(thresh=2)<jupyter_output><empty_output><jupyter_text>**Preenchendo valores ausentes**<jupyter_code>#passa por parametro o valor a ser preenchido
df.fillna(0)
#preencher com valores diferentes
df.fillna({1:0.5, 2:0})
#modificar o dataframe sem gerar uma cópia
_ = df.fillna(0, inplace=True)
df
df = pd.DataFrame(np.random.randn(6,3))

df.iloc[2:,1] = NA
df.iloc[4:,2] = NA
df
df.fillna(method ='ffill')
#numero máximo de valores a ser preenchido pra frente ou pra trás
df.fillna(method='ffill', limit=2)
data = pd.Series([1., NA, 3.5, NA, 7])
data.fillna(data.mean())<jupyter_output><empty_output><jupyter_text>**Transformação de dados**<jupyter_code>data = pd.DataFrame({'k1':['one','two'] * 3 + ['two'],
                     'k2':[1,1,2,3,3,4,4]})
data
#Esse metodo devolve um boolean
data.duplicated()
#devolve um dataframe onde o duplicado em false
data.drop_duplicates()
data['v1'] = range(7)

#identificando valores a partir de uma coluna
data.drop_duplicates(['k1'])
#mantem a ultima combinação de valores duplicados ao invés da primeira que aparece
data.drop_duplicates(['k1','k2'], keep='last')<jupyter_output><empty_output><jupyter_text>**Transformando dados usando uma função ou um mapeamento**<jupyter_code>data = pd.DataFrame({'food': ['bacon','pulled pork','bacon','Pastrami','corned beef','Bacon', 'pastrami','honey ham','nova lox'],
                     'ounces': [4,3,12,6,7.5,8,3,5,6]})
data
meat_to_animal = {
    'bacon':'pig',
    'pulled pork':'pig',
    'pastrami':'cow',
    'corned beef':'cow',
    'honey ham':'pig',
    'nova lox':'salmon'
}
lowercased = data['food'].str.lower()
lowercased
data['animal'] = lowercased.map(meat_to_animal)
data
#Uma função fazendo a mesma coisa
data['food'].map(lambda x: meat_to_animal[x.lower()])<jupyter_output><empty_output><jupyter_text>**Substituindo valores**<jupyter_code>data = pd.Series([1., -999., 2., -999., -1000., 3.])
data
data.replace(-999, np.nan)
data.replace([-999, -1000], np.nan)
data.replace([-999, -1000], [np.nan, 0])
data.replace({-999: np.nan, -1000:0})<jupyter_output><empty_output><jupyter_text>**Renomeando os índices dos eixos**<jupyter_code>data = pd.DataFrame(np.arange(12).reshape(3,4), index=['Ohio','Colorado','New York'], columns=['one','two','three','four'])
transform = lambda x: x[:4].upper()
data.index.map(transform)
data.index = data.index.map(transform)
data
data.rename(index=str.title, columns=str.upper)
data.rename(index={'OHIO':'INDIANA'}, columns={'three':'peekaboo'})
data.rename(index={'OHIO':'INDIANA'}, columns={'three':'peekaboo'}, inplace=True)
data<jupyter_output><empty_output><jupyter_text>**Discretização e compartimentalização (binning)**<jupyter_code>ages = [20,22, 25,27,21,23,37,31,61,45,41,32]
bins = [18,25,35,60,100]
cats = pd.cut(ages, bins)
cats
cats.codes
cats.categories
pd.value_counts(cats)
pd.cut(ages, [18,26,36,61,100], right = False)
group_names = ['Jovem', '<NAME>', 'Meia idade','Terceira idade']
pd.cut(ages, bins, labels=group_names)
data = np.random.rand(20)
#precision limita a precisão decimal de acordo com o valor do argumento, nesse caso aqui é 2 digitos
pd.cut(data, 4, precision=2)
data = np.random.randn(1000) #Normalmente distribuidos
cats = pd.qcut(data, 4) #Separa em quantis
cats
pd.value_counts(cats)
pd.qcut(data,[0, 0.1, 0.5, 0.9, 1.])<jupyter_output><empty_output><jupyter_text>**Detectando e filtrando valores discrepantes**<jupyter_code>data = pd.DataFrame(np.random.randn(1000, 4))
data.describe()
#Encontrar valores que excedem 3 na coluna
col =  data[2]
col[np.abs(col) > 3]
#Selecionar todas as linhas que exceda o valor 3 ou -3
data[(np.abs(data) > 3). any(1)]
#Eliminar os valores fora do intervalo -3 e 3
data[np.abs(data) > 3] = np.sign(data) * 3
data.describe()
np.sign(data).head()<jupyter_output><empty_output><jupyter_text>**Permutação e amostragem aleatória**<jupyter_code>df = pd.DataFrame(np.arange(5 * 4).reshape((5,4)))

sampler = np.random.permutation(5)
sampler
df
df.take(sampler)
#trás linhas aleatórias do dataframe, a quantidade pode ser passada por argumento. Nesse exemplo são 3
df.sample(n=3)
choices = pd.Series([5,7,-1,6,4])
#Gerar uma amostra com substituição
draws = choices.sample(n=10, replace=True)
draws<jupyter_output><empty_output><jupyter_text>**Calculando variáveis indicadoras/dummy**<jupyter_code>df = pd.DataFrame({'key': ['b','b','a','c','a','b'], 'data': range(6)})
pd.get_dummies(df['key'])
dummie = pd.get_dummies(df['key'], prefix='key')
df_with_dummy = df[['data']].join(dummie)
df_with_dummy<jupyter_output><empty_output><jupyter_text>**Separando muitas informações dentro de uma mesma célula**<jupyter_code>mnames = ['movie_id','title','genres']
movies = pd.read_table('/content/drive/MyDrive/dados_pandas/pydata-book-2nd-edition/datasets/movielens/movies.dat', sep='::', header=None, names=mnames)
movies[:10]
all_genres = []
for x in movies.genres:
  all_genres.extend(x.split('|'))
genres = pd.unique(all_genres)
genres
zero_matrix = np.zeros((len(movies), len(genres)))
dummies = pd.DataFrame(zero_matrix, columns=genres)
gen = movies.genres[0]
gen.split('|')
dummies.columns.get_indexer(gen.split('|'))
for i, gen in enumerate(movies.genres):
  indices = dummies.columns.get_indexer(gen.split('|'))
  dummies.iloc[i, indices] = 1
movies_windic = movies.join(dummies.add_prefix('Genre_'))
movies_windic.iloc[0]
np.random.seed(12345)
values = np.random.rand(10)
values
bins=[0, 0.2, 0.4, 0.6, 0.8, 1]
pd.get_dummies(pd.cut(values, bins))<jupyter_output><empty_output><jupyter_text>**Manipulação de strings** **Métodos de objetos string**<jupyter_code>val = 'a,b, guido'
val.split(',')
pieces = [x.strip() for x in val.split(',')]
pieces
first, second, thrid = pieces
first + '::' + second + '::' + thrid
#outro jeito de fazer a mesma coisa
'::'.join(pieces)

'guido' in val
val.index(',')
val.find(':')
val.count(',')
val.replace(',','::')
val.replace(',','')<jupyter_output><empty_output><jupyter_text>**Expressões regulares**<jupyter_code>import re<jupyter_output><empty_output><jupyter_text>Suponha que quiséssemos separar uma string com um número variável de caracteres de espaços em brnco (tabulações, espaços e quebras de linha). A regex que descreve um ou mais caracteres para espaços em branco é `\s+`.<jupyter_code>text = "foo bar\t baz \tqux"
re.split('\s+', text)
#outro jeito de fazer a mesma coisa
regex = re.compile('\s+')
regex.split(text)
#findall mostra uma lista de padrões que tem a vê com regex
regex.findall(text)
text = """Dave <EMAIL>
Steve <EMAIL>
Rob <EMAIL>
Ryan <EMAIL>"""
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
#IGNORECASE faz a regex não diferenciar maiuscula de minuscula
regex = re.compile(pattern, flags=re.IGNORECASE)
regex.findall(text)
m = regex.search(text)
m
text[m.start():m.end()]
#Aparece None se o padrão não existir no inicio da string
print(regex.match(text))
#Sub devolve uma nova strig com as ocorrencias do padrão
print(regex.sub('REDACTED', text))<jupyter_output>Dave REDACTED
Steve REDACTED
Rob REDACTED
Ryan REDACTED<jupyter_text>Suponha que quiséssemos encontrar os endereços de email e, simultaneamente, segmentar cada endereço em seus três componentes: nome do usuário, nome do domínio e sufico do domínio.<jupyter_code>pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern, flags=re.IGNORECASE)
m = regex.match('<EMAIL>')
m.groups()
regex.findall(text)
print(regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text))<jupyter_output>Dave Username: dave, Domain: google, Suffix: com
Steve Username: steve, Domain: gmail, Suffix: com
Rob Username: rob, Domain: gmail, Suffix: com
Ryan Username: ryan, Domain: yahoo, Suffix: com<jupyter_text>**Funções de string vetorizadas no pandas**<jupyter_code>data = {'Dave': '<EMAIL>', 'Steve':'<EMAIL>','Rob':'<EMAIL>.com','Wes':np.nan}
data = pd.Series(data)
data
data.isnull()
data.str.contains('gmail')
pattern
#outro jeito de fazer usando expressões regulares
data.str.findall(pattern, flags=re.IGNORECASE)
matches = data.str.match(pattern, flags=re.IGNORECASE)
matches
#erro do próprio livro. Aguardando correção do autor do livro e criador do Pandas
matches.str.get(1)
matches.str[0]
data.str[:5]<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17317524203198084, 'fraction_numerical': 0.026868269335363865, 'mean_word_length': 6.642560266001663, 'pattern_counts': {'":': 0, '<': 80, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '539404', 'license': 'MIT', 'n_tokens_mistral': 3887, 'n_tokens_neox': 3707, 'n_words': 778, 'path': 'limpeza_preparacao_dados.ipynb', 'repo_name': 'anicelysantos/book-python-para-analise-de-dados', 'size': '9254'}