我在這里問了一個非常相似的問題,但想知道如果必須依賴多個列來執行附加,是否有辦法解決這個問題。所以資料框如下所示,
import pandas as pd
d1 ={'col1': ['I ate dinner','I ate dinner', 'the play was inetresting','the play was inetresting'],
'col2': ['I ate dinner','I went to school', 'the play was inetresting for her','the gold is shining'],
'col3': ['I went out','I did not stay at home', 'the play was inetresting for her','the house is nice'],
'col4': ['min', 'max', 'mid','min'],
'col5': ['min', 'max', 'max','max']}
d2 ={'col1': ['I ate dinner',' the glass is shattered', 'the play was inetresting'],
'col2': ['I ate dinner',' the weather is nice', 'the gold is shining'],
'col3': ['I went out',' the house was amazing', 'the house is nice'],
'col4': ['min', 'max', 'max'],
'col5': ['max', 'min', 'mid']}
df1 = pd.DataFrame(d1)
df2 = pd.DataFrame(d2)
所以這一次,我想將 df2 中的行附加到 df1 中的相似行下,前提是所有 col1、col2、col3 中的行都相似。所以輸出是,
col1 col2 col3 col4 col5
0 I ate dinner I ate dinner I went out min min
1 I ate dinner I ate dinner I went out min max
2 the play was inetresting the gold is shining the house is nice min max
3 the play was inetresting the gold is shining the house is nice max mid
所以我嘗試了以下方法,
df = pd.concat(df1[df1.set_index(['col1','col2','col3']).index.isin(df2.set_index(['col1','col2','col3']).index)]).sort_values(df1.set_index(['col1','col2','col3']).index, ignore_index=True)
但我得到這個錯誤,
TypeError: first argument must be an iterable of pandas objects, you passed an object of type "DataFrame"
uj5u.com熱心網友回復:
另一種解決方案是使用pd.mergeand pd.wide_to_long:
out = (
pd.wide_to_long(
pd.merge(df1, df2, how='inner', on=['col1', 'col2', 'col3']).reset_index(),
stubnames=['col4', 'col5'], i='index', j='val', sep='_', suffix=r'[xy]')
.sort_index().reset_index(drop=True)[df1.columns]
)
輸出:
>>> out
col1 col2 col3 col4 col5
0 I ate dinner I ate dinner I went out min min
1 I ate dinner I ate dinner I went out min max
2 the play was inetresting the gold is shining the house is nice min max
3 the play was inetresting the gold is shining the house is nice max mid
一步步
# Step 1: merge
>>> out = pd.merge(df1, df2, how='inner', on=['col1', 'col2', 'col3']).reset_index()
index col1 col2 col3 col4_x col5_x col4_y col5_y
0 0 I ate dinner I ate dinner I went out min min min max
1 1 the play was inetresting the gold is shining the house is nice min max max mid
# Step 2: wide_to_long
>>> out = pd.wide_to_long(out, stubnames=['col4', 'col5'], i='index', j='val', sep='_', suffix=r'[xy]')
col3 col2 col1 col4 col5
index val
0 x I went out I ate dinner I ate dinner min min
1 x the house is nice the gold is shining the play was inetresting min max
0 y I went out I ate dinner I ate dinner min max
1 y the house is nice the gold is shining the play was inetresting max mid
# Step 3: reorder dataframe
>>> out = out.sort_index().reset_index(drop=True)[df1.columns]
col1 col2 col3 col4 col5
0 I ate dinner I ate dinner I went out min min
1 I ate dinner I ate dinner I went out min max
2 the play was inetresting the gold is shining the house is nice min max
3 the play was inetresting the gold is shining the house is nice max mid
uj5u.com熱心網友回復:
好的,我意識到自己的錯誤,并會在此處發布答案,以防任何人感興趣,(答案基于問題中的鏈接)
print(pd.concat([df1, df2[df2.set_index(['col1','col2','col3']).index.isin(df1.set_index(['col1','col2','col3']).index)]]).sort_values(['col1','col2','col3'], ignore_index=True))
uj5u.com熱心網友回復:
我強烈建議您提出數字最小示例,而不是基于文本的示例。更容易閱讀,更容易理解。話雖如此,如果我理解正確,您希望 df1 的每一行:
- 檢查是否有來自 df2 的某些行在某些列上具有相同的值。
- 將這些行附加到 df1,就在所述行的后面。
當然,我們可以討論 df1 中重復的情況,以及您希望如何處理它們。然后,我們可以撰寫兩種解決方案,一種使用 for 回圈,另一種使用 Pandas 的函式式編程(取決于您的技能、習慣和其他偏好)。
一種 for 回圈方法
假設 df1 中沒有重復項,則:
df1 = pd.DataFrame(d1)
df2 = pd.DataFrame(d2)
cols = ["col1", "col2", "col3"]
## create a new dataframe
new_df = pd.DataFrame()
## loop over all rows of df1
for _, row1 in df1.iterrows():
## check for equality with df2, we need all elements cols being equal to select these rows
is_eq_to_row_1 = df2.eq(row1.loc[cols]).loc[:, cols].all(axis=1)
## if at least one row of df2 is equal to row, append them
if is_eq_to_row_1.any():
## first append the row1
new_df = new_df.append(row1)
## then all rows of df2 equal to row1
new_df = new_df.append(df2[is_eq_to_row_1])
功能性方法
我還沒有時間寫一個合適的解決方案,但我猜它暗示了 groupby、apply 和一堆與 Pandas 相關的函式。對于每一行 x,我們仍然習慣于df2[df2.eq(x.loc[cols]).loc[:, cols].all(axis=1)]選擇 df2 的等于 x 的行。
我們只是在所有行上“回圈”。設計的工具可以是 groupby。然后我們不再關心重復。
new_df = df1.groupby(cols). \
apply(lambda x : pd.concat([x,
df2[df2.eq(x.iloc[0, :].loc[cols]). \
loc[:, cols].all(axis=1)]]))
There are still some work to do to not append rows if no df2's row was found, and to clean up the output.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/444923.html
