[PROJETO] Analisando Dados da App Store e Google Play - Parte I
Tags: python, analytics, beginners, programming
Published: 2022-01-28 14:26:02

Todo o conteúdo deste projeto pode ser encontrado no meu repositório do GitHub. Para mais detalhes, [acesse o link](https://github.com/lis-r-barreto/Data-Engineering-Portfolio).

## **Objetivo**

Nosso objetivo neste projeto é encontrar perfis de aplicativos móveis que sejam lucrativos para os mercados da App Store e Google Play. Estamos trabalhando como analistas de dados para uma empresa que desenvolve aplicativos para dispositivos móveis Android e iOS, e nosso trabalho é permitir que nossa equipe de desenvolvedores tome decisões baseadas em dados com relação ao tipo de aplicativo que constroem.

Em nossa empresa, só criamos aplicativos de download e instalação gratuitos, e nossa principal fonte de receita consiste em anúncios no aplicativo. Isso significa que nossa receita para qualquer aplicativo é influenciada principalmente pelo número de usuários que usam nosso aplicativo. Nosso objetivo para este projeto é analisar dados para ajudar nossos desenvolvedores a entender quais tipos de aplicativos podem atrair mais usuários.

## **Explorando os Dados**

Em setembro de 2018, havia aproximadamente 2 milhões de aplicativos iOS disponíveis na App Store e 2,1 milhões de aplicativos Android no Google Play.

<p align="center">
  <img src="https://s3.amazonaws.com/dq-content/350/py1m8_statista.png">
</p>

Fonte: [Statista](https://www.statista.com/statistics/276623/number-of-apps-available-in-leading-app-stores/)

Coletar dados para mais de quatro milhões de aplicativos requer uma quantidade significativa de tempo e dinheiro, então, tentaremos analisar uma amostra de dados. Para evitar o gasto de recursos com a coleta de novos dados por conta própria, devemos primeiro tentar ver se podemos encontrar quaisquer dados existentes relevantes sem nenhum custo. Felizmente, esses são dois conjuntos de dados que parecem adequados para o nosso propósito:

- [Um conjunto de dados](https://www.kaggle.com/lava18/google-play-store-apps) contendo dados sobre aproximadamente dez mil aplicativos Android do Google Play. Você pode baixar o conjunto de dados através [desse link](https://dq-content.s3.amazonaws.com/350/googleplaystore.csv).
- [Um conjunto de dados](https://www.kaggle.com/ramamet4/app-store-apple-data-set-10k-apps) contendo dados sobre aproximadamente sete mil aplicativos iOS da App Store. Você pode baixar o conjunto de dados através [desse link](https://dq-content.s3.amazonaws.com/350/AppleStore.csv).

Vamos começar abrindo os dois conjuntos de dados e, em seguida, continuar explorando os dados.

```python
from csv import reader

### Dataset do Google Play
opened_file = open('googleplaystore.csv')
read_file = reader(opened_file)
android = list(read_file)
android_header = android[0]
android = android[1:]

### Dataset da App Store
opened_file = open('AppleStore.csv')
read_file = reader(opened_file)
ios = list(read_file)
ios_header = ios[0]
ios = ios[1:]
```

Para tornar mais fácil explorar os dois conjuntos de dados, primeiro escreveremos uma função chamada `explore_data ()` que podemos usar repetidamente para explorar as linhas de uma forma mais legível. Também adicionaremos uma opção para nossa função para mostrar o número de linhas e colunas para qualquer conjunto de dados.

```python
def explore_data(dataset, start, end, rows_and_columns=False):
    dataset_slice = dataset[start:end]    
    for row in dataset_slice:
        print(row)
        print('\n') # Adiciona uma nova linha vazia entre as outras linhas
        
    if rows_and_columns:
        print('Número de linhas:', len(dataset))
        print('Número de colunas:', len(dataset[0]))

print(android_header)
print('\n')
explore_data(android, 0, 3, True)
```

Vemos que o conjunto de dados do Google Play tem 10841 aplicativos e 13 colunas. Em uma rápida olhada, as colunas que podem ser úteis para o propósito de nossa análise são `'App'`, `'Category'`, `'Reviews'`, `'Installs'`, `'Type'`, `'Price'`, e `'Genres'`.

Agora vamos dar uma olhada no conjunto de dados da App Store.

```python
print(ios_header)
print('\n')
explore_data(ios, 0, 3, True)
```

Temos 7197 aplicativos iOS neste conjunto de dados e as colunas que parecem interessantes são: `'track_name'`, `'currency'`, `'price'`, `'rating_count_tot'`, `'rating_count_ver'` e `'prime_genre'`. Nem todos os nomes de coluna são autoexplicativos neste caso, mas os detalhes sobre cada coluna podem ser encontrados na [documentação do conjunto de dados](https://www.kaggle.com/ramamet4/app-store-apple-data-set-10k-apps/home).

## **Deletando Dados Errados**

O conjunto de dados do Google Play tem uma [seção de discussão](https://www.kaggle.com/lava18/google-play-store-apps/discussion) dedicada e podemos ver que [uma das discussões](https://www.kaggle.com/lava18/google-play-store-apps/discussion/66015) descreve um erro para a linha 10472. Vamos imprimir esta linha e compará-la com o cabeçalho e outra linha que está correta.

```python
print(android[10472])  # linha incorreta
print('\n')
print(android_header)  # cabeçalho
print('\n')
print(android[0])      # linha correta
```

A linha 10472 corresponde ao aplicativo _Life Made WI-Fi Touchscreen Photo Frame_, e podemos ver que a classificação é 19. Isso está claramente desativado porque a classificação máxima para um aplicativo do Google Play é 5 (conforme mencionado na [seção de discussões](https://www.kaggle.com/lava18/google-play-store-apps/discussion/66015), este problema é causado por um valor ausente na coluna `'Categoria'`). Como consequência, vamos deletar esta linha.

```python
print(len(android))
del android[10472]  # não execute essa linha de código mais de uma vez
print(len(android))
```

## **Removendo Entradas Duplicadas**

### **Parte I**
Se explorarmos o conjunto de dados do Google Play por tempo suficiente, descobriremos que alguns aplicativos têm mais de uma entrada. Por exemplo, o aplicativo Instagram possui quatro entradas:

```python
for app in android:
    name = app[0]
    if name == 'Instagram':
        print(app)
```

No total, existem 1.181 casos em que um aplicativo ocorre mais de uma vez:

```python
duplicate_apps = []
unique_apps = []

for app in android:
    name = app[0]
    if name in unique_apps:
        duplicate_apps.append(name)
    else:
        unique_apps.append(name)
    
print('Número de aplicativos duplicados:', len(duplicate_apps))
print('\n')
print('Examplos de aplicativos duplicados:', duplicate_apps[:15])
```

Não queremos contar determinados aplicativos mais de uma vez quando analisamos os dados, então precisamos remover as entradas duplicadas e manter apenas uma entrada por aplicativo. Uma coisa que poderíamos fazer é remover as linhas duplicadas aleatoriamente, mas provavelmente poderíamos encontrar uma maneira melhor.

Se você examinar as linhas que imprimimos nas duas células acima para o aplicativo Instagram, a principal diferença acontece na quarta posição de cada linha, que corresponde ao número de comentários. Os diferentes números mostram que os dados foram coletados em momentos diferentes. Podemos usar isso para construir um critério para manter as linhas. Não removeremos as linhas aleatoriamente, mas manteremos as linhas com o maior número de revisões, pois quanto maior o número de revisões, mais confiáveis ​​serão as avaliações.

Para fazer isso, vamos:

- Criar um dicionário em que cada chave seja um nome de aplicativo exclusivo e o valor seja o maior número de avaliações desse aplicativo;
- Usar o dicionário para criar um novo conjunto de dados, que terá apenas uma entrada por aplicativo (e apenas selecionamos os aplicativos com o maior número de avaliações)

### **Parte II**
Vamos começar construindo o dicionário.

```python
reviews_max = {}

for app in android:
    name = app[0]
    n_reviews = float(app[3])
    
    if name in reviews_max and reviews_max[name] < n_reviews:
        reviews_max[name] = n_reviews
        
    elif name not in reviews_max:
        reviews_max[name] = n_reviews
```

Em uma célula de código anterior, descobrimos que existem 1.181 casos em que um aplicativo ocorre mais de uma vez, portanto, o comprimento do nosso dicionário (de aplicativos exclusivos) deve ser igual à diferença entre o comprimento do nosso conjunto de dados e 1.181.

```python
print('Tamanho esperado:', len(android) - 1181)
print('Tamanho atual:', len(reviews_max))
```

Agora, vamos usar o dicionário `reviews_max` para remover as duplicatas. Para os casos duplicados, manteremos apenas as entradas com o maior número de revisões. Na célula de código abaixo:

- Começamos inicializando duas listas vazias, `android_clean` e` already_added`.
- Fazemos loop através do conjunto de dados `android` e para cada iteração:
    - Isolamos o nome do aplicativo e o número de avaliações.
    - Adicionamos a linha atual (`app`) à lista` android_clean`, e o nome do aplicativo (`name`) à lista` already_added` se:
        - O número de comentários do aplicativo atual corresponde ao número de comentários desse aplicativo, conforme descrito no dicionário `reviews_max`; e
        - O nome do aplicativo ainda não está na lista `already_added`. Precisamos adicionar essa condição suplementar para contabilizar os casos em que o maior número de avaliações de um aplicativo duplicado é o mesmo para mais de uma entrada (por exemplo, o aplicativo Box tem três entradas e o número de avaliações é o mesmo) . Se apenas verificarmos por `reviews_max [name] == n_reviews`, ainda acabaremos com entradas duplicadas para alguns aplicativos.

```python
android_clean = []
already_added = []

for app in android:
    name = app[0]
    n_reviews = float(app[3])
    
    if (reviews_max[name] == n_reviews) and (name not in already_added):
        android_clean.append(app)
        already_added.append(name) # certifique-se de estar dentro do bloco
```

Agora vamos explorar rapidamente o novo conjunto de dados e confirmar se o número de linhas é 9.659.

```python
explore_data(android_clean, 0, 3, True)
```

Temos 9659 linhas, exatamente como o esperado.


## **Removendo aplicativos que não sejam em inglês**

### **Parte I**

Se você explorar os conjuntos de dados o suficiente, notará que os nomes de alguns dos aplicativos sugerem que eles não são direcionados a um público que fala inglês. Abaixo, vemos alguns exemplos de ambos os conjuntos de dados:

```python
print(ios[813][1])
print(ios[6731][1])

print(android_clean[4412][0])
print(android_clean[7940][0])
```

Não estamos interessados em manter esse tipo de aplicativo, então vamos removê-lo. Uma maneira de fazer isso é remover cada aplicativo cujo nome contém um símbolo que não é comumente usado no texto em inglês - o texto em inglês geralmente inclui letras do alfabeto inglês, números compostos por dígitos de 0 a 9, sinais de pontuação (.,! ,?,;, etc.) e outros símbolos (+, *, /, etc.).

Todos esses caracteres que são específicos para textos em inglês são codificados usando o padrão ASCII. Cada caractere ASCII tem um número correspondente entre 0 e 127 associado a ele, e podemos aproveitar isso para construir uma função que verifica o nome de um aplicativo e nos diz se ele contém caracteres não ASCII.

Construímos esta função abaixo e usamos a função incorporada `ord ()` para descobrir o número de codificação correspondente de cada caractere.

```python
def is_english(string):
    
    for character in string:
        if ord(character) > 127:
            return False
    
    return True

print(is_english('Instagram'))
print(is_english('爱奇艺PPS -《欢乐颂2》电视剧热播'))
```

A função parece funcionar bem, mas alguns nomes de aplicativos em inglês usam emojis ou outros símbolos (™, - (traço), - (traço), etc.) que estão fora da faixa ASCII. Por causa disso, removeremos aplicativos úteis se usarmos a função em sua forma atual.

```python
print(is_english('Docs To Go™ Free Office Suite'))
print(is_english('Instachat 😜'))

print(ord('™'))
print(ord('😜'))
```

### **Parte II**

Para minimizar o impacto da perda de dados, removeremos um aplicativo apenas se seu nome tiver mais de três caracteres não ASCII:

```python
def is_english(string):
    non_ascii = 0
    
    for character in string:
        if ord(character) > 127:
            non_ascii += 1
    
    if non_ascii > 3:
        return False
    else:
        return True

print(is_english('Docs To Go™ Free Office Suite'))
print(is_english('Instachat 😜'))
```

A função ainda não é perfeita e muito poucos aplicativos que não sejam em inglês podem passar por nosso filtro, mas isso parece bom o suficiente neste ponto de nossa análise - não devemos gastar muito tempo com otimização neste ponto.

Abaixo, usamos a função `is_english ()` para filtrar os aplicativos em outros idiomas para ambos os conjuntos de dados:

```python
android_english = []
ios_english = []

for app in android_clean:
    name = app[0]
    if is_english(name):
        android_english.append(app)
        
for app in ios:
    name = app[1]
    if is_english(name):
        ios_english.append(app)
        
explore_data(android_english, 0, 3, True)
print('\n')
explore_data(ios_english, 0, 3, True)
```

Podemos ver que ficamos com 9.614 aplicativos para Android e 6.183 aplicativos para iOS.

## **Isolando os aplicativos gratuitos**

Como mencionamos na introdução, apenas criamos aplicativos cujo download e instalação são gratuitos, e nossa principal fonte de receita consiste em anúncios no aplicativo. Nossos conjuntos de dados contêm aplicativos gratuitos e não livres, e precisaremos isolar apenas os aplicativos gratuitos para nossa análise. Abaixo, isolamos os aplicativos gratuitos para ambos os nossos conjuntos de dados.

```python
android_final = []
ios_final = []

for app in android_english:
    price = app[7]
    if price == '0':
        android_final.append(app)
        
for app in ios_english:
    price = app[4]
    if price == '0.0':
        ios_final.append(app)
        
print(len(android_final))
print(len(ios_final))
```

Ficamos com 8864 aplicativos para Android e 3222 aplicativos para iOS, o que deve ser suficiente para nossa análise.