【问题标题】:Pandas adding rows to df in loop熊猫在循环中向df添加行
【发布时间】:2018-08-21 20:28:39
【问题描述】:

我正在循环解析数据,一旦它被解析和结构化,我想将它添加到数据框中。

我想要的数据框的结束格式如下:

df:

id   2018-01 2018-02 2018-03  
234     2       1       3
345     4       5       1
534     5       3       4
234     2       2       3

当我遍历循环中的数据时,我有一个包含 id、月份和月份值的字典,例如:

{'id':234,'2018-01':2}
{'id':534,'2018-01':5}
{'id':534,'2018-03':4}
           .
           .
           .

获取空数据框并在循环中向其中添加行和列及其值的最佳方法是什么?

基本上在我迭代时它看起来像这样

df:

id   2018-01   
234     2       

然后

df:

id   2018-01   
234     2  
534     5

然后

df:

id   2018-01   2018-03
234     2  
534     5         4

等等……

【问题讨论】:

  • 输入数据是什么?>

标签: python pandas dataframe


【解决方案1】:

IIUC,你需要先将单个dict转换为dataframe,然后我们做append,如果我们没有重复的'id',我们需要groupby获取first的值

df=pd.DataFrame()
l=[{'id':234,'2018-01':2},
{'id':534,'2018-01':5},
{'id':534,'2018-03':4}]

for x in l:
    df=df.append(pd.Series(x).to_frame().T.set_index('id')).groupby(level=0).first()
    print(df)

     2018-01
id          
234        2
     2018-01
id          
234        2
534        5
     2018-01  2018-03
id                   
234      2.0      NaN
534      5.0      4.0

【讨论】:

    【解决方案2】:

    不建议在每次迭代时生成一个新的数据帧并附加它,这非常昂贵。如果您的数据不是太大并且适合内存,您可以先制作一个字典列表,然后 pandas 允许您简单地做:

    df = pd.DataFrame(your_list_of_dicts)
    df.set_index('id')
    

    如果制作列表的成本很高(因为您想为数据框节省内存),请考虑使用 生成器 而不是列表。生成器函数的基本结构是这样的:

    def datagen(your_input):
        for item in your_input:
            # your code to make a dict
            yield dict
    

    生成器对象data = datagen(input) 不会存储字典,但会在每次迭代时产生一个字典。它可以按需生成项目。当您执行pd.DataFrame(data) 时,pandas 将流式传输所有数据并制作一个数据框。生成器可用于数据管道(如 UNIX 中的管道),并且对于大数据工作流非常强大。但是请注意,一个生成器对象只能被使用一次,也就是说,如果您再次运行 pd.DataFrame(data),您将得到一个空数据框。

    【讨论】:

    • 您能否提供更多信息,说明为什么它在循环中向现有 DF 添加数据是“昂贵的”?正如您所提到的,对于 memory,就地添加行会更节省内存;知道时间效率如何是有用的。我知道每次迭代的时间可能会影响数百万行,但也许对于 1000 行来说这不是问题。
    【解决方案3】:

    我在 Pandas 中发现(虽然不直观)迭代地将新数据行附加到数据帧的最简单方法是使用 df.loc[ ] 引用最后(不存在的)行,以 len(df) 作为索引:

    df.loc[ len(df) ] = [new, row, of, data]
    

    这会将新数据行“附加”到数据框的末尾。

    上面的例子是一个空的 Dataframe,正好有 4 列,例如:

    df = pandas.DataFrame(  columns=["col1", "col2", "col3", "col4"]  )
    

    df.loc[ ] 索引可以在任何 Row 插入数据,无论它是否存在。似乎它永远不会给出 IndexError,就像 numpy.arrayList 如果你试图分配给一个不存在的行。 对于一个全新的空 DataFrame,len(df) 返回0,因此引用第一个空白行,然后每次添加一行时增加一个。

    –––––

    我不知道这种方法的速度/内存效率成本,但它适用于我的适度数据集(几千行)。至少从内存的角度来看,我认为将数据直接附加到目标 DataFrame 的大型循环将比首先生成重复数据的中间列表,然后从该列表生成 DataFrame 使用更少的内存。时间“效率”可能完全是一个不同的问题,需要其他 SO 大师来评论。

    –––––

    但是,对于 OP 的特定情况,您要求合并 columns,如果数据用于现有的同名列,则在 for 循环期间需要 som 逻辑.

    相反,我会将 DataFrame 设置为“哑”,并按原样导入数据,并在它们到来时重复日期,例如。你的循环后 DataFrame 看起来像这样,用简单的列名描述 raw 数据:

    df:
    
    id   date      data
    234  2018-01   2
    534  2018-01   5
    535  2018-03   4
    

    (同一日期有两个条目)。

    然后我会使用 DataFrame 的数据库功能来组织这些数据,可能会使用df.unique()df.sort() 的某种组合。稍后将对此进行更多研究。

    【讨论】:

    • 顺便说一句,DataFrame.append() 函数的运行方式与 List.append() 不同,这似乎造成了严重的混乱 - 列表将 append() 就地,DataFrames append() 返回一个新数组。可能两者都有相同的“成本”,需要分配一个全新数组的内存,但pandas 使这一点显而易见,而List 对用户隐藏了这一点。
    猜你喜欢
    • 2021-05-20
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 2020-08-29
    • 2021-10-26
    • 2019-02-12
    • 2022-09-23
    • 2019-05-04
    相关资源
    最近更新 更多