【问题标题】:Can pd.DataFrame.apply append dataframe returned by lambda function?pd.DataFrame.apply 可以附加 lambda 函数返回的数据帧吗?
【发布时间】:2021-01-23 09:16:13
【问题描述】:

我正在尝试转换此代码 -

    for item in data['item'].unique():
     response = process_item(item) # returns List[Dict[Text, Optional[int]]]
     response = pd.DataFrame(response)
     response['item'] = item
     final_response = final_response.append(response)

类似于 -

    data = data[['item']].drop_duplicates().reset_index(drop=True)
    final_response = data[['item']].apply(lambda x: process_item(x))
    final_response['item'] = data['item']

这个想法是稍后使用 dask 并行处理数据帧上的应用。

我尝试从 process_item 返回一个 pd.DataFrame 但我得到 ValueError: If using all scalar values, you must pass an index

响应看起来像这样 -

   A       B         C
0  456  foo bar     123.0

如何解决 ValueError 以及我的假设 apply 会将输出 df 从 process_item 附加到 final_response 是否正确?

编辑:添加示例数据

在 pd.Series 中包装 process_item 的输出 -

#output from process_item
{'A': [456, 789], 'B': ['foo bar', 'dog bar'], 'C': [123.0, 160.0]}

#printing ouput in pd.Series
A        [456, 789]
B        [foo bar, dog bar]
C        [123.0, 160.0]

#Adding a new 'item' column
          A             B           C                    item
0  [456, 789]  [foo bar, dog bar]  [123.0, 160.0]         bar

下面是从第一个代码sn -p -

#output from process_item
{'A': [456, 789], 'B': ['foo bar', 'dog bar'], 'C': [123.0, 160.0]}

#output from process_item in pd.DataFrame
    A      B          C
0  456  foo bar     123.0
1  789  dog bar     160.0

#Adding a new 'item' column
            A              B               C           item
0          456          foo bar          123.0         bar
1          789          dog bar          160.0         bar

我需要按照第二个示例添加的项目。

编辑(已解决): 我终于能够让它与@yugandhar 共享的 split_dataframe_rows 函数中的一些变化一起工作。 1. 计算 max_split - 它正在计算新添加的“item”列的长度,其中包含“bar”,因此计算结果为 3,而其他列表仅包含两个元素,因此添加了类型检查。 2. split_rows[column_selector].pop(0) 为“item”列抛出错误,说 str 对象没有 pop 属性。因此,仅当它是一个列表时才添加一个检查来执行此操作,否则只需分配。也使用您更新的解决方案进行了测试,并且工作正常。不知道为什么这些问题没有出现在 colab 上,可能是 python 版本的差异之类的。 我试过爆炸,但它对我也不起作用,我想我没有使用 pandas 0.25。我将继续寻找更好的方法来进行拆分。

【问题讨论】:

标签: pandas


【解决方案1】:

如果我理解正确,那么您需要进行以下更改:
返回 pd.Series 而不是 pd.DataFrame,
使用 data['item'] 获取值(这是您需要的apply) 列和
data[['item']] 以获取具有索引和项目列的数据框
Working Solution

【讨论】:

  • 谢谢@yugandhar,这非常适合标量列表,但是我从 process_item 得到的输出是一个类似这样的字典列表 - List[Dict[Text, Optional[int]]] 抱歉,我应该更清楚地了解数据.更新了问题。
  • @rxtechsbay 检查此Updated Solutionhere 中提取了拆分功能,因为 Pandas df.explode 功能不起作用并且知道原因。这能解决您的问题吗?
  • 我在这一行收到此错误TypeError: _split_list_to_rows() got an unexpected keyword argument 'axis' - df.apply(_split_list_to_rows,axis=1,args = (new_rows,column_selectors)) 不知道为什么。想法?
  • @rxtechsbay 您可能在 split_dataframe_rows 和 Series.apply() 中将 pd.Series 作为 df 参数传递,而 DataFrame.apply() 不支持轴参数
  • 我的代码中的最后三行与您更新的解决方案中的相同,只是我在 apply 中调用了一个 lambda 函数,该函数返回包装在 pd.Series 中的响应。 process_item(item) {return pd.Series({'A': [456, 789], 'B': ['foo bar', 'dog bar'], 'C': [123.0, 160.0]})} 在你的情况下,final_response 似乎被 python 视为 df,而在我的情况下,它被视为一个系列。
【解决方案2】:

考虑使用列表推导来构建要在最后连接的数据框列表:

dfs = [(pd.DataFrame(process_item(i)) 
          .assign(item = i) 
       ) for i in data['item'].unique()]

final_df = pd.concat(dfs, ignore_index=True)

【讨论】:

    猜你喜欢
    • 2015-12-09
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    相关资源
    最近更新 更多