【问题标题】:Creating Pandas DataFrame from SmartSheet API (nested, awkward, JSON)从 SmartSheet API 创建 Pandas DataFrame(嵌套、笨拙、JSON)
【发布时间】:2020-02-13 20:52:53
【问题描述】:

我正在尝试通过 Python 连接到我办公室的 SmartSheet API,以创建一些使用 SmartSheet 之外的数据的性能跟踪仪表板。我要做的就是创建一个简单的 DataFrame,其中字段反映 columnId,单元格值反映 Smartsheet 字典中的 displayValue 键。我使用标准 API requests.get 而不是 SmartSheet 的 API 文档来执行此操作,因为我发现后者不太容易使用。

表格(样本)设置为:

Number  Letter  Name
1       A       Joe
2       B       Jim
3       C       Jon

表单 GET 请求的 JSON 语法为:

{'id': 339338304219012,
 'name': 'Sample Smartsheet',
 'version': 1,
 'totalRowCount': 3,
 'accessLevel': 'OWNER',
 'effectiveAttachmentOptions': ['GOOGLE_DRIVE',
  'EVERNOTE',
  'DROPBOX',
  'ONEDRIVE',
  'LINK',
  'FILE',
  'BOX_COM',
  'EGNYTE'],
 'ganttEnabled': False,
 'dependenciesEnabled': False,
 'resourceManagementEnabled': False,
 'cellImageUploadEnabled': True,
 'userSettings': {'criticalPathEnabled': False, 'displaySummaryTasks': True},
 'userPermissions': {'summaryPermissions': 'ADMIN'},
 'hasSummaryFields': False,
 'permalink': 'https://app.smartsheet.com/sheets/5vxMCJQhMV7VFFPMVfJgg2hX79rj3fXgVGG8fp61',
 'createdAt': '2020-02-13T16:32:02Z',
 'modifiedAt': '2020-02-14T13:15:18Z',
 'isMultiPicklistEnabled': True,
 'columns': [{'id': 6273865019090820,
   'version': 0,
   'index': 0,
   'title': 'Number',
   'type': 'TEXT_NUMBER',
   'primary': True,
   'validation': False,
   'width': 150},
  {'id': 4022065205405572,
   'version': 0,
   'index': 1,
   'title': 'Letter',
   'type': 'TEXT_NUMBER',
   'validation': False,
   'width': 150},
  {'id': 8525664832776068,
   'version': 0,
   'index': 2,
   'title': 'Name',
   'type': 'TEXT_NUMBER',
   'validation': False,
   'width': 150}],
 'rows': [{'id': 8660990817003396,
   'rowNumber': 1,
   'expanded': True,
   'createdAt': '2020-02-14T13:15:18Z',
   'modifiedAt': '2020-02-14T13:15:18Z',
   'cells': [{'columnId': 6273865019090820, 'value': 1.0, 'displayValue': '1'},
    {'columnId': 4022065205405572, 'value': 'A', 'displayValue': 'A'},
    {'columnId': 8525664832776068, 'value': 'Joe', 'displayValue': 'Joe'}]},
  {'id': 498216492394372,
   'rowNumber': 2,
   'siblingId': 8660990817003396,
   'expanded': True,
   'createdAt': '2020-02-14T13:15:18Z',
   'modifiedAt': '2020-02-14T13:15:18Z',
   'cells': [{'columnId': 6273865019090820, 'value': 2.0, 'displayValue': '2'},
    {'columnId': 4022065205405572, 'value': 'B', 'displayValue': 'B'},
    {'columnId': 8525664832776068, 'value': 'Jim', 'displayValue': 'Jim'}]},
  {'id': 5001816119764868,
   'rowNumber': 3,
   'siblingId': 498216492394372,
   'expanded': True,
   'createdAt': '2020-02-14T13:15:18Z',
   'modifiedAt': '2020-02-14T13:15:18Z',
   'cells': [{'columnId': 6273865019090820, 'value': 3.0, 'displayValue': '3'},
    {'columnId': 4022065205405572, 'value': 'C', 'displayValue': 'C'},
    {'columnId': 8525664832776068, 'value': 'Jon', 'displayValue': 'Jon'}]}]}

这是我解决问题的两种方法:

输入:

from pandas.io.json import json_normalize
samplej = sample.json()
s_rows = json_normalize(data=samplej['rows'], record_path='cells', meta=['id', 'rowNumber'])
s_rows

输出:

DataFrame 以 columnId、value、disdlayValue、id 和 rowNumber 作为自己的字段。

如果我能弄清楚如何以正确的方式转置这些数据,我可能会使其工作,但这似乎非常复杂。

输入:

samplej = sample.json()
cellist = []
def get_cells():
    srows = samplej['rows']
    for s_cells in srows:
        scells = s_cells['cells']
        cellist.append(scells)
get_cells()
celldf = pd.DataFrame(cellist)
celldf

输出:

这将返回具有正确列数和行数的 DataFrame,但每个单元格都填充了一个看起来像

的字典
In [14]:
celldf.loc[1,1]
Out [14]:
{'columnId': 4022065205405572, 'value': 'B', 'displayValue': 'B'}

如果有办法删除除每个单元格中 displayValue 键对应的值之外的所有内容,这可能会解决我的问题。不过,这似乎又出奇的复杂。

我对 Python 和使用 API 还很陌生,因此可能有一种简单的方法可以解决我忽略的问题。或者,如果您对接近我上面概述的可能解决方案有建议,我会全力以赴。感谢您的帮助!

【问题讨论】:

  • 您有智能工作表示例吗?
  • @BillChen 我用样本表数据更新了问题。如果您需要其他信息,请告诉我!

标签: python pandas dataframe smartsheet-api


【解决方案1】:

您必须使用columns 字段:

colnames = {x['id']: x['title'] for x in samplej['columns']}
columns = [x['title'] for x in samplej['columns']]
cellist = [{colnames[scells['columnId']]: scells['displayValue']
            for scells in s_cells['cells']} for s_cells in samplej['rows']]
celldf = pd.DataFrame(cellist, columns=columns)

这符合预期:

  Number Letter Name
0      1      A  Joe
1      2      B  Jim
2      3      C  Jon

如果某些单元格只能包含 columnId 但不包含 displayValue 字段,则应将上述代码中的 scells['displayValue'] 替换为 scells.get('displayValue', defaultValue),其中 defaultValue 可以是 None、np.nan 或任何其他相关默认值。

【讨论】:

  • 它确实适用于样本表。是否有语法来处理为空的单元格。也就是说,内容中没有 displayValue 键的单元格?谢谢!
  • @denicoloma:他们有一个value 字段或者你想要在结果数据框中什么?
  • 如果单元格包含 displayValue 键,则使用显示值填充,否则使用 None 填充。当 SmartSheet 中的单元格为空时,字典仅包含 columnId。
猜你喜欢
  • 1970-01-01
  • 2014-02-24
  • 2020-12-26
  • 2014-09-16
  • 1970-01-01
  • 2017-05-08
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多