我有以下資料框:
d = {'col1': [1, "Avoid", 3, "Avoid"], 'col2': ["AA", "BB", "Avoid", "Avoid"]}
df = pd.DataFrame(data=d)
df
col1 col2
0 1 AA
1 Avoid BB
2 3 Avoid
3 Avoid Avoid
我必須有條件地將col1和col2連接到col3中。條件:
- 只有 concat 2 列,只要它們都不是Avoid。
- 如果col1和col2中的任何一個為 Avoid,則col3也將等于Avoid。
- 執行連接時,需要在col3的列值之間添加“&”。例如,col3的第一行將是"1 & AA"。
最終結果應該如下所示:
col1 col2 col3
0 1 AA 1 & AA
1 Avoid BB Avoid
2 3 Avoid Avoid
3 Avoid Avoid Avoid
在不處理 for 回圈的情況下如何做到這一點?
uj5u.com熱心網友回復:
在普通 python 中對字串運行串列推導:
out = [f"{l}&{r}"
if 'Avoid' not in {l, r}
else 'Avoid'
for l, r in zip(df.col1, df.col2)]
df.assign(col3 = out)
col1 col2 col3
0 1 AA 1&AA
1 Avoid BB Avoid
2 3 Avoid Avoid
3 Avoid Avoid Avoid
uj5u.com熱心網友回復:
不是使用 pandas 的有效方法,但如果您無法更改資料結構,這些是解決方案:
解決方案1:
def custom_merge(cols):
if cols["col1"]=="Avoid" or cols["col2"]=="Avoid":
return "Avoid"
else:
return f"{cols['col1']} & {cols['col2']}"
df['col3'] = df.apply(custom_merge, axis=1)
解決方案2:
df['col3'] = (df["col1"].astype(str) " & " df["col2"].astype(str)).apply(lambda x: "Avoid" if 'Avoid' in x else x)
兩種解決方案都會導致以下結果:
col1 col2 col3
0 1 AA 1 & AA
1 Avoid BB Avoid
2 3 Avoid Avoid
3 Avoid Avoid Avoid
執行時間比較
在本節中,我將計算提出的解決方案的執行時間。@mozway 在他的回答中提出了 2 個非常棘手的解決方案,我將其稱為解決方案 3a 和解決方案 3b。另一個有趣的解決方案是@sammywemmy 的解決方案,它使用串列推導,然后將串列添加到資料框中,我將此解決方案稱為解決方案 4
實驗實體將具有以下結構:
import pandas as pd
n = 100000
d = {'col1': [1, "Avoid", 3, "Avoid"] * n, 'col2': ["AA", "BB", "Avoid", "Avoid"] * n}
df = pd.DataFrame(data=d)
執行時間處理時間:
解決方案1:
%timeit 3.56 s ± 71.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
解決方案2:
%timeit 140 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
解決方案 3a:
%timeit 3.44 s ± 77.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
解決方案 3b:
%timeit 893 ms ± 13.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
解決方案4:
%timeit 191 ms ± 5.71 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
解決方案 1 和解決方案 3a 在所考慮的實體上具有相似的執行時間。解決方案 3b 的運行速度比解決方案 1 和 3a 快 4 倍。最快的解決方案是解決方案 2,它比解決方案 2 快約 7 倍,比解決方案 1 和 3a 快約 25 倍。這是因為解決方案 2 利用了pandas vectorization。解決方案 4 具有與解決方案 2 類似的運行時間,利用串列理解來進行合并操作(不使用 pandas)。
提示:如果您可以更改資料格式,建議對資料進行格式化,以便您可以使用原生 pandas 函式進行連接操作,或者如果您無法更改資料格式并且可以不使用 pandas,您可能會有使用字典或串列稍微加快解決方案 2,使用串列理解進行合并操作。
uj5u.com熱心網友回復:
嘗試這個:
df["col3"]=df.apply(lambda x:"Avoid" if x["col1"]=="Avoid" or x["col2"]=="Avoid" else f"{x['col1']} & {x['col2']}",axis=1)
uj5u.com熱心網友回復:
df["col3"] = df["col1"] " & " df["col2"]
df["col3"] = df["col3"].apply(lambda x: "Avoid" if x.contains("Avoid") else x)
uj5u.com熱心網友回復:
使用布爾運算,這使您可以使用任意數量的列:
# is any value in the row "Avoid"?
m = df.eq('Avoid').any(1)
# concatenate all columns unless there was a "Avoid"
df['col3'] = df.astype(str).agg(' & '.join, axis=1).mask(m, 'Avoid')
如果您有很多行而使用“避免”的行數很少,那么替代方案應該會更快:
m = df.ne('Avoid').all(1)
df.loc[m, 'col3'] = df[m].astype(str).agg(' & '.join, axis=1)
df['col3'] = df['col3'].fillna('Avoid')
輸出:
col1 col2 col3
0 1 AA 1 & AA
1 Avoid BB Avoid
2 3 Avoid Avoid
3 Avoid Avoid Avoid
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/507960.html
標籤:Python python-3.x 熊猫 数据框