我有一个dataframe df
,其中包含'Name','Date'和'Id'列。'Id'列最初全为0,我想如下填充它:具有相同“Date”和same_names(name_i, name_j) == True
的行采用相同的ID。
我设法用一个for循环来完成它,它遍历df的行:
from collections import defaultdict
import pandas as pd
def same_names(name1, name2):
name1_parts = name1.split()
name2_parts = name2.split()
# Compare last names
return name1_parts[-1] == name2_parts[-1]
# Sample data
data = [
['John Smith', '2022-01-01', 0],
['Mary Johnson', '2022-01-04', 0],
['Mark Williams', '2022-01-02', 0],
['Jessica Brown', '2022-01-03', 0],
['David Lee', '2022-01-03', 0],
['John Brown', '2022-01-02', 0],
['Frank Johnson', '2022-01-04', 0],
['Mary Lee', '2022-01-03', 0],
['David Lee', '2022-01-03', 0]
]
header = ['Name', 'Date', 'Id']
df = pd.DataFrame(data, columns=header)
date_to_index = defaultdict(list)
for index, row in df.iterrows():
date = row['Date']
if date in date_to_index:
for i in date_to_index[date]:
prev_row = df.iloc[i]
if same_names(prev_row['Name'], row['Name']):
df.at[index, 'Id'] = prev_row['Id']
else:
df.at[index, 'Id'] = df["Id"].max() + 1
date_to_index[date].append(index)
else:
if index > 0:
df.at[index, 'Id'] = df["Id"].max() + 1
date_to_index[date].append(index)
df.sort_values(by="Id", inplace=True, ignore_index=True)
print(df)
结果:
Name Date Id
0 John Smith 2022-01-01 0
1 Mary Johnson 2022-01-04 1
2 Frank Johnson 2022-01-04 1
3 Mark Williams 2022-01-02 2
4 Jessica Brown 2022-01-03 3
5 David Lee 2022-01-03 4
6 Mary Lee 2022-01-03 4
7 David Lee 2022-01-03 4
8 John Brown 2022-01-02 5
有没有办法将这段代码向量化(或者用其他方法使它更快)?也许可以用groupby
,但问题是我使用函数same_names
来比较名称,而不仅仅是通过相等来比较,这会使它变得复杂。
注意:same_names()
函数可能与示例不同,因为实际上名称可能会更混乱(例如,不是'玛丽Json',而是'Johnson Mary'或'Ms Mary Johnson',所以我仍然需要弄清楚same_names()
将是什么)。
2条答案
按热度按时间qco9c6ql1#
您可以拆分列并获取list中的最后一个元素,然后使用
pd.factorize
将Series值编码为枚举类型yfwxisqw2#
我知道你的函数
same_names
可能不同。不过,如果总是比较,你可以使用一个函数(下面的
identity
)来计算一个用于分组的临时列。这与标准sorted()
函数的key
参数是相同的机制。您还需要一个来自
itertools
的计数器来生成id。如果不使用
"Id"
列,可以首先删除它。下面是如何做到这一点: