두 개의 데이터 프레임 df1과 df2가 있는데, 여기서 df2는 df1의 하위 집합입니다. 두 데이터 프레임의 차이 인 새 데이터 프레임 (df3)을 어떻게 얻습니까?
즉, df2에없는 df1의 모든 행 / 열이있는 데이터 프레임?
답변:
사용하여 drop_duplicates
pd.concat([df1,df2]).drop_duplicates(keep=False)
Update :
Above method only working for those dataframes they do not have duplicate itself, For example
df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
df2=pd.DataFrame({'A':[1],'B':[2]})
아래와 같이 출력됩니다.
잘못된 출력 :
pd.concat([df1, df2]).drop_duplicates(keep=False)
Out[655]:
A B
1 2 3
올바른 출력
Out[656]:
A B
1 2 3
2 3 4
3 3 4
그것을 달성하는 방법?
방법 1 : isin
함께 사용tuple
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
Out[657]:
A B
1 2 3
2 3 4
3 3 4
방법 2 : merge
와indicator
df1.merge(df2,indicator = True, how='left').loc[lambda x : x['_merge']!='both']
Out[421]:
A B _merge
1 2 3 left_only
2 3 4 left_only
3 3 4 left_only
pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
float
(때문에 12.00000000001 != 12
) 인 경우 결과에 예기치 않은 행이 남아있을 수 있습니다 . 더 나은 방법은 두 데이터 프레임에서 설정된 ID의 교차점을 찾아 그에 따라 차이를 얻는 것입니다.
indicator=True
)는 매우 다재다능하고 유용한 도구 이므로이 답변의 상단에서보고 싶지만 '왼쪽'이 아닌 '외부'로 3 가지 상황을 모두 포함합니다.
행의 경우 다음을 시도하십시오 Name
. 결합 인덱스 열은 어디 입니까? (여러 공통 열에 대한 목록이거나 left_on
및 지정 가능 right_on
) :
m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)
이 indicator=True
설정은 "left_only", "right_only"또는 "both"의 3 가지 종류로 분류 된 및 _merge
사이의 모든 변경 사항이있는 이라는 열을 추가하므로 유용합니다 .df1
df2
열의 경우 다음을 시도하십시오.
set(df1.columns).symmetric_difference(df2.columns)
merge
with indicator=True
는 주어진 필드로 데이터 프레임을 비교하는 고전적인 솔루션입니다.
허용 된 답변 방법 1은 NaN이 내부에있는 데이터 프레임에 대해 작동하지 않습니다 pd.np.nan != pd.np.nan
. 이것이 최선의 방법인지 확실하지 않지만 다음 방법으로 피할 수 있습니다.
df1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]
edit2, 인덱스 설정없이 새로운 솔루션을 찾았습니다.
newdf=pd.concat([df1,df2]).drop_duplicates(keep=False)
좋아, 나는 가장 높은 투표의 대답에 이미 내가 알아 낸 것을 포함하고 있음을 발견했다. 예, 두 개의 df에 중복이없는 경우에만이 코드를 사용할 수 있습니다.
까다로운 방법이 있습니다. 먼저 질문에서 주어진 두 데이터 프레임의 인덱스로 '이름'을 설정합니다. 두 개의 df에 동일한 'Name'이 있으므로 'bigger'df에서 'smaller'df의 인덱스를 삭제할 수 있습니다. 다음은 코드입니다.
df1.set_index('Name',inplace=True)
df2.set_index('Name',inplace=True)
newdf=df1.drop(df2.index)
import pandas as pd
# given
df1 = pd.DataFrame({'Name':['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa',],
'Age':[23,45,12,34,27,44,28,39,40]})
df2 = pd.DataFrame({'Name':['John','Smith','Wale','Tom','Menda','Yuswa',],
'Age':[23,12,34,44,28,40]})
# find elements in df1 that are not in df2
df_1notin2 = df1[~(df1['Name'].isin(df2['Name']) & df1['Age'].isin(df2['Age']))].reset_index(drop=True)
# output:
print('df1\n', df1)
print('df2\n', df2)
print('df_1notin2\n', df_1notin2)
# df1
# Age Name
# 0 23 John
# 1 45 Mike
# 2 12 Smith
# 3 34 Wale
# 4 27 Marry
# 5 44 Tom
# 6 28 Menda
# 7 39 Bolt
# 8 40 Yuswa
# df2
# Age Name
# 0 23 John
# 1 12 Smith
# 2 34 Wale
# 3 44 Tom
# 4 28 Menda
# 5 40 Yuswa
# df_1notin2
# Age Name
# 0 45 Mike
# 1 27 Marry
# 2 39 Bolt
아마도 동일하거나 다른 열 이름을 가진 더 간단한 한 줄짜리 일 것입니다. df2 [ 'Name2']에 중복 값이 포함 된 경우에도 작동했습니다.
newDf = df1.set_index('Name1')
.drop(df2['Name2'], errors='ignore')
.reset_index(drop=False)
여기 에서 언급했듯이
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
올바른 솔루션이지만 다음과 같은 경우 잘못된 출력을 생성합니다.
df1=pd.DataFrame({'A':[1],'B':[2]})
df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
이 경우 위의 솔루션은 Empty DataFrame 을 제공
하지만 대신 사용해야합니다.concat
각 datframe에서 중복을 제거한 후 메서드 .
사용하다 concate with drop_duplicates
df1=df1.drop_duplicates(keep="first")
df2=df2.drop_duplicates(keep="first")
pd.concat([df1,df2]).drop_duplicates(keep=False)
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
경우에도 정답입니다. df1 또는 df2에 있지만 둘 다가 아닌 값을 얻으려는 경우 제안 된 접근 방식이 정확합니다 (원래 데이터 프레임에서 중복 제거에 대한주의 사항 포함).
기존 데이터 프레임의 인덱스를 변경할 필요가없는 멋진 @liangli 솔루션의 약간 변형 :
newdf = df1.drop(df1.join(df2.set_index('Name').index))
인덱스로 차이 찾기. df1이 df2의 하위 집합이고 하위 집합시 인덱스가 이월된다고 가정합니다.
df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
# Example
df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5])
df2 = df1.loc[[1,3,5]]
df1
gender subject
1 f bio
2 m chem
3 f phy
4 m bio
5 f bio
df2
gender subject
1 f bio
3 f phy
5 f bio
df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
df3
gender subject
2 m chem
4 m bio
받아 들여진 답변 외에도 / ( 두 데이터 프레임에 대해 일치하지 않을 수 있음)를 사용하여 두 데이터 프레임 의 2D 세트 차이 를 찾을 수있는 더 넓은 솔루션을 제안하고 싶습니다 . 또한 방법은 데이터 프레임 비교를 위해 요소에 대한 허용 오차를 설정할 수 있습니다 (사용 )index
columns
float
np.isclose
import numpy as np
import pandas as pd
def get_dataframe_setdiff2d(df_new: pd.DataFrame,
df_old: pd.DataFrame,
rtol=1e-03, atol=1e-05) -> pd.DataFrame:
"""Returns set difference of two pandas DataFrames"""
union_index = np.union1d(df_new.index, df_old.index)
union_columns = np.union1d(df_new.columns, df_old.columns)
new = df_new.reindex(index=union_index, columns=union_columns)
old = df_old.reindex(index=union_index, columns=union_columns)
mask_diff = ~np.isclose(new, old, rtol, atol)
df_bool = pd.DataFrame(mask_diff, union_index, union_columns)
df_diff = pd.concat([new[df_bool].stack(),
old[df_bool].stack()], axis=1)
df_diff.columns = ["New", "Old"]
return df_diff
예:
In [1]
df1 = pd.DataFrame({'A':[2,1,2],'C':[2,1,2]})
df2 = pd.DataFrame({'A':[1,1],'B':[1,1]})
print("df1:\n", df1, "\n")
print("df2:\n", df2, "\n")
diff = get_dataframe_setdiff2d(df1, df2)
print("diff:\n", diff, "\n")
Out [1]
df1:
A C
0 2 2
1 1 1
2 2 2
df2:
A B
0 1 1
1 1 1
diff:
New Old
0 A 2.0 1.0
B NaN 1.0
C 2.0 NaN
1 B NaN 1.0
C 1.0 NaN
2 A 2.0 NaN
C 2.0 NaN