팬더는 다른 데이터 프레임에없는 행을 얻습니다.


229

공통으로 일부 행이있는 두 개의 팬더 데이터 프레임이 있습니다.

dataframe2가 dataframe1의 서브 세트라고 가정하십시오.

dataframe2에없는 dataframe1의 행을 어떻게 얻을 수 있습니까?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})

1
@TedPetrou 나는 당신이 제공 한 답변이 어떻게 올바른지 보지 못했습니다. 하나가 다른 하나의 서브 세트 인 두 개의 데이터 프레임이있는 경우 서브 세트에있는 모든 행을 제거해야합니다. 중복을 제거하고 싶지 않습니다. 부분 집합을 완전히 제거하고 싶습니다.
주크 박스

답변:


172

하나의 방법은 내부 병합 양식의 결과를 두 df로 저장하는 것입니다. 그런 다음 하나의 열 값이이 공통 값이 아닌 경우 간단히 행을 선택할 수 있습니다.

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

편집하다

당신이 찾은 또 다른 방법은 사용할 수 isin있는 NaN행을 생성하는 것입니다 .

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

그러나 df2가 같은 방식으로 행을 시작하지 않으면 작동하지 않습니다.

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

전체 df를 생성합니다.

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

13
df1[~df1.isin(df2)].dropna(how = 'all')트릭을 수행하는 것 같습니다. 어쨌든 고마워-당신의 대답은 해결책을 찾는 데 도움이되었습니다.
좋은 것을 생각하십시오

5
를 사용 isin하려면 두 df가 모두 같은 행 값으로 시작해야합니다. 예를 들어 df2 인 경우 분석법이 df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11,12, 13]})작동하지 않습니다.
EdChum

2
이것은 모든 정수를 수레로 변환했습니다!
Chris Nielsen

3
@ SergeyZakharov 3 년 전에 게시 된이 답변은 OP에 관한 한 정확하고 문제는 다른 답변은 더 나은 답변이며 원래 질문에 포함되지 않은 더 넓은 문제를 처리합니다. 답변이 잘못되었습니다. 문제가 제시된대로 정확합니다. 또한 누군가가 설명없이이을 downvoted있다, 이것이 허용 대답으로 작은 내가 할 수있다, 영업 이익은 자신의 마음을 변경되지 않았습니다 나는 그것을 만들기 위해 다른 답변을 잠식하지 않을거야 못했습니다 .
EdChum

1
@Cecilia 전달해야합니다 keep=False: df0.append(df1).drop_duplicates(keep=False), 기본적으로 첫 번째 복제본을 유지하고 모든 복제본을 삭제하려고합니다.
EdChum

189

현재 선택된 솔루션이 잘못된 결과를 생성합니다. 제대로이 문제를 해결하기 위해, 우리는이에서 왼쪽 조인을 수행 할 수 있습니다 df1df2처음만을위한 고유 행을 얻을 수 있는지에있어 df2.

먼저, 데이터가있는 행을 추가하기 위해 원본 DataFrame을 수정해야합니다 [3, 10].

df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 
                           'col2' : [10, 11, 12, 13, 14, 10]}) 
df2 = pd.DataFrame(data = {'col1' : [1, 2, 3],
                           'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
5     3    10

df2

   col1  col2
0     1    10
1     2    11
2     3    12

왼쪽 조인을 수행하여 df2각 행이 df1정확히 1 행의 조인 되도록 중복을 제거하십시오 df2. 매개 변수 indicator를 사용하여 행이 어느 테이블에 있는지를 나타내는 추가 열을 리턴 하십시오 .

df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], 
                   how='left', indicator=True)
df_all

   col1  col2     _merge
0     1    10       both
1     2    11       both
2     3    12       both
3     4    13  left_only
4     5    14  left_only
5     3    10  left_only

부울 조건을 만듭니다.

df_all['_merge'] == 'left_only'

