Pandas Tutorial: анализ обзоров видеоигр с помощью Python

Python – язык, который просто создан для анализа данных, прежде всего из-за фантастической экосистемы пакетов. Pandas является одним из этих замечательных пакетов и значительно упрощает импорт и анализ данных.  Pandas основывается на пакетах, таких как NumPy и matplotlib, которые уже в свою очередь предоставляют вам инструменты для анализа и визуализации данных.

В данной статье мы будем использовать Pandas для анализа данных об обзорах видеоигр от IGN, с новостного и информационного веб-сайта, освещающего тематику компьютерных игр.

Эти данные были собраны Эриком Гринштейном, и их можно найти здесь. Пока мы будем анализировать обзоры видеоигр, мы изучим ключевые концепции Pandas (например индексирование).

Для нашего анализа нам нужен только Python 3.5 и Jupyter Notebook )

Импортируем данные

Сначала нам конечно же нужно прочитать данные.  Данные хранятся как значения, разделенные запятыми. Формат хранения таких данных называется csv, файл, где каждая строка файла – это одна стока таблицы, а разделитель колонок – простая запятая(,).  Вот первые несколько строк файла ign.csv:

,score_phrase,title,url,platform,score,genre,editors_choice,release_year,release_month,release_day
0,Amazing,LittleBigPlanet PS Vita,/games/littlebigplanet-vita/vita-98907,PlayStation Vita,9.0,Platformer,Y,2012,9,12
1,Amazing,LittleBigPlanet PS Vita -- Marvel Super Hero Edition,/games/littlebigplanet-ps-vita-marvel-super-hero-edition/vita-20027059,PlayStation Vita,9.0,Platformer,Y,2012,9,12
2,Great,Splice: Tree of Life,/games/splice/ipad-141070,iPad,8.5,Puzzle,N,2012,9,12
3,Great,NHL 13,/games/nhl-13/xbox-360-128182,Xbox 360,8.5,Sports,N,2012,9,11
,score_phrase,title,url,platform,score,genre,editors_choice,release_year,release_month,release_day
0,Amazing,LittleBigPlanet PS Vita,/games/littlebigplanet-vita/vita-98907,PlayStation Vita,9.0,Platformer,Y,2012,9,12
1,Amazing,LittleBigPlanet PS Vita -- Marvel Super Hero Edition,/games/littlebigplanet-ps-vita-marvel-super-hero-edition/vita-20027059,PlayStation Vita,9.0,Platformer,Y,2012,9,12
2,Great,Splice: Tree of Life,/games/splice/ipad-141070,iPad,8.5,Puzzle,N,2012,9,12
3,Great,NHL 13,/games/nhl-13/xbox-360-128182,Xbox 360,8.5,Sports,N,2012,9,11

Как вы можете видеть выше, каждая строка в данных представляет собой одну игру, которая была рассмотрена IGN. В столбцах содержится информация об этой игре:

• score_phrase – таким образом  IGN описал игру одним словом. Это связано со счетом, который она получила

• title – это имя игры

• url – URL, где вы можете просмотреть полный обзор

• platform – Платформа, на которой была рассмотрена игра (ПК, PS4 и т.д.)

• score – Оценка игры, от 1.0 до 10.0

• genre – Жанр игры

• editors_choice – N, если игра не была выбором редактора, Y, если бы это было так. Это связано с оценкой

• release_year – год,  когда игра была выпущена

• release_month – месяц релиза

• release_day – день релиза

Есть еще главный столбец, который содержит значение индекса строки. Но не обращайте на него внимание, мы с ним разберемся попозже. Чтобы начать работать с данными в Python нам сначала нужно перевести наш csv-файл в Pandas DataFrame. DataFrame – это способ представления и работы с табличными данными. Табличные данные имеют строки и столбцы, как и наш файл csv.

Чтобы считать наши данные, нам нужно использовать функцию pandas.read_csv. Эта функция возьмет файл csv и вернет DataFrame.

Ну и конечно же сам код:

import pandas as pd
reviews = pd.read_csv(‘ign.csv‘)

• Сначала импортируем библиотеку pandas и  переименуем ее в pd, чтобы быстрее было печатать.

Считываем данные в DataFrame и присваиваем результат переменной reviews

