Как перебрать вложенный для l oop в pandas кадр данных? - PullRequest
0 голосов
/ 25 апреля 2020

Я пытаюсь перебрать набор данных Hacker News и пытался создать 3 категории (то есть типы сообщений), найденные на форуме HN, а именно: ask_posts, show_posts и other_posts.

Короче говоря, я пытаясь выяснить среднее количество комментариев на сообщения в категории (описано ниже).

import pandas as pd
import datetime as dt

df = pd.read_csv('HN_posts_year_to_Sep_26_2016.csv')

ask_posts = []
show_posts = []
other_post = []
total_ask_comments = 0
total_show_comments = 0

for i, row in df.iterrows():
    title = row.title
    comments = row['num_comments']
    if title.lower().startswith('ask hn'):
        ask_posts.append(title)
        for post in ask_posts:
            total_ask_comments += comments
    elif title.lower().startswith('show hn'):
        show_posts.append(title)
        for post in show_posts:
             total_show_comments += comments
    else:
        other_post.append(title)

avg_ask_comments = total_ask_comments/len(ask_posts)
avg_show_comments = total_show_comments/len(show_posts)


print(total_ask_comments)
print(total_show_comments)

print(avg_ask_comments)
print(avg_show_comments)

Результаты соответственно:

395976587

250362315

и

43328.21829521829

24646.81187241583

Они кажутся довольно высокими, и я не уверен, что так, потому что это проблема с тем, как я структурировал мою вложенную l oop. Этот метод правильный? Для этого крайне важно, чтобы я использовал для l oop.

Любая помощь и проверка моего кода приветствуется.

1 Ответ

2 голосов
/ 26 апреля 2020

Этот пост не отвечает конкретно на вопрос о циклическом перемещении по фреймам данных; но оно дает вам альтернативное решение, которое работает быстрее.

Цикл по Pandas фреймам данных для сбора информации по мере ее поступления будет чрезвычайно медленным. Гораздо быстрее использовать фильтрацию для получения необходимой информации.

>>> show_posts = df[df.title.str.contains("show hn", case=False)]
>>> show_posts
              id  ...       created_at
52      12578335  ...   9/26/2016 0:36
58      12578182  ...   9/26/2016 0:01
64      12578098  ...  9/25/2016 23:44
70      12577991  ...  9/25/2016 23:17
140     12577142  ...  9/25/2016 20:06
...          ...  ...              ...
292995  10177714  ...   9/6/2015 14:21
293002  10177631  ...   9/6/2015 13:50
293019  10177511  ...   9/6/2015 13:02
293028  10177459  ...   9/6/2015 12:38
293037  10177421  ...   9/6/2015 12:16

[10189 rows x 7 columns]
>>> ask_posts = df[df.title.str.contains("ask hn", case=False)]
>>> ask_posts
              id  ...       created_at
10      12578908  ...   9/26/2016 2:53
42      12578522  ...   9/26/2016 1:17
76      12577908  ...  9/25/2016 22:57
80      12577870  ...  9/25/2016 22:48
102     12577647  ...  9/25/2016 21:50
...          ...  ...              ...
293047  10177359  ...   9/6/2015 11:27
293052  10177317  ...   9/6/2015 10:52
293055  10177309  ...   9/6/2015 10:46
293073  10177200  ...    9/6/2015 9:36
293114  10176919  ...    9/6/2015 6:02

[9147 rows x 7 columns]

Таким способом вы можете очень быстро получить свои номера

>>> num_ask_comments = ask_posts.num_comments.sum()
>>> num_ask_comments
95000
>>> num_show_comments = show_posts.num_comments.sum()
>>> num_show_comments
50026
>>> 
>>> total_num_comments = df.num_comments.sum()
>>> total_num_comments
1912761
>>> 
>>> # Get a ratio of the number ask comments to total number of comments
>>> num_ask_comments / total_num_comments
0.04966642460819726
>>> 

Также вы получите другие цифры с помощью .startswith() против .contains() (я не уверен, что вы хотите).

>>> ask_posts = df[df.title.str.lower().str.startswith("ask hn")]
>>> len(ask_posts)
9139
>>> 
>>> ask_posts = df[df.title.str.contains("ask hn", case=False)]
>>> len(ask_posts)
9147
>>> 

Аргумент шаблона для .contains() может быть регулярным выражением - что очень полезно. Таким образом, мы можем указать все записи, которые начинаются с «ask hn» в самом начале заголовка, но если мы не уверены, будет ли перед ним какой-либо пробел, мы можем сделать

>>> ask_posts = df[df.title.str.contains(r"^\s*ask hn", case=False)]
>>> len(ask_posts)
9139
>>> 

То, что происходит в операторах фильтра, вероятно, трудно asp, когда вы начинаете использовать Pandas. Например, выражение в квадратных скобках df[df.title.str.contains("show hn", case=False)].

То, что выдает оператор в квадратных скобках (df.title.str.contains("show hn", case=False)), представляет собой столбец значений True и False - логический фильтр (не уверен, что он так и называется, но он имеет такой эффект).

Так что созданный логический столбец используется для выбора строк в кадре данных, df[<bool column>], и он создает новый кадр данных с соответствующими записями. Затем мы можем использовать это для извлечения другой информации - например, для суммирования столбца комментариев.

...