Помимо коллекций и понятий
Пару дней назад я написал пост, в котором резюмировал, сколько были использованы Коллекции и Понимание. Данные были предоставлены в виде lists
, либо списков dictionaries
, либо tuples
. А чтобы ответить на вопросы о данных, автор часто использовал list comprehensions
— перебор списков с помощью цикла for. Я начинаю видеть в этом очень ориентированный на Python способ решения проблем.
Хотя не все данные являются табличными, многие из них представлены, поэтому разумно предположить, что чаще всего вы будете иметь дело с табличными данными, подобными электронным таблицам ( примечание: здесь я открыт для других точек зрения, не стесняйтесь оставлять комментарии ниже!).
В любом случае, у меня возник зуд вернуться к этой главе и спросить:
Как решить ту же проблему, используя фреймы данных?
Так вот о чем этот пост.
Вы можете ссылаться на эти предыдущие посты для контекста; также имейте в виду, что это небольшое отклонение от книги Джоэла Груса (например, здесь я буду использовать панды и блокнот jupyter, которые не рассматриваются в книге).
Для ознакомления вот данные, которые вы получаете как недавно нанятый специалист по данным в Data Scienster™.
# users in the network # stored as a list of dictionaries users = [ {"id": 0, "name": "Hero"}, {"id": 1, "name": "Dunn"}, {"id": 2, "name": "Sue"}, {"id": 3, "name": "Chi"}, {"id": 4, "name": "Thor"}, {"id": 5, "name": "Clive"}, {"id": 6, "name": "Hicks"}, {"id": 7, "name": "Devin"}, {"id": 8, "name": "Kate"}, {"id": 9, "name": "Klein"} ]
# friendship pairings in the network # stored as a list of tuples friendship_pairs = [(0,1), (0,2), (1,2), (1,3), (2,3), (3,4), (4,5), (5,6), (5,7), (6,8), (7,8), (8,9)]
# interests data # stored as another list of tuples interests = [ (0, "Hadoop"), (0, "Big Data"), (0, "HBase"), (0, "Java"), (0, "Spark"), (0, "Storm"), (0, "Cassandra"), (1, "NoSQL"), (1, "MongoDB"), (1, "Cassandra"), (1, "HBase"), (1, "Postgres"), (2, "Python"), (2, "scikit-learn"), (2, "scipy"), (2, "numpy"), (2, "statsmodels"), (2, "pandas"), (3, "R"), (3, "Python"), (3, "statistics"), (3, "regression"), (3, "probability"), (4, "machine learning"), (4, "regression"), (4, "decision trees"), (4, "libsvm"), (5, "Python"), (5, "R"), (5, "Java"), (5, "C++"), (5, "Haskell"), (5, "programming langauges"), (6, "statistics"), (6, "probability"), (6, "mathematics"), (6, "theory"), (7, "machine learning"), (7, "scikit-learn"), (7, "Mahout"), (7, "neural networks"), (8, "neural networks"), (8, "deep learning"), (8, "Big Data"), (8, "artificial intelligence"), (9, "Hadoop"), (9, "Java"), (9, "MapReduce"), (9, "Big Data") ]
Имея только эти фрагменты данных, мы можем создавать функции, использовать циклы for и понимание списков, чтобы ответить на некоторые вопросы, например:
- С кем дружит каждый пользователь?
- Каково общее и среднее количество подключений?
- Какие пользователи разделяют одинаковые интересы?
- Какие самые популярные темы в этой сети?
Однако глава заканчивается списками, функциями и пониманием. Как насчет хранения данных во фреймах данных?
Сначала мы сохраним users
как фрейм данных:
import pandas as pd
# convert list of dict into dataframe users_df = pd.DataFrame(users) users_df
Просто визуально data frame
отличается от list of dictionaries
:
Ваш пробег может отличаться, но я понимаю данные совершенно по-разному, когда смотрю на список и на фрейм данных. Строки и столбцы неразрывно связаны с моим представлением о данных.
Затем нам дается число list of tuples
, представляющее пары дружбы, и мы продолжаем превращать его в число dictionary
, используя число dictionary comprehension
:
# list of tuples friendship_pairs = [(0,1), (0,2), (1,2), (1,3), (2,3), (3,4), (4,5), (5,6), (5,7), (6,8), (7,8), (8,9)]
# create a dict, where keys are users id, # dictionary comprehension friendships = {user["id"]: [] for user in users}
for i, j in friendship_pairs: friendships[i].append(j) friendships[j].append(i)
Как и в предыдущем примере, я обнаружил, что просмотр данных как data frame
отличается от просмотра их как dictionary
:
С этого момента я делаю несколько операций в пандах, чтобы объединить первые две таблицы, чтобы у меня был столбец с идентификатором пользователя, именем пользователя и идентификатором их первого, второго или , в некоторых случаях третьи друзья (у большинства людей в этой сети есть 3 прямых соединения).
Если вы хотите узнать конкретную операцию панд, вот код:
# The users_df is fine as is with two columns: id and name (see above)
# We'll transform the friendships_df
# reset_index allows us to add an index column friendships_df.reset_index(inplace=True) # add index column friendships_df = friendships_df.rename(columns = {"id":"new column name"}) # change index column to 'id' friendships_df = friendships_df.rename(columns = {'index':'id'}) # join with users_df so we get each person's name users_friendships = pd.merge(users_df, friendships_df, on='id')
После того, как мы объединили users_df
и friendships_df
, у нас есть:
Поскольку у нас есть данные users
и friendships
, мы могли бы написать функцию, которая поможет нам ответить на вопрос «сколько друзей у каждого пользователя?». Кроме того, нам нужно будет создать list comprehension
, чтобы мы перебирали все user
внутри users
:
# function to count how many friend each user has def number_of_friends(user): """How many friends does _user_ have?""" user_id = user["id"] friend_ids = friendships[user_id] return len(friend_ids)
# list comprehension to apply the function for each user num_friends_by_id = [(user["id"], number_of_friends(user)) for user in users]
# this gives us a list of tuples num_friends_by_id
[(0, 2), (1, 3), (2, 3), (3, 3), (4, 2), (5, 3), (6, 2), (7, 2), (8, 3), (9, 1)]
Опять же, просмотр данных в виде list of tuples
отличается от data frame
, поэтому давайте продолжим и превратим это во фрейм данных pandas:
# when converting to data frame, we can set the name of the columns to id and num_friends; this sets us up for another join
num_friends_by_id = pd.DataFrame(num_friends_by_id, columns = ['id', 'num_friends'])
Поскольку у нас есть столбец «id», мы можем соединить его с нашим ранее созданным фреймом данных users_friendships
:
После объединения с users_friendships
с помощью функции merge
мы получаем (users_friendships2
):
Теперь вы знакомы с процессом. У нас есть коллекция Python, обычно list
из dictionaries
или tuples
, и мы хотим преобразовать их в data frame
.
Мы повторим этот процесс для переменной interests
, которая является длинной list of tuples
(см. выше). Мы преобразуем его во фрейм данных, затем соединим с users_friendships_2
, чтобы получить более длинный фрейм данных с interests
в качестве одного из столбцов (примечание: изображение обрезано для пробела):
Преимущество pandas заключается в том, что после того, как все ваши данные объединены вместе во фрейме данных, вы можете запросить данные.
Например, я могу захотеть, чтобы все пользователи интересовались «большими данными»:
Раньше нам пришлось бы создавать функцию, которая возвращает list comprehension
:
def data_scientists_who_like(target_interest): """Find the ids of all users who like the target interests.""" return [user_id for user_id, user_interest in interests if user_interest == target_interest]
data_scientists_who_like("Big Data")
Фрейм данных имеет и другие преимущества, вы также можете запрашивать столбцы по нескольким условиям, вот два способа запроса нескольких тем:
# Option One: Use .query() user_friendship_topics.query('topic == "machine learning" | topic == "regression" | topic == "decision trees" | topic == "libsvm"')
# Option Two: Use .isin() user_friendship_topics[user_friendship_topics['topic'].isin(["machine learning", "regression", "decision trees", "libsvm"])]
Оба варианта возвращают этот фрейм данных:
Запросив фрейм данных, мы узнали:
- все пользователи, интересующиеся этими четырьмя темами
- пользователи, у которых есть общие интересы с Тором
- (при необходимости)
num_friends
, которые есть у каждого пользователя
Вы также можете узнать самые популярные темы в этой сети:
# groupby topic, tally(count), then reset_index(), then sort
user_friendship_topics.groupby(['topic']).count().reset_index().sort_values('id', ascending=False)
Вы даже можете groupby
два столбца (имя и тема), чтобы увидеть темы интересов, перечисленные каждым пользователем:
user_friendship_topics.groupby(['name', 'topic']).count()
Надеемся, вы убедились, что фреймы данных являются мощным дополнением к более знакомым операциям в Python, таким как циклы for и/или понимание списков; что оба стоит хорошо знать, чтобы манипулировать данными в различных форматах. (например, для доступа к данным JSON словари Python предпочтительнее, чем фреймы данных).
***
Чтобы узнать больше о науке о данных, машинном обучении, R, Python, SQL и многом другом, найдите меня в Twitter.