0    False
1    False
2    False
3     True
4     True
5     True
Name: _merge, dtype: bool

다른 솔루션이 잘못된 이유

일부 솔루션은 동일한 실수를합니다. 각 값이 동일한 행이 아니라 각 열에 독립적으로 있는지 확인합니다. 고유하지만 두 열의 값이있는 마지막 행을 추가하면 df2실수 가 노출됩니다.

common = df1.merge(df2,on=['col1','col2'])
(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))
0    False
1    False
2    False
3     True
4     True
5    False
dtype: bool

이 솔루션은 동일한 잘못된 결과를 얻습니다.

df1.isin(df2.to_dict('l')).all(1)

2
그러나, 그들은 col1이 인덱스 인 것으로 가정하고 있다고 생각합니다 (질문에는 언급되지 않았지만 명백합니다). 따라서 동일한 col1 값에 대해 두 개의 col2 값이있는 경우가 없다면 (두 col1 = 3 행은있을 수 없음) 위의 대답은 정확합니다.
pashute

14
분명히 분명하지 않으므로 요점이 잘못되었습니다. 내 솔루션은 더 많은 경우를 일반화합니다.
Ted Petrou

질문 : 부울 배열 대신 슬라이스를 만드는 것이 쉽지 않습니까? 목표는 행을 얻는 것입니다.
Matías Romo

5
사용 df_all[df_all['_merge'] == 'left_only']결과에 안양 가지고
gies0r

77

인덱스가 데이터 프레임에서 일관성이 있다고 가정하면 (실제 col 값을 고려하지 않음) :

df1[~df1.index.isin(df2.index)]

1
조건의 @ChrisNielsen 부정. 따라서이 예 df1에서 df2.index" 인덱스가없는 행을 가져옵니다"를 의미 합니다. 부정에 대한 자세한 내용 : stackoverflow.com/q/19960077/304209 (놀랍게도 팬더 문서에서 물결표에 대한 언급을 찾을 수 없었습니다).
Dennis Golomazov 2018 년

df가 같은 길이 여야합니까? 나는 점점ValueError: Item wrong length x instead of y.
단어 14:17

@wordsfortheno 아니, 그들은하지 않습니다. 마스크의 길이는 df1이며 df1에도 적용됩니다. 예를 들어 줄 수 있습니까?
Dennis Golomazov

항목 길이 문제를 해결하려면 .loc
Moreno

13

이미 암시 한 것처럼 isin은 일치하는 열과 인덱스가 동일해야합니다. match가 행 내용에만 있어야하는 경우 행을 필터링하기위한 마스크를 얻는 한 가지 방법은 행을 (Multi) Index로 변환하는 것입니다.

In [77]: df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {'col1' : [1, 3, 4], 'col2' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
   col1  col2
1     2    11
4     5    14
5     3    10

인덱스를 고려해야하는 경우 set_index에는 키워드 인수가 추가되어 기존 인덱스에 열을 추가합니다. 열이 정렬되지 않으면 list (df.columns)를 열 사양으로 바꾸어 데이터를 정렬 할 수 있습니다.

pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())

대안으로 인덱스를 만드는 데 사용될 수는 있지만 이것이 더 효율적이라고는 생각하지 않습니다.


@ Dev_123 처음에 ~를 제거하십시오. 핵심은 df1의 행이 df2에서도 발생하는지 여부에 대한 술어 목록을 작성하는 것이므로 df1의 행은 df1에 고유하지 않습니다. ~ df1의 행이 df2에서 발생하지 않는지 여부에 대한 술어 목록으로 무시합니다.
룬 Lyngsoe

11

여러 필드 (column_names)가있는 df_1 및 df_2 데이터 프레임이 있고 df_2에서 일부 필드 (예 : fields_x, fields_y)를 기준으로 df_2에없는 항목 만 찾으려고한다면 다음 단계를 따르십시오.

1 단계. 열 키 1과 키 2를 각각 df_1과 df_2에 추가합니다.

