将计数器对象转换为Pandas DataFrame

84

我在列表上使用了Counter来计算这个变量:

final = Counter(event_container)

打印最终结果:

Counter({'fb_view_listing': 76, 'fb_homescreen': 63, 'rt_view_listing': 50, 'rt_home_start_app': 46, 'fb_view_wishlist': 39, 'fb_view_product': 37, 'fb_search': 29, 'rt_view_product': 23, 'fb_view_cart': 22, 'rt_search': 12, 'rt_view_cart': 12, 'add_to_cart': 2, 'create_campaign': 1, 'fb_connect': 1, 'sale': 1, 'guest_sale': 1, 'remove_from_cart': 1, 'rt_transaction_confirmation': 1, 'login': 1})

现在我想将final转换为Pandas的DataFrame,但是当我执行以下操作时:

```python # 示例代码 import pandas as pd
df = pd.DataFrame(final) ```
它会出现错误:'xxx' object is not iterable
final_df = pd.DataFrame(final)

但是我遇到了一个错误。

我猜测final不是一个合适的字典,那么我怎么将final转换成字典呢?还是有其他方法将final转换成DataFrame吗?


你希望最终的 df 看起来像什么?你想让每个条目成为一列还是一行? - EdChum
5个回答

128
您可以使用from_dict构建数据并传递参数orient='index',然后调用reset_index以获取一个包含两列的数据框:
In [40]:
from collections import Counter
d = Counter({'fb_view_listing': 76, 'fb_homescreen': 63, 'rt_view_listing': 50, 'rt_home_start_app': 46, 'fb_view_wishlist': 39, 'fb_view_product': 37, 'fb_search': 29, 'rt_view_product': 23, 'fb_view_cart': 22, 'rt_search': 12, 'rt_view_cart': 12, 'add_to_cart': 2, 'create_campaign': 1, 'fb_connect': 1, 'sale': 1, 'guest_sale': 1, 'remove_from_cart': 1, 'rt_transaction_confirmation': 1, 'login': 1})
df = pd.DataFrame.from_dict(d, orient='index').reset_index()
df

Out[40]:
                          index   0
0                         login   1
1   rt_transaction_confirmation   1
2                  fb_view_cart  22
3                    fb_connect   1
4               rt_view_product  23
5                     fb_search  29
6                          sale   1
7               fb_view_listing  76
8                   add_to_cart   2
9                  rt_view_cart  12
10                fb_homescreen  63
11              fb_view_product  37
12            rt_home_start_app  46
13             fb_view_wishlist  39
14              create_campaign   1
15                    rt_search  12
16                   guest_sale   1
17             remove_from_cart   1
18              rt_view_listing  50

您可以将列重命名为更有意义的名称:

In [43]:
df = df.rename(columns={'index':'event', 0:'count'})
df

Out[43]:
                          event  count
0                         login      1
1   rt_transaction_confirmation      1
2                  fb_view_cart     22
3                    fb_connect      1
4               rt_view_product     23
5                     fb_search     29
6                          sale      1
7               fb_view_listing     76
8                   add_to_cart      2
9                  rt_view_cart     12
10                fb_homescreen     63
11              fb_view_product     37
12            rt_home_start_app     46
13             fb_view_wishlist     39
14              create_campaign      1
15                    rt_search     12
16                   guest_sale      1
17             remove_from_cart      1
18              rt_view_listing     50

1
谢谢!为什么需要传递参数orient='index'? 这肯定是有效的,感谢您的回答,但在尝试自我学习时,我不明白为什么需要这个参数。 - Heather Claxton
1
如果你没有传递 orient='index',那么它会引发一个 ValueError,因为它期望你传递一个索引,你应该尝试使用参数来理解输出的差异。 - EdChum

15

另一种选择是使用DataFrame.from_records方法。

import pandas as pd
from collections import Counter

c = Counter({'fb_view_listing': 76, 'fb_homescreen': 63, 'rt_view_listing': 50, 'rt_home_start_app': 46, 'fb_view_wishlist': 39, 'fb_view_product': 37, 'fb_search': 29, 'rt_view_product': 23, 'fb_view_cart': 22, 'rt_search': 12, 'rt_view_cart': 12, 'add_to_cart': 2, 'create_campaign': 1, 'fb_connect': 1, 'sale': 1, 'guest_sale': 1, 'remove_from_cart': 1, 'rt_transaction_confirmation': 1, 'login': 1})

df = pd.DataFrame.from_records(list(dict(c).items()), columns=['page','count'])

这是一个简单的代码行,速度似乎是相同的。

或者使用这个变体来按照最常用的进行排序。同样的,性能大约是一样的。

df = pd.DataFrame.from_records(c.most_common(), columns=['page','count'])

2
我提名这个作为最佳答案,因为它不需要在之后重命名列,并且避免了一个数据列被视为索引而不是索引列(由于from_dict中的“orient”参数)。 - heretomurimudamura
+1 这个解决方案的运行时间比被采纳的答案要低。我在 jupyter-notebook 中使用了 %%time 来查找运行时间。这个方案的运行时间在“微秒”范围内,而被采纳的答案有两个操作,对于 30 个条目,运行时间在“毫秒”范围内。 - hafiz031

6
如果您想要两列,请在使用from_dict从字典创建DataFrame时,设置关键字参数orient='index':
final_df = pd.DataFrame.from_dict(final, orient='index')

查看 DataFrame.from_dict的文档


谢谢,但这给了我一个1行,n列的数据框。我怎样才能得到一个n行,2列的数据框呢? - woshitom

1
我发现将计数器转换为按计数排序并且有序项目为索引的pandas Series更加有用,因此我使用了zip
def counter_to_series(counter):
  if not counter:
    return pd.Series() 
  counter_as_tuples = counter.most_common(len(counter)) 

  items, counts = zip(*counter_as_tuples)
  return pd.Series(counts, index=items)

计数器对象的most_common方法返回一个(item, count)元组列表。当计数器没有任何项时,zip将抛出异常,因此必须事先检查空计数器。请保留HTML标签。

0
你遇到的错误可能是“如果使用所有标量值,则必须传递索引。” 要解决此问题,只需提供一个索引(例如,“count”),然后进行转置:
final_df = pd.DataFrame(final, index=['count']).transpose()

完成了。 如果您愿意,之后可以重命名索引。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接