C  DataFrame очень удобно работать. Чтобы быстро просмотреть данные нам предоставляется 2 функции:

• pandas.DataFrame.head – выведет первые N строк (по умолчанию 5)

• pandas.DataFrame.tail – выведет последние N строк (по умолчанию 5)

Нам нужен именно head, чтобы посмотреть что находится  в нашей переменной reviews:

reviews.head()

Результат:

DeepinScreenshot_select-area_20170721221158

 

Ну а если вам срочно нужно посчитать количество строк и столбцов, то в помощь вам pandas.DataFrame.shape:

reviews.shape

Результат:

(18625, 11)

Все правильно – у нас есть 18625 строк и 11 столбцов.

У библиотеки Pandas просто огромное преимущество перед numpy – она позволяет иметь столбцы с разными типами данных. Например в нашей переменной reviews есть столбцы, которые хранят значения float(это score), значения string( это score_phrase) и целые числа (release_year).

Теперь, когда мы прочитали данные, давайте поработаем над индексацией, чтобы получить нужные нам строки и столбцы.

Индексируем DataFrames с помощью Pandas

Выше мы использовали метод head для вывода  первых 5 строк переменной reviews. Мы могли бы сделать то же самое, используя метод pandas.DataFrame.iloc. Метод iloc позволяет нам извлекать строки и столбцы по их местоположению.  Для этого нам нужно будет указать позиции строк либо позиции столбцов (в зависимости от того, что именно вам нужно), которые мы хотим.

В общем, вот такую строчку кода: reviews.head() можно было написать по другому:

reviews.iloc[0:5,:]

Результат:

DeepinScreenshot_select-area_20170721221443

Как вы можете видеть выше, мы указали, что нам нужны строки 0:5. Это означает, что нам нужны строки с позиции 0 до 5 (но не включая позицию 5).  Первая строка по умолчанию всегда  находится на позиции 0. В результате мы получаем строки на позициях 0, 1, 2, 3 и 4.

На первой позиции мы указываем сколько строк нам нужно, а после запятой сколько столбцов. В нашем случае на второй позиции стоит : , а это означает, что нам нужны все столбцы.

Приведу вам еще парочку примеров(вдруг они вам понадобятся для работы):

 reviews.iloc[:5,:] – Первые 5 строк и все столбцы

• reviews.iloc[:,:] – Вся DataFrame

• reviews.iloc[5:,5:] – Строки с позиции 5 и до конца, и столбцы с позиции 5 и до конца.

• reviews.iloc[:,0] – Выведет только первый столбец и все строки этого столбца

• reviews.iloc[9,:] – Только  9 столбец и все строчки этого столбца

Индексирование по позиции очень похоже на индексацию NumPy. Если вам хочется узнать об этом больше – читайте здесь.

Теперь, когда мы немножко разобрались в этой теме, давайте удалим наш первый столбец (он нам просто не нужен):

reviews = reviews.iloc[:,1:]
reviews.head()

Вот что у вас должно получиться:

DeepinScreenshot_select-area_20170721221946

Индексирование с использованием меток в Pandas

Теперь, когда мы знаем, как извлекать строки и столбцы по позиции, стоит обратить внимание на другой важный способ работы с DataFrames, который заключается в извлечении строк и столбцов по метке.

Основным преимуществом Pandas над NumPy является то, что каждый из столбцов и строк имеет свою метку.

А для работы с метками в библиотеке Pandas есть прекрасный метод – pandas.DataFrame.loc, который позволяет нам индексировать, используя метки вместо позиций.

Мы может вывести первые 5 строк переменной reviews, используя метод loc, например:

reviews.loc[0:5,:]

Вывод:

DeepinScreenshot_select-area_20170721222706
Как вы уже заметили, этот результат не сильно отличается от reviews.iloc[0:5,:]. Это связано с тем, что наши метки строк точно соответствуют позициям.  Вы можете увидеть ярлыки строк в самом левом углу таблицы (они выделены жирным шрифтом). Вы также можете увидеть их, обратившись к свойству индекса DataFrame. Вот все индексы строк нашей переменной reviews:

reviews.index

Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, …], dtype=’int64′)
Но не всегда все так просто. Иногда индексы просто не совпадают со своими позициями. В приведенной ниже ячейке кода мы:

