【问题标题】:Updating Dataframe based on another new dataframe基于另一个新数据框更新数据框
【发布时间】:2020-09-25 14:28:10
【问题描述】:

我有 2 个数据帧,其结构方式如下:

df1 = pd.read_csv("Main_Database.csv")
# df1 Columns: ..., Timestamp, Name, Query, Website, Status,...

df2 = pd.read_csv("New_Raw_Results.csv")
# df2 COlumns: ..., Timestamp, Name, Query, Website, Status,...

两个数据框可以拥有完全相同的列。

我的Main_database.csv 跟踪所有记录,我的new_raw_results 是每周新结果的列表。我想根据 3 个场景处理我的 main_database 中的更改:

A) 如果在 DF1 中找到 DF2 中的查询 AND 网站, --> 使用 Df2 中的 Timestamp 在 DF1 列“Last Seen”中写入 --> 覆盖状态为"STILL ACTIVE"

B) 如果 DF2 中的查询 AND 网站在 DF1 中未找到, --> 将整个 df2.row 附加到 df1 --> 覆盖状态为"NET NEW"

C) IF 查询 AND DF1 中的网站在 DF2 中未找到, --> 覆盖状态为"EXPIRED"

我尝试过使用合并和连接的组合,但我被困在这里。例如,如果我在一个新的数据框中隔离了这两个表之间的内部连接的结果,我不确定如何使用它来对我的主数据库执行操作。我试图在一个函数下满足所有这些条件,所以我可以使用这个函数来处理新条目。

你会如何构建这个函数?解决这个问题的最简洁的方法是什么?

【问题讨论】:

  • 如果您接近您的任何合并或连接或任何中间步骤似乎有效,您应该在问题中说明哪些有效,哪些无效以及它们如何不足。您还应该包含两个 DataFrame 的最小示例 - 仅包含您感兴趣的几列和足够的行以根据您的三个条件生成 TrueFalse 值。
  • 请接受任何答案,如果有正确的答案,那么显然没有什么可做的了

标签: python dataframe


【解决方案1】:

这应该做你的事情:

import pandas as pd

data = [
{"timestamp": 1, "last_seen": 1, "status": "XXX", "website": "website1", "query": "query1"},
{"timestamp": 1, "last_seen": 2, "status": "XXX", "website": "website2", "query": "query2"},
{"timestamp": 1, "last_seen": 3, "status": "XXX", "website": "website3", "query": "query1"},
{"timestamp": 1, "last_seen": 4, "status": "XXX", "website": "website5", "query": "query1"},
{"timestamp": 1, "last_seen": 5, "status": "XXX", "website": "website6", "query": "query1"}
]

new_data = [
{"timestamp": 1, "last_seen": 6, "status": "XXX", "website": "website1", "query": "query1"},
{"timestamp": 1, "last_seen": 7, "status": "XXX", "website": "website2", "query": "query2"},
{"timestamp": 1, "last_seen": 8, "status": "XXX", "website": "website3", "query": "query4"},
{"timestamp": 1, "last_seen": 9, "status": "XXX", "website": "website3", "query": "query8"}
]

df = pd.DataFrame(data)
df_new = pd.DataFrame(new_data)

for i, row in df.iterrows():
    tmp = df_new.loc[(df_new['website'] == row['website']) & (df_new['query'] == row['query'])]
    if not tmp.empty:
        # A)
        df.at[i, 'last_seen'] = tmp['last_seen']
        df.at[i, 'status'] = "STILL ACTIVE"
    else:
        # B)
        df.at[i, 'status'] = "EXPIRED"

for i, row in df_new.iterrows():
    # C)
    tmp = df.loc[(df['website'] == row['website']) & (df['query'] == row['query'])]
    if tmp.empty:
        row["status"] = "NET NEW"
        df = df.append(row, ignore_index=True)

print(df)

【讨论】:

  • 就是这样。 :D 正是我需要的。非常感谢,我现在意识到我可以更好地制定我的例子
【解决方案2】:

数据集

import pandas as pd
from numpy.random import default_rng
rng = default_rng()

columns = ['query','website','timestamp','status','last_seen']
data = rng.integers(1,20,(100,5))
df1 = pd.DataFrame(data=data, columns=columns,dtype=str)
data = rng.integers(1,20,(100,5))
df2 = pd.DataFrame(data=data, columns=columns,dtype=str)

连接querywebsite 列将有助于比较。例如

      Query   Website
  0  query1  website1  --> 'query1website1'

为连接列的每个 DataFrame 制作一个系列

a = df2['query'].str.cat(df2.website)
b = df1['query'].str.cat(df1.website)

为您的三个条件中的每一个创建一个布尔系列。

cond1 = a.isin(b)    # ended up not using this
cond2 = ~cond1
cond3 = ~b.isin(a)

根据条件 3 设置状态 - 你的 C)

df1.loc[cond3,'status'] = 'EXPIRED'

更新新信息 - 您的 A)

使用 numpy broadcasting 将所有 df2 值 (a) 与所有 df1 值 (b) 进行比较,并获取它们匹配的索引。

indices1 = (a.values[:,None] == b.values).argmax(1)

(a.values[:,None] == b.values) 生成一个二维布尔数组,它是每个 a 值与每个 b 值的比较。 argmax 函数返回它们匹配的索引。

# df1 row indices where df1.qw == df2.qw
x = indices1[indices1 > 0]
# df2 rows where df2.qw == df1.qw
y = df2.loc[np.where(indices1 > 0)]

xdf1 整数索引数组,在df2 中有匹配y 是与 xdf2 的子集)对应的 匹配 的 DataFrame。使用整数数组将新值分配给正确的df1 行。

df1.loc[x,'last_seen'] = y.timestamp.values
df1.loc[x,'status'] = "STILL ACTIVE"

警告:如果 df1 有多个具有相同 qw 值的行,np.argmax 将只找到第一个,而第二个的列保持不变。使用随机数据会定期出现。


添加新行 - 您的 B)

df2.loc[cond2,'status'] = "NET NEW"
df1 = pd.concat([df1,df2.loc[cond2]], ignore_index=True)

完成...

a = df2['query'].str.cat(df2.website)
b = df1['query'].str.cat(df1.website)

cond1 = a.isin(b)    # ended up not using this
cond2 = ~cond1
cond3 = ~b.isin(a)

df1.loc[cond3,'status'] = 'EXPIRED'

indices1 = (a.values[:,None] == b.values).argmax(1)
x = indices1[indices1 > 0]
y = df2.loc[np.where(indices1 > 0)]

df1.loc[x,'last_seen'] = y.timestamp.values
df1.loc[x,'status'] = "STILL ACTIVE"

df2.loc[cond2,'status'] = "NET NEW"
df1 = pd.concat([df1,df2.loc[cond2]], ignore_index=True)

【讨论】:

  • 感谢您的帮助。我还没有弄清楚指数,但我到了那里
猜你喜欢
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
相关资源
最近更新 更多