将列表转换为大熊猫中的数据框时出现AssertionError

时间:2020-08-21 00:45:20

标签: python pandas api reddit

我正在尝试将从API抓取的一些数据存储到数据帧,然后将其写入.csv。这通常可以工作,但是脚本有时会因以下错误消息而中断:

AssertionError:传递了16列,传递的数据有17列

有人知道这里发生了什么吗?代码在下面-在“通过”之后会中断

from psaw import PushshiftAPI
import datetime as dt
import pandas as pd

api = PushshiftAPI()
start_epoch=int(dt.datetime(2018, 6,2).timestamp())
end_epoch=int(dt.datetime(2018, 12, 31).timestamp())

subreddit = input('Which subreddit would you like to scrape? ')

submission_results = list(api.search_submissions(after=start_epoch,
                                                 before=end_epoch,
                                                 subreddit=subreddit,
                                                 filter=['id', 'title', 'subreddit', 'num_comments', 'score', 'author', 'is_original content', 'is_self', 'stickied', 'selftext',
                  'created_utc', 'locked', 'over_18', 'permalink', 'upvote_ratio',
                  'url'], limit = None))

print ('pass one')

submission_results_df = pd.DataFrame(submission_results)
print ('pass two')
submission_results_df.fillna('NULL')
print('pass three')
submission_results_df.to_csv('D:/CAMER/%s_Submittisons-%s-%s.csv'.format(start_epoch, end_epoch) %(subreddit, start_epoch, end_epoch))

1 个答案:

答案 0 :(得分:0)

我相信最可能的解释是,从查询返回的提交没有全部具有相同数量的字段,并且您构造数据框的方式无法处理此问题。我将提出两种解决方案,然后我将更详细地解释我的想法。

选项1:转换为字典

您可以convert each namedtuple record into a dictionary。这应该更安全,因为熊猫不会假设每个记录都具有相同顺序的相同字段集。如果某些记录有一个额外的字段,那么pandas会为此创建一个列,并为所有其他记录填充NaN。

submission_results_df = pd.DataFrame(result._asdict() for result in submission_results)

选项2:改为使用psaw CLI

我注意到您使用的psaw库有一个command-line interface,可以直接保存到JSON或CSV。如果您实际上仅使用熊猫将数据转换为CSV,也许这可以避免您的麻烦。


说明

我没有使用Redis的数据直接重现该问题,但是我可以解释一下这里发生的情况。 submission_results包含在_wrap_thing中创建的namedtuple列表。 (我以前误读了源代码,并认为它们是praw.models.reddit.submission的实例,但这仅在您在构造过程中提供了reddit API对象的情况下才会出现。)

错误消息“声明错误:已传递16列,传递的数据具有17列”似乎来自熊猫_validate_or_indexify_columns,并表明它期望 16列,但已接收到17列的数据列。我不是100%清楚到达这里需要哪个代码路径,但是我在下面提供了一个示例,该示例使用namedtuple会得到相同的错误。

我认为直接将对象列表传递到DataFrame构造函数中不是一个好主意。构造函数可以采用多种不同的格式解释数据,包括一些似乎没有明确记录的格式。当它获得一个命名元组列表时,它使用 first 命名元组来确定字段名称,然后将每个项目转换为一个列表以提取字段。如果是这样,那么在数据中的某个位置上,至少一个对象具有17个字段而不是16个字段。我不知道psaw是否做出任何特别保证,以确保所有对象都具有相同数量的字段,甚至即使这些字段相同,这些字段是否也会以相同的顺序出现。


改用namedtuple复制同一错误消息:

from collections import namedtuple
from pandas import DataFrame

RGB = namedtuple('RGB', 'red green blue')
RGBA = namedtuple('RGBA', 'red green blue alpha')

# This works:
d_okay = DataFrame([RGB(1,2,3),RGB(4,5,6)])

# This fails:
d_bad = DataFrame([RGB(1,2,3),RGB(4,5,6),RGBA(7,8,9,0)])
Traceback (most recent call last):
  File "/home/annette/anaconda3/lib/python3.7/site-packages/pandas/core/internals/construction.py", line 497, in _list_to_arrays
    content, columns, dtype=dtype, coerce_float=coerce_float
  File "/home/annette/anaconda3/lib/python3.7/site-packages/pandas/core/internals/construction.py", line 581, in _convert_object_array
    f"{len(columns)} columns passed, passed data had "
AssertionError: 3 columns passed, passed data had 4 columns

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "repro.py", line 11, in <module>
    d_bad = DataFrame([RGB(1,2,3),RGB(4,5,6),RGBA(7,8,9,0)])
  File "/home/annette/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py", line 474, in __init__
    arrays, columns = to_arrays(data, columns, dtype=dtype)
  File "/home/annette/anaconda3/lib/python3.7/site-packages/pandas/core/internals/construction.py", line 461, in to_arrays
    return _list_to_arrays(data, columns, coerce_float=coerce_float, dtype=dtype)
  File "/home/annette/anaconda3/lib/python3.7/site-packages/pandas/core/internals/construction.py", line 500, in _list_to_arrays
    raise ValueError(e) from e
ValueError: 3 columns passed, passed data had 4 columns