Мы получим строки с 10 по 20 и присвоим их переменной some_reviews

И выведем первые 5 строк some_reviews

some_reviews = reviews.iloc[10:20,]
some_reviews.head()

DeepinScreenshot_select-area_20170721223318

В итоге, в some_reviews индексы строк начинаются с 10 и заканчиваются на 20. И теперь, когда вы попытаетесь с помощью loc поиск  ниже 10 или выше 20, то получите ошибку (KeyError: ‘start bound [9] is not the [index]’).

some_reviews.loc[9:21,:]

Скажу по собственному опыту, ярлыки столбцов могут значительно облегчить жизнь при работе с данными. Можно при помощи метода loc указывать метки столбцов, чтобы потом извлекать по ним (они же вам известны):

reviews.loc[:5,”score”]

 

0    9.0
1    9.0
2    8.5
3    8.5
4    8.5
5    7.0
Name: score, dtype: float64
0    9.0
1    9.0
2    8.5
3    8.5
4    8.5
5    7.0
Name: score, dtype: float64

Мы также можем указать более одного столбца, просто передав их названия в виде списка (list):

reviews.loc[:5,[“score”, “release_year”]]

DeepinScreenshot_select-area_20170721030109

Series

А что делать если нам нужен отдельный столбец? Сделать это можно несколькими способами. До сих пор мы видели два типа синтаксиса:

• reviews.iloc[:,1] – Будет извлекать второй столбец.

•  reviews.loc[:,”score_phrase”] – Результат будет тот же самый(2 столбец)

Есть третий, еще более простой способ получить целую колонку. Мы можем просто указать имя столбца в квадратных скобках:

reviews[“score”]

 

0     9.0
1     9.0
2     8.5
3     8.5
4     8.5
5     7.0
6     3.0
7     9.0
8     3.0
9     7.0
10    7.5
11    7.5
12    7.0
13    9.0
14    9.0
...
18610     6.0
18611     5.8
18612     7.8
18613     8.0
18614     9.2
18615     9.2
18616     7.5
18617     8.4
18618     9.1
18619     7.9
18620     7.6
18621     9.0
18622     5.8
18623    10.0
18624    10.0
Name: score, Length: 18625, dtype: float64
0     9.0
1     9.0
2     8.5
3     8.5
4     8.5
5     7.0
6     3.0
7     9.0
8     3.0
9     7.0
10    7.5
11    7.5
12    7.0
13    9.0
14    9.0
...
18610     6.0
18611     5.8
18612     7.8
18613     8.0
18614     9.2
18615     9.2
18616     7.5
18617     8.4
18618     9.1
18619     7.9
18620     7.6
18621     9.0
18622     5.8
18623    10.0
18624    10.0
Name: score, Length: 18625, dtype: float64

А если вдруг нужен не один столбец, а несколько, то пожалуйста:

reviews[[“score”, “release_year”]]

18625 строк × 2 столбца

Когда мы извлекаем один столбец, мы фактически извлекаем объект  Series. Ведь столбцами в объекте DataFrame выступают объекты Series, строки которых являются их непосредственными элементами.

Убеждаемся в этом:

type(reviews[“score“])

pandas.core.series.Series

А давайте создадим свой объект Series, чтобы лучше понять как все это работает. Чтобы это сделать нам нужно передать список или массив NumPy в объект Series при его создании:

s1 = pd.Series([1,2])
s1

 

0    1
1    2
dtype: int64
0    1
1    2
dtype: int64

В объекте Series можно хранить значения разных типов(int, string, float и т.д). Здесь мы создаем Series, который будет содержать тип (string):

s2 = pd.Series([“Boris Yeltsin”, “Mikhail Gorbachev”])
s2

 

0        Boris Yeltsin
1    Mikhail Gorbachev
dtype: object
0        Boris Yeltsin
1    Mikhail Gorbachev
dtype: object

Создаем объект DataFrame в Pandas

Мы можем создать DataFrame, просто передав несколько объектов Series в класс DataFrame. Выше мы уже создали эти объекты Series – это s1 и s2, а теперь пришло время  создавать непосредственно сам объект DataFrame:

pd.DataFrame([s1,s2])

