【问题标题】:How to concatenate two dataframes without duplicates?Pandas/Python:如何连接两个没有重复的数据帧?
【发布时间】:2014-02-14 13:04:26
【问题描述】:

我想将两个数据帧 A、B 连接到一个没有重复行的新数据帧(如果 B 中的行已经存在于 A 中,则不要添加):

数据框 A:数据框 B:

   I    II    I    II
0  1    2     5    6
1  3    1     3    1

新数据框:

     I    II
  0  1    2
  1  3    1
  2  5    6

我该怎么做?

【问题讨论】:

  • 确保您的示例是有效的 python,并且您没有遗漏任何内容。您似乎缺少索引。
  • A 和 B 是数据框名称。这是你的意思吗?
  • 我的意思是A = pd.DataFrame({"II": [2, 1]}, index=[1, 3])I 列是 DataFrame 的索引吗?
  • I 和 II 是列名。
  • 那么你应该在你的例子中包含索引。最好从提示中复制粘贴示例。

标签: python pandas duplicates


【解决方案1】:

最简单的方法是只进行连接,然后删除重复项。

>>> df1
   A  B
0  1  2
1  3  1
>>> df2
   A  B
0  5  6
1  3  1
>>> pandas.concat([df1,df2]).drop_duplicates().reset_index(drop=True)
   A  B
0  1  2
1  3  1
2  5  6

reset_index(drop=True)是修复concat()drop_duplicates()之后的索引。没有它,您将拥有[0,1,0] 的索引,而不是[0,1,2]。如果不立即重置此dataframe,这可能会导致后续操作出现问题。

【讨论】:

  • 也可以在 concat 中使用 ignore_index=True 来避免重复索引。
  • @AndyHayden 可能值得注意 - 你可以使用 ignore_index=True 来避免重复索引,但如果你不使用 reset_index,那么你可能跳过了索引(因为它们被删除了)(例如. 0, 1, 2, 4, 5 ...),这可能是不可取的
【解决方案2】:

我很惊讶 pandas 没有为此任务提供本地解决方案。 如果您使用大型数据集(如 Rian G 建议的那样),我认为仅删除重复项并不有效。

使用集合来查找不重叠的索引可能是最有效的。然后使用列表推导从索引转换为“行位置”(布尔值),您需要使用 iloc[,] 访问行。您可以在下面找到执行该任务的函数。如果您不选择特定列 (col) 来检查重复项,则将按照您的要求使用索引。如果您选择了特定列,请注意“a”中现有的重复条目将保留在结果中。

import pandas as pd

def append_non_duplicates(a, b, col=None):
    if ((a is not None and type(a) is not pd.core.frame.DataFrame) or (b is not None and type(b) is not pd.core.frame.DataFrame)):
        raise ValueError('a and b must be of type pandas.core.frame.DataFrame.')
    if (a is None):
        return(b)
    if (b is None):
        return(a)
    if(col is not None):
        aind = a.iloc[:,col].values
        bind = b.iloc[:,col].values
    else:
        aind = a.index.values
        bind = b.index.values
    take_rows = list(set(bind)-set(aind))
    take_rows = [i in take_rows for i in bind]
    return(a.append( b.iloc[take_rows,:] ))

# Usage
a = pd.DataFrame([[1,2,3],[1,5,6],[1,12,13]], index=[1000,2000,5000])
b = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], index=[1000,2000,3000])

append_non_duplicates(a,b)
#        0   1   2
# 1000   1   2   3    <- from a
# 2000   1   5   6    <- from a
# 5000   1  12  13    <- from a
# 3000   7   8   9    <- from b

append_non_duplicates(a,b,0)
#       0   1   2
# 1000  1   2   3    <- from a
# 2000  1   5   6    <- from a
# 5000  1  12  13    <- from a
# 2000  4   5   6    <- from b
# 3000  7   8   9    <- from b

【讨论】:

  • 如果只删除所有行值重复的行怎么办?如示例所示,使用col = 0 会删除b 中以1 开头的每一行。
  • 通常使用isinstance 而不是type(...) is ...
【解决方案3】:

如果您在 DataFrame A 中已有重复行,则连接然后删除重复行,将从 DataFrame A 中删除您可能想要保留的行。

在这种情况下,您需要创建一个具有累积计数的新列,然后删除重复项,这完全取决于您的用例,但这在时间序列数据中很常见

这是一个例子:

df_1 = pd.DataFrame([
{'date':'11/20/2015', 'id':4, 'value':24},
{'date':'11/20/2015', 'id':4, 'value':24},
{'date':'11/20/2015', 'id':6, 'value':34},])

df_2 = pd.DataFrame([
{'date':'11/20/2015', 'id':4, 'value':24},
{'date':'11/20/2015', 'id':6, 'value':14},
])


df_1['count'] = df_1.groupby(['date','id','value']).cumcount()
df_2['count'] = df_2.groupby(['date','id','value']).cumcount()

df_tot = pd.concat([df_1,df_2], ignore_index=False)
df_tot = df_tot.drop_duplicates()
df_tot = df_tot.drop(['count'], axis=1)
>>> df_tot

date    id  value
0   11/20/2015  4   24
1   11/20/2015  4   24
2   11/20/2015  6   34
1   11/20/2015  6   14

【讨论】:

    猜你喜欢
    • 2020-09-02
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2023-03-25
    相关资源
    最近更新 更多