想象一下2个数据框,其中MasterDB(df1)是中央数据库,而LatestResults(df2)是我每周检索的传入CSV。
df1 = pd.read_sv("Master.csv")
#with columns:
Index(['Timestamp', 'ID', 'Status', 'Username', 'URL', 'Last Seen'],
dtype='object')
Shape(1000,6)
df2 = pd.read_sv("LatestResults.csv")
#with same columns:
Index(['Timestamp', 'ID', 'Status', 'Username', 'URL', 'Last Seen'],
dtype='object')
Shape(300,6)
基于某些条件,我想遍历df2中的(新)项目,并根据以下3个条件(假设目前只有3个条件)来处理项目:
a)如果不存在新项目(针对不匹配的“ URL”)
b)如果已经存在新项目,请将其状态编辑为“仍然有效”(用于匹配“ URL”,而不考虑“ ID”)
c)如果在LatestResults中找不到MasterDB(df1)中的项目(仅用于匹配“ ID”和“ URL”)
这是我到目前为止的代码:
def function(input1, input2):
df1 = pd.read_csv(input1)
df2 = pd.read_csv(input2)
df1['Status'] = df1['Status'].astype(str)
df1['Last Seen'] = df1['Last Seen'].astype(str)
for i, row in df1.iterrows():
tmp = df2.loc[(df2['URL'] == row['URL'])
# A) STILL ACTIVE
if not tmp.empty:
df1.at[i, 'Last Seen'] = str(datetime.now().replace(second=0, microsecond=0))
df1.at[i, 'Status'] = "STILL ACTIVE"
for i, row in df1.iterrows():
tmp = df2.loc[(df2['URL'] == row['URL']) & (df2['ID'] == row['ID'])]
# B) NOT FOUND // EXPIRED
if tmp.empty:
df1.at[i, 'Status'] = "EXPIRED"
for i, row in df2.iterrows():
tmp = df1.loc[(df1['URL'] == row['URL']) & (df1['ID'] == row['ID'])]
# C) NET NEW
if tmp.empty:
df1.at[i, 'Last Seen'] = str(datetime.now().replace(second=0, microsecond=0))
row["Status"] = "NET NEW"
df1 = df1.append(row, ignore_index=True)
df1['Last Seen'].fillna("Not Set", inplace=True)
df1.to_csv("MasterDB.csv", index=False)
该解决方案在大多数情况下都有效。追加了新项目,并且正确标记了(某些)先前存在的项目。我遇到的问题是:
我已经探索过使用熊猫合并,联接和地图,但使用上面的方法坚持不懈。但是几天之后,我意识到它的体积很大。我很想听听有关如何进行不同设计的想法。预先非常感谢。
答案 0 :(得分:0)
我将与您分享如何为您的问题实施解决方案。也许有不同的观点可以帮助您了解代码中的错误。
首先,我使用的数据。这是我的LatestResults.csv
ID Status Username URL Last Seen
0 1 new Harry Potter google 2020-10-20 12:00:00
1 20 new Hermione Granger yahoo 2020-10-20 12:00:00
2 3 new Ron Weasley twitter 2020-10-20 12:00:00
3 4 new Hagrid instagram 2020-10-20 12:00:00
这是我的MasterDB.csv
ID Status Username URL Last Seen
0 1 blabla Harry Potter google 2020-10-20 12:00:00
1 2 blabla Hermione Granger yahoo 2020-10-20 12:00:00
2 3 blabla Ron Weasley bing 2020-10-20 12:00:00
3 4 blabla McGonagall facebook 2020-10-20 12:00:00
4 5 blabla Dumbledore google 2020-10-20 12:00:00
5 6 blabla You-Know-Who badoo 2020-10-20 12:00:00
我试图包括所有可能的组合:
Harry Potter
在两个DataFrame中都具有相同的ID
和URL
Hermione Granger
具有相同的URL
,但不同的ID
Ron Weasley
具有相同的ID
,但不同的URL
McGonagall
具有唯一的URL
,但与ID
相同的Hagrid
Dumbledore
具有唯一的ID
,但与URL
相同的Harry Potter
You-Know-Who
具有唯一性ID
和URL
Hagrid
具有唯一的唯一URL
,但它不在您的数据库中我知道代码中的任何地方都没有使用username
,但是这些名称有助于我们了解发生了什么。
现在输入代码。
def new_function(db_file, input_file):
today = datetime.now().replace(second=0, microsecond=0)
df_input = pd.read_csv(input_file)
df_database = pd.read_csv(db_file)
df_database['Last Seen'].astype(str)
# Filter for input data
net_new_filter = ~ df_input['URL'].isin(df_database['URL'])
# Filter for DB data
still_active = df_database['URL'].isin(df_input['URL'])
expired_filter = (pd.merge(df_database, df_input, on=['ID', 'URL'],
how='left', indicator=True)['_merge'] != 'both')
expired_filter = expired_filter & (~ still_active)
# Applying filters
df_database.loc[still_active, 'Status'] = 'Still Active'
df_database.loc[still_active, 'Last Seen'] = str(today)
df_database.loc[expired_filter, 'Status'] = 'Expired'
new_data = df_input[net_new_filter].copy()
new_data['Status'] = 'Net New'
new_data['Last Seen'] = str(today)
final_database = pd.concat([df_database, new_data],
ignore_index=True)
final_database.to_csv("Test_Data/Output.csv", index=False)
我喜欢单独编写DataFrame过滤器,因为它可以使您更清楚地应用什么条件。
您可以使用方法.isin()
来验证一列的元素是否位于另一列的某处。它直接检测“仍处于活动状态”和“净新状态”。
然后,如果要检查同一行的两列是否同时等于其他两列,则可以使用.merge()
方法,例如描述的here。但是,我们一定不能覆盖“保持活动”条件,因此不能覆盖附加表达式expired_filter = expired_filter & (~ still_active)
。
运行代码后,将保存以下DataFrame:
ID Status Username URL Last Seen
0 1 Still Active Harry Potter google 2020-10-23 20:18:00
1 2 Still Active Hermione Granger yahoo 2020-10-23 20:18:00
2 3 Expired Ron Weasley bing 2020-10-20 12:00:00
3 4 Expired McGonagall facebook 2020-10-20 12:00:00
4 5 Still Active Dumbledore google 2020-10-23 20:18:00
5 6 Expired You-Know-Who badoo 2020-10-20 12:00:00
6 3 Net New Ron Weasley twitter 2020-10-23 20:18:00
7 4 Net New Hagrid instagram 2020-10-23 20:18:00
具有新URL
的行位于末尾,而来自原始数据库的与ID
和URL
不完全匹配的行被设置为“过期”。最后,保留具有相应URL
的行,并将它们的Status
设置为“保持活动”。
希望此示例对您有所帮助。至少它要快一点,因为它不依赖于for
循环。
如果数据没有帮助,请提供您自己的数据样本,以便我们可以使用相同的数据集进行测试。