【问题标题】:Updating Pandas row without iterrows在没有 iterrows 的情况下更新 Pandas 行
【发布时间】:2018-10-11 08:35:13
【问题描述】:

我有一个本地数据框,每天都会附加新条目。偶尔会更新一个旧条目。赠品是一堆列将匹配,但时间戳是更新的。

为了删除旧条目并保留新的(更新的)条目,我追加了新条目,然后通过遍历行并找到旧条目来“清理”数据框:

del_rows=[]
df2 = df.copy()
for index, row in df.iterrows():
    for index2, row2 in df2.iterrows():
        if row["crit1"]==row2["crit1"] and row["date"] > row2["date"]:
            del_rows.append(index2)

df = df.drop(df.index[del_rows])

虽然功能正常,但我很想知道执行此过程的更多“熊猫”方式。我知道apply 和 NumPy 矢量化更快;但是,我想不出可以将apply 映射到的函数,或者在给定不同数据类型的情况下使用矢量化的方法。

【问题讨论】:

  • 请尝试包含一个简单的example dataset,以显示您的数据是什么样的。

标签: python pandas loops


【解决方案1】:

IIUC,您可以使用duplicated() 创建布尔过滤器,因此对于示例数据框:

    crit1        date
0   test1  01-01-2018
1   test2  01-02-2018
2   test3  01-03-2018
3   test4  01-04-2018
4   test5  01-05-2018
5   test6  01-06-2018
6   test3  01-07-2018
7   test7  01-08-2018
8   test8  01-09-2018
9   test2  01-10-2018
10  test9  01-11-2018

简单地做:

df[~df.duplicated(subset=['crit1'], keep='last')].reset_index(drop=True)

产量:

   crit1        date
0  test1  01-01-2018
1  test4  01-04-2018
2  test5  01-05-2018
3  test6  01-06-2018
4  test3  01-07-2018
5  test7  01-08-2018
6  test8  01-09-2018
7  test2  01-10-2018
8  test9  01-11-2018

【讨论】:

  • 这是完美的:优雅而简单。非常感谢,我不知道 duplicated() 存在!
【解决方案2】:

这可以在crit1 上使用groupby 并选择最新的行来完成,如下所示:

df.sort_values('date').groupby('crit1').tail(1)

【讨论】:

  • 我知道某些项目可以用 loc 删除,但是脚本如何知道旧的 v 新项目而不检查每个项目与其他项目?或者您是否建议在附加新项目之前调整 df?
  • 我认为这会起作用,但实际数据集有很多额外的标准,在df[~df.duplicated(subset=['crit1'], keep='last')] 的子集部分添加几个标准似乎是一种更简单的方法,而不是重复/级别groupby
  • @user129818 有道理。请注意,keep='last' 保留遇到的最后一行,就日期/时间而言,这不一定是 最新 行。
【解决方案3】:

可能新条目的日期早于现有条目的日期。那么仅仅通过第一个或最后一个掺杂可能是不正确的。

另一种选择是通过找到最小条目来删除重复项。

下面是一个成功的例子。

import pandas as pd

date = pd.date_range(start='1/1/2018', end='1/5/2018')

crit = ['a', 'b', 'c', 'd', 'e']

df = pd.DataFrame({'crit':crit, 'date':date})

# insert a new entry to df
df.loc[len(df)] = ['b', '1/6/2016']

#convert date to datetime
df['date'] = pd.to_datetime(df['date'])

print(df, '\n')


#find the duplicated row in crit

print(df[df.duplicated('crit', keep=False)]['date'].min(), '\n')
print(df['date'] != df[df.duplicated('crit', keep=False)]['date'].min())

#apply 
df[df['date'] != df[df.duplicated('crit', keep=False)]['date'].min()]

【讨论】:

    猜你喜欢
    • 2021-04-05
    • 2012-11-24
    • 2021-09-07
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多