Результат:

0 1
0 1 2
1 Boris Yeltsin Mikhail Gorbachev

pd.DataFrame(Мы можем делать тоже самое, не объявляя перед этим переменные, а просто передать строки в виде списка:

pd.DataFrame(
[
[1,2],
[“Boris Yeltsin“, “Mikhail Gorbachev“]
],
columns=[“column1“, “column2“]
)

Вывод:

0 1
0 1 2
1 Boris Yeltsin Mikhail Gorbachev

А еще мы можем указывать метки столбцов при создании DataFrame:

pd.DataFrame(
[
[1,2],
[“Boris Yeltsin“, “Mikhail Gorbachev“]
],
columns=[“column1“, “column2“]
)

Результат:

column1 column2
0 1 2
1 Boris Yeltsin Mikhail Gorbachev

Помимо меток, можно еще задавать индекс:

frame = pd.DataFrame(
[
[1,2],
[“Boris Yeltsin”, “Mikhail Gorbachev“]
],
index=[“row1″, “row2“],
columns=[“column1″, “column2“]
)

frame

Вывод:

column1 column2
row1 1 2
row2 Boris Yeltsin Mikhail Gorbachev

Пример индексирования DataFrame при помощи меток:


frame.loc[“row1″:”row2″, “column1“]

 

row1                1
row2    Boris Yeltsin
Name: column1, dtype: object
row1                1
row2    Boris Yeltsin
Name: column1, dtype: object

Методы работы с DataFrame

Как уже упоминалось ранее, каждый столбец в DataFrame является объектом Series:

type(reviews[“title“])

 

pandas.core.series.Series
pandas.core.series.Series

Очень много методов из Series можно смело брать и  применять к DataFrame, в том числе метод head():

reviews[“title“].head()

 

0                              LittleBigPlanet PS Vita
1    LittleBigPlanet PS Vita -- Marvel Super Hero E...
2                                 Splice: Tree of Life
3                                               NHL 13
4                                               NHL 13
Name: title, dtype: object
0                              LittleBigPlanet PS Vita
1    LittleBigPlanet PS Vita -- Marvel Super Hero E...
2                                 Splice: Tree of Life
3                                               NHL 13
4                                               NHL 13
Name: title, dtype: object

В рядах Pandas и DataFrames также есть другие методы, упрощающие вычисления. Например, мы можем использовать метод pandas.Series.mean для поиска среднего значения:

reviews[“score”].mean()

 

6.950459060402685
6.950459060402685

Есть и другие методы наподобие mean:

• pandas.DataFrame.corr – Определяет корреляцию между столбцами в DataFrame.

•  pandas.DataFrame.count – Подсчитывает количество ненулевых значений в каждом столбце Data Frame.

• pandas.DataFrame.max – Находит максимальное значение в каждом столбце

• pandas.DataFrame.min – Находит минимальное значение в каждом столбце

•  pandas.DataFrame.median – Находит медиану в каждом столбце

• pandas.DataFrame.std – Находит среднеквадратическое отклонение каждого столбца

Графики в Pandas

Теперь, когда мы научились более или менее работать с объектами DataFrames и Series, мы можем сделать гистограмму для каждой консоли(PlayStation 4, Xbox One и т.д), используя метод pandas.DataFrame.plot. Это поможет нам понять, какая консоль лучше. И все это сделает за нас крутая библиотека matplotlib.

Метод plot по умолчанию использует рисование линейного графика. Нам нужно будет передать аргумент kind = “hist”, чтобы у нас получилась гистограмма.

В приведенном ниже коде, мы:

Вызовем %matplotlib inline, чтобы наши графики не выходили за Jupyter notebook

Профильтруем reviews таким образом, чтобы у нас остались данные только о Xbox One

Построим график столбца score

%matplotlib inline
reviews[reviews[“platform”] == “Xbox One“][“score“].plot(kind=”hist”)

download

Проделаем те же манипуляции с PS4:

reviews[reviews[“platform”] == “PlayStation 4“][“score“].plot(kind=”hist”)

download

Из нашей гистограммы видно, что в PlayStation 4 есть намного больше высоко оцененных игр, чем у Xbox One:

filtered_reviews[“score“].hist()

download