[英]Update pandas column values if they are equal to another column's value
我有一個 pandas 數據框,其中包含帳戶 ID、家庭、工作和手機號碼。 所有這些值都是字符串。 我的目標是更新每一行的值,使同一行和不同行中的所有重復數字都設置為 NaN,留下一個“原始”數字。 我怎樣才能有效地完成這項工作?
更新同一行中的值時,優先考慮家庭電話,然后是工作電話。 因此,如果home == work == mobile
,則 work 和 mobile 都會更新為 NaN。 如果home != work == mobile
,則 mobile 更新為 NaN。 更新不同行中的值時,將哪個重復電話號碼保留為“原始”號碼並不重要。 例如,如果A['home'] == B['mobile'] == C['work']
,其中兩個值應設置為 NaN,其余一個保持不變。 在顯示數據框時,我選擇保留第一個數字並將其他重復數字設置為 NaN。
我已經想出如何使用df.loc
更新同一行內的值,但我一直沒能弄清楚如何將不同行和列的重復值更新為 NaN。 我怎樣才能做到這一點?
以下是有關我正在嘗試做什么以及我遇到困難的更多信息:
我的初始數據框看起來像這樣:
acct_id home work mobile
A 1111111111 1111111111 1111111111
B 2222222222 2222222222 2222222222
C 3333333333 3333333333 3333333333
D 4444444444 5555555555 5555555555
E 6666666666 7777777777 8888888888
F 9999999999 9999999999 8888888888
G 7777777777 6666666666 5555555555
H 4444444444 3333333333 2222222222
I NaN NaN NaN
我的目標是更新數據框,使其看起來像這樣:
acct_id home work mobile
A 1111111111 NaN NaN
B 2222222222 NaN NaN
C 3333333333 NaN NaN
D 4444444444 5555555555 NaN
E 6666666666 7777777777 8888888888
F 9999999999 NaN NaN
G NaN NaN NaN
H NaN NaN NaN
I NaN NaN NaN
我目前正在將其作為兩步問題來處理。 第 1 步是刪除同一行中的重復數字。 第 2 步是刪除跨不同行和不同列的重復數字。 我已經找到了第 1 步,使用df.loc
命令:
df.loc[df['home'] == df['work'], ['work']] = np.nan
df.loc[df['home'] == df['mobile'], ['mobile']] = np.nan
df.loc[df['work'] == df['mobile'], ['mobile']] = np.nan
這是運行上述命令后我的數據框的樣子:
acct_no home work mobile
A 1111111111 NaN NaN
B 2222222222 NaN NaN
C 3333333333 NaN NaN
D 4444444444 5555555555 NaN
E 6666666666 7777777777 8888888888
F 9999999999 NaN 8888888888
G 7777777777 6666666666 5555555555
H 4444444444 3333333333 2222222222
I NaN NaN NaN
但是,我無法繞過第 2 步。作為一種蠻力方法,我發現我可以對 home 上的數據幀進行排序,然后遍歷每一行,檢查前一行的 home 值是否與當前行相同行的,如果當前行的值相同,則將其設置為 nan。 最后,我將不得不為工作密鑰和移動密鑰重復該過程。 這是檢查主場的代碼的樣子:
df.sort_values(by='home', inplace=True)
prev_row = {'home':None,'work':None,'mobile':None}
for cur_idx,cur_row in df.iterrows():
if prev_row['home'] == cur_row['home']:
cur_row['home'] = np.nan
prev_row = cur_row
在運行上面的代碼只是為了更新和檢查主頁列之后,我的數據框將如下所示:
acct_no home work mobile
A 1111111111 NaN NaN
B 2222222222 NaN NaN
C 3333333333 NaN NaN
D 4444444444 5555555555 NaN
E NaN 3333333333 2222222222
F 6666666666 7777777777 8888888888
G 7777777777 6666666666 5555555555
H 9999999999 NaN 8888888888
I NaN NaN NaN
這個解決方案非常笨拙,對於較大的數據集效率不高,那么我怎樣才能以更有效的方式實現這一目標呢?
非常感謝任何幫助 - 在此先感謝您!
這可能會解決您第 2 步的需求。 如果沒有,請隨意采用另一種方法。
df = pd.DataFrame(
[
dict(acct_no="D", home="4444444444", work="5555555555"),
dict(acct_no="E", home=np.NaN, work="3333333333", mobile="2222222222"),
dict(acct_no="J", home=np.NaN, work=np.NaN, mobile="8888888888"),
dict(acct_no="K", home=np.NaN, work="8888888888"),
dict(acct_no="L", home=np.NaN, work=np.NaN, mobile="8888888888"),
]
)
df["phone"] = (df.home
.combine_first(df.work)
.combine_first(df.mobile))
df = (df.sort_values(by="phone")
.drop_duplicates(subset="phone")
.set_index("acct_no"))
print(df)
輸出
home work mobile phone
acct_no
E NaN 3333333333 2222222222 3333333333
D 4444444444 5555555555 NaN 4444444444
J NaN NaN 8888888888 8888888888
在此實現中,我們只查看phone
列,這是帳戶的首選號碼。 這可能比期望的更嚴厲一些。 例如,請注意帳戶“K”和“L”在與“J”共享電話號碼的基礎上完全被刪除。 如果多個客戶共享一條家庭固定電話,那可能不是所需的業務邏輯。 另請注意,如果“K”要添加家庭號碼 7878787878,他將存活下來,盡管 8888888888 dup。 如果移動比家庭“更獨特”,也許我們應該更喜歡那個數字。
現在我們已經充分利用了phone
列,可以隨意使用 .drop() 了。
排序成本為 O(N log N),其他一切都是線性的,因此這應該是一個高性能的解決方案,即使對於大型數據集也是如此。
在我看來,最簡單的方法是將數字stack
為 Series、 mask
或drop_duplicates
,然后恢復原始形狀:
out = (df.set_index('acct_id').stack()
# the magic happens here
.mask(lambda d: d.duplicated())
# restore original format
.unstack().reset_index()
)
選擇:
out = (df.set_index('acct_id')
.stack().drop_duplicates().unstack()
.reindex(df['acct_id']).reset_index().reindex(columns=df.columns)
)
輸出:
acct_id home work mobile
0 A 1111111111 NaN NaN
1 B 2222222222 NaN NaN
2 C 3333333333 NaN NaN
3 D 4444444444 5555555555 NaN
4 E 6666666666 7777777777 8888888888
5 F 9999999999 NaN NaN
6 G NaN NaN NaN
7 H NaN NaN NaN
8 I NaN NaN NaN
如果你願意,你可以輕松地調整上面的內容,以在選擇要保留的重復項的方式中給出列優先的偏好:
out = (df.set_index('acct_id').unstack()
.mask(lambda d: d.duplicated())
.swaplevel().unstack().reset_index() # or: .unstack().T.reset_index()
)
輸出:
acct_id home work mobile
0 A 1111111111 NaN NaN
1 B 2222222222 NaN NaN
2 C 3333333333 NaN NaN
3 D 4444444444 5555555555 NaN
4 E 6666666666 NaN 8888888888
5 F 9999999999 NaN NaN
6 G 7777777777 NaN NaN
7 H NaN NaN NaN
8 I NaN NaN NaN
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.