迭代地添加计算列,然后将新数据添加到 Pandas 数据框(python 3.7.1)

Posted

技术标签:

【中文标题】迭代地添加计算列,然后将新数据添加到 Pandas 数据框(python 3.7.1)【英文标题】:Adding calculated columns and then just new data to a Pandas dataframe iteratively (python 3.7.1) 【发布时间】:2019-08-05 07:04:20 【问题描述】:

我有一个初始数据帧 df1:

    df1 = pd.DataFrame(np.array([[1, 'B', 'C', 'D', 'E'], [2, 'B', 'C', 'D', 'E'], [3, 'B', 'C', 'D', 'E'], [4, 'B', 'C', 'D', 'E'], [5, 'B', 'C', 'D', 'E']]), columns=['a', 'b', 'c', 'd', 'e'])

        a   b   c   d   e
    0   1   B   C   D   E
    1   2   B   C   D   E
    2   3   B   C   D   E
    3   4   B   C   D   E
    4   5   B   C   D   E

然后我根据 df1 列值计算一些新参数,创建一个新的 df2 并在列名“a”上与 df1 合并。

    df2 = pd.DataFrame(np.array([[1, 'F', 'G'], [2, 'F', 'G']]), columns=['a', 'f', 'g'])

        a   f   g
    0   1   F   G
    1   2   F   G
    df1 = pd.merge(df1, df2,  how='left', left_on=['a'], right_on = ['a'])

        a   b   c   d   e   f   g
    0   1   B   C   D   E   F   G
    1   2   B   C   D   E   F   G
    2   3   B   C   D   E   NaN NaN
    3   4   B   C   D   E   NaN NaN
    4   5   B   C   D   E   NaN NaN

这工作得很好,但是在另一个循环事件中,我创建了一个与 df2 具有相同列的 df3,但在这种情况下合并不起作用,它没有考虑到相同的列已经在 df1 中。

重要说明:这仅用于说明目的,要添加数千个新数据帧,每个循环步骤一个。

    df3 = pd.DataFrame(np.array([[3, 'F', 'G']]), columns=['a', 'f', 'g'])

        a   f   g
    0   3   F   G
df1 = pd.merge(df1, df3,  how='left', left_on=['a'], right_on = ['a'])

        a   b   c   d   e   f_x g_x f_y g_y
    0   1   B   C   D   E   F   G   NaN NaN
    1   2   B   C   D   E   F   G   NaN NaN
    2   3   B   C   D   E   NaN NaN F   G
    3   4   B   C   D   E   NaN NaN NaN NaN
    4   5   B   C   D   E   NaN NaN NaN NaN

我只是使用已经存在的列来填补缺失的空白。这种方法会创建新列(f_x, g_x, f_y, g_y)

附加和联系也不起作用,因为它们重复信息(“a”上的重复行)。

关于如何解决这个问题的任何建议? 最终结果df1df2 合并后,与df3 合并后应为:

        a   b   c   d   e   f   g
    0   1   B   C   D   E   F   G
    1   2   B   C   D   E   F   G
    2   3   B   C   D   E   F   G
    3   4   B   C   D   E   NaN NaN
    4   5   B   C   D   E   NaN NaN

最终所有的列都会在循环过程中被填充,所以第一个添加的 (df2) 将添加新的列,从 df3 开始只是新的数据来填充所有的 NaN。循环如下所示:

df1 = pd.DataFrame(np.array([[1, 'B', 'C', 'D', 'E'], [2, 'B', 'C', 'D', 'E'], [3, 'B', 'C', 'D', 'E'], [4, 'B', 'C', 'D', 'E'], [5, 'B', 'C', 'D', 'E']]), columns=['a', 'b', 'c', 'd', 'e'])
for num, item in enumerate(df1['a']):
    #compute df[num] (based on values on df1)
    df1 = pd.merge(df1, df[num],  how='left', left_on=['a'], right_on = ['a'])

【问题讨论】:

我在编辑后看到了你的新评论。您能否在merge 所有这些数据帧的位置展示您的loop 的一部分? @Erfan 类似于:df1 = pd.DataFrame(np.array([[1, 'B', 'C', 'D', 'E'], [2, 'B', 'C', 'D', 'E'], [3, 'B', 'C', 'D', 'E'], [4, 'B', 'C', 'D', 'E'], [5, 'B', 'C', 'D', 'E']]), columns=['a', 'b', 'c', 'd', 'e'])for num, item in enumerate(df1['a'].values): #compute df[num] df1 = pd.merge(df1, df[num], how='left', left_on=['a'], right_on = ['a']) 请在您的帖子中包含此内容@juanman 【参考方案1】:

一种可能的解决方案是concat 全部小DataFrames,然后只有一次merge

df4 = pd.concat([df2, df3])
print (df4)
   a  f  g
0  1  F  G
1  2  F  G
0  3  F  G

df1 = pd.merge(df1, df4,  how='left', on = 'a')
print (df1)
   a  b  c  d  e    f    g
0  1  B  C  D  E    F    G
1  2  B  C  D  E    F    G
2  3  B  C  D  E    F    G
3  4  B  C  D  E  NaN  NaN
4  5  B  C  D  E  NaN  NaN

另一种可能的解决方案是使用DataFrame.combine_firstDataFrame.set_index

df1 = (df1.set_index('a')
         .combine_first(df2.set_index('a'))
         .combine_first(df3.set_index('a')))
print (df1)
   b  c  d  e    f    g
a                      
1  B  C  D  E    F    G
2  B  C  D  E    F    G
3  B  C  D  E    F    G
4  B  C  D  E  NaN  NaN
5  B  C  D  E  NaN  NaN

【讨论】:

感谢@jezrael 的方法有一个重要的说明:新的数据帧是循环生成的,一次一个新的。所以我们与原始(df1)合并的第一个是可以的,但是在我们遇到这个问题之后。我们要生成数千个 df,因此将它们全部存储并在最后合并它们可能不会节省内存。但我会努力的。 @juanman - 嗯,merge 循环中的数据应该消耗更多的内存,但这一切都取决于数据。最好的测试一下。 @juanman - 通用解决方案不容易,我再找一个,请检查一下。 从那时起我一直在测试这种方法,由于数学计算量的原因,它只需要很长时间。有数以千计的数据框要创建,会让您保持更新。谢谢! 谢谢,我确认这成功了!所以我首先创建了所有新数据帧的列表,然后将它们连接起来,最后与原始数据帧 (df1) 合并。【参考方案2】:

另一种方法是使用fillna,然后删除不再需要的额外列:

# Fill NaN with the extra columns value
df1.f_x.fillna(df1.f_y, inplace=True)
df1.g_x.fillna(df1.g_y, inplace=True)

   a  b  c  d  e  f_x  g_x  f_y  g_y
0  1  B  C  D  E    F    G  NaN  NaN
1  2  B  C  D  E    F    G  NaN  NaN
2  3  B  C  D  E    F    G    F    G
3  4  B  C  D  E  NaN  NaN  NaN  NaN
4  5  B  C  D  E  NaN  NaN  NaN  NaN

# Slice of the last two columns
df1 = df1.iloc[:, :-2]
# Rename the columns correctly
df1.columns = df1.columns.str.replace('_x', '')

输出

   a  b  c  d  e    f    g
0  1  B  C  D  E    F    G
1  2  B  C  D  E    F    G
2  3  B  C  D  E    F    G
3  4  B  C  D  E  NaN  NaN
4  5  B  C  D  E  NaN  NaN

【讨论】:

【参考方案3】:

我会在与 df3 的合并中只使用df1 的子集,或者我会保留原始df1 的副本。

    子集:

    df1.fillna(pd.merge(df1.loc(1)['a':'e'], df3, how='left',
                        left_on=['a'], right_on = ['a']),
               inplace=True)
    

    原始数据的副本

    df1_orig = df1           # before merging with df2
    ...
    df1.fillna(pd.merge(df1_orig, df3, how='left',
                        left_on=['a'], right_on = ['a']),
               inplace=True)
    

【讨论】:

以上是关于迭代地添加计算列,然后将新数据添加到 Pandas 数据框(python 3.7.1)的主要内容,如果未能解决你的问题,请参考以下文章

如何遍历数据框,将新字段添加到系列,然后将该系列附加到 csv?

根据多个条件将新列添加到 Python Pandas DataFrame [重复]

熊猫:将新列添加到作为索引列副本的数据框

如何将新列添加到按 groupby 分组的分层数据框中

将新列添加到现有表中并使用 PL/SQL 中游标中的值更新它们

将新列添加到 wordpress 数据库