2 단계. 아래와 같이 데이터 프레임을 병합합니다. field_x 및 field_y는 원하는 열입니다.

df_1에서 key1이 key2와 같지 않은 행만 선택하십시오.

4 단계. 키 1과 키 2를 삭제합니다.

이 방법은 문제를 해결하고 빅 데이터 세트에서도 빠르게 작동합니다. 1,000,000 개가 넘는 행이있는 데이터 프레임에 대해 시도했습니다.

df_1['key1'] = 1
df_2['key2'] = 1
df_1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'left')
df_1 = df_1[~(df_1.key2 == df_1.key1)]
df_1 = df_1.drop(['key1','key2'], axis=1)

나는 이것이 기술적으로 그가 원하는 것이라고 생각하지 않습니다. 그는 어떤 행이 어떤 df에 고유했는지 알고 싶어합니다. 그러나이 솔루션은 첫 번째 df 또는 두 번째 df에 고유 한 df 행을 반환한다고 생각합니다.
합법적 스택


3

isin (dict) 메소드를 사용하여 수행 할 수 있습니다 .

In [74]: df1[~df1.isin(df2.to_dict('l')).all(1)]
Out[74]:
   col1  col2
3     4    13
4     5    14

설명:

In [75]: df2.to_dict('l')
Out[75]: {'col1': [1, 2, 3], 'col2': [10, 11, 12]}

In [76]: df1.isin(df2.to_dict('l'))
Out[76]:
    col1   col2
0   True   True
1   True   True
2   True   True
3  False  False
4  False  False

In [77]: df1.isin(df2.to_dict('l')).all(1)
Out[77]:
0     True
1     True
2     True
3    False
4    False
dtype: bool

잘못된 결과가 발생합니다. 아래 내 설명을 참조하십시오.
테드 페트로 우

2

또한 CONCAT 수 df1, df2:

x = pd.concat([df1, df2])

그런 다음 모든 중복 항목을 제거하십시오.

y = x.drop_duplicates(keep=False, inplace=False)

StackOverflow에 오신 것을 환영합니다. 코드, XML 또는 데이터 샘플을 게시하는 경우 텍스트 편집기에서 해당 행을 강조 표시하고 편집기 도구 모음에서 "코드 샘플"버튼 ({})을 클릭하거나 키보드에서 Ctrl + K를 사용하여 형식을 지정하십시오. 그리고 구문 강조!
WhatsThePoint

4
df1에만있는 데이터뿐만 아니라 두 세트에있는 모든 데이터를 반환합니다.
Jamie Marshall

1

이건 어때요:

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 
                               'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 
                               'col2' : [10, 11, 12]})
records_df2 = set([tuple(row) for row in df2.values])
in_df2_mask = np.array([tuple(row) in records_df2 for row in df1.values])
result = df1[~in_df2_mask]

1

이것을 해결하는 또 다른 방법은 다음과 같습니다.

df1[~df1.index.isin(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

또는:

df1.loc[df1.index.difference(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

0

이 작업을 수행하는 방법에는 하나의 데이터 프레임에 고유 한 새 열을 추가하고이를 사용하여 항목을 유지할지 여부를 선택하는 것이 포함됩니다

df2[col3] = 1
df1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'outer')
df1['Empt'].fillna(0, inplace=True)

이렇게하면 df1의 모든 항목에 코드가 있습니다-df1에 고유하면 0, 두 dataFrames에 있으면 1입니다. 그런 다음 이것을 사용하여 원하는 것으로 제한하십시오.

answer = nonuni[nonuni['Empt'] == 0]

0
merge 함수를 사용하여 다른 행을 추출하십시오.
df = df.merge(same.drop_duplicates(), on=['col1','col2'], 
               how='left', indicator=True)
이기종 행을 CSV로 저장
df[df['_merge'] == 'left_only'].to_csv('output.csv')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.