pandalar diğer veri çerçevesinde OLMAYAN satırlar alır


230

Bazı ortak satırları olan iki panda veri çerçevesi var.

Diyelim ki dataframe2, dataframe1'in bir alt kümesidir.

Dataframe2'de olmayan dataframe1 satırlarını nasıl edinebilirim?

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 Verdiğiniz cevabın nasıl doğru olduğunu göremiyorum. Biri diğerinin alt kümesi olan iki veri çerçevem ​​varsa, alt kümedeki tüm bu satırları kaldırmam gerekir. Kopyaları kaldırmak istemiyorum. Altkümeyi tamamen kaldırmak istiyorum.
müzik kutusu

Yanıtlar:


172

Bir yöntem, her iki dfs'de bir iç birleştirme formunun sonucunu saklamak olacaktır, o zaman bir sütunun değerleri bu ortak olmadığında satırları seçebiliriz:

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

DÜZENLE

Bulduğunuz başka bir yöntem , bırakabileceğiniz satırlar isinüretecek kullanmaktır NaN:

In [138]:

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

Ancak df2 satırları aynı şekilde başlatmazsa, bu çalışmaz:

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

tüm df üretecek:

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')hile yapıyor gibi görünüyor. Yine de teşekkürler - cevabınız bir çözüm bulmama yardımcı oldu.
güzel şeyler düşün

5
Kullanmanın isinher iki dfs'nin de aynı satır değerleriyle başlatılmasını gerektirdiğini unutmayın; örneğin df2 ise df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11,12, 13]}), yönteminiz çalışmaz
EdChum

2
Bu tüm ints yüzer dönüştürdü!
Chris Nielsen

3
@SergeyZakharov, yaklaşık 3 yıl önce yayınlanan bu cevap, OP ile ilgili olarak doğruydu ve problemleri için, diğer cevap daha iyi bir cevap ve orijinal sorunun bir parçası olmayan daha geniş bir sorunu ele alıyor, bunun yanlış olduğunu belirtmek yanlış cevap yanlış, ortaya çıktığında sorun göz önüne alındığında doğrudur. Buna ek olarak, birisi açıklama yapmadan bunu reddetti, bu kabul edilebilir bir cevap olduğu için yapabileceğim çok az şey var, OP fikrini değiştirmedi ve doğru yapmak için başka bir cevabı yamyamıyorum .
EdChum

1
@Cecilia geçmek gerekir keep=False: df0.append(df1).drop_duplicates(keep=False)tüm çiftleri bırakmanı istiyorum, ilk yinelenen tutan varsayılan olarak,
EdChum

190

Şu anda seçili çözüm yanlış sonuçlar veriyor. Bu sorunu doğru bir şekilde çözmek df1için df2, önce sadece benzersiz satırları aldığınızdan emin olarak soldan birleştirme gerçekleştirebiliriz df2.

İlk olarak, veri içeren satırı eklemek için orijinal DataFrame'i değiştirmemiz gerekir [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

Sola birleştirme işlemini gerçekleştirin, yinelenenleri ortadan kaldırarak df2her bir satırın df1tam olarak 1 satır ile birleşmesini sağlayın df2. Parametreyi indicator, satırın hangi tablodan geldiğini gösteren ek bir sütun döndürmek için kullanın .

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

Bir boolean koşulu oluşturun:

df_all['_merge'] == 'left_only'

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

Diğer çözümler neden yanlış

Birkaç çözüm aynı hatayı yapar - sadece her bir değerin aynı satırda değil, her sütunda bağımsız olarak olup olmadığını kontrol ederler. Benzersiz ancak her iki sütundaki değerleri içeren son satırı eklemek df2hatayı ortaya çıkarır:

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

Bu çözüm aynı yanlış sonucu alır:

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

2
ancak, sanırım, col1'in bir indeks olarak benzersiz olduğunu varsayıyorlardı (soruda belirtilmemiş, ancak açıktır). Bu nedenle, aynı col1 değeri için iki col2 değerinin (böyle iki col1 = 3 satır olamaz) olduğu böyle bir durum yoksa, yukarıdaki cevaplar doğrudur.
pashute

14
Kesinlikle belli değil, bu yüzden amacınız geçersiz. Benim çözümüm daha fazla vakaya genelleme yapıyor.
Ted Petrou

Soru, boole dizisi yerine dilim oluşturmak daha kolay olmaz mıydı? Amaç satırları elde etmektir.
Matías Romo

5
df_all[df_all['_merge'] == 'left_only']Sonuçları ile bir df elde etmek için kullanın
gies0r

77

Dizinlerin veri çerçevelerinde tutarlı olduğunu varsayarsak (gerçek col değerleri dikkate alınmaz):

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

1
@ChrisNielsen durumun olumsuzlanması. Yani bu örnekte " df1dizinlerin DEĞİLDİR olduğu satırları al" anlamına gelir df2.index. Olumsuzluk hakkında daha fazla bilgi: stackoverflow.com/q/19960077/304209 (şaşırtıcı bir şekilde, panda dokümanlarında tilde'den herhangi bir söz bulamadım).
Dennis Golomazov

Görünüşe göre dfs aynı uzunlukta olmalı, değil mi? Ben alıyorumValueError: Item wrong length x instead of y.
wordsforthewise

@wordsforthewise hayır, bilmiyorlar. Maske df1 uzunluğuna sahiptir ve df1'e de uygulanır. Örneğinizi verebilir misiniz?
Dennis Golomazov

Ürün uzunluğu sorununu düzeltmek için .loc
Moreno

13

Daha önce de ima edildiği gibi, isin bir eşleşme için sütunların ve indekslerin aynı olmasını gerektirir. Eşleşmenin yalnızca satır içeriğinde olması gerekiyorsa, mevcut satırları filtrelemek için maskeyi almanın bir yolu, satırları bir (Çoklu) Dizine dönüştürmektir:

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

Dizin dikkate alınacaksa, set_index'in mevcut dizine sütun eklemek için anahtar kelime bağımsız değişkeni eklenir. Sütunlar hizalanmazsa, verileri hizalamak için liste (df.columns) sütun spesifikasyonlarıyla değiştirilebilir.

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

alternatif olarak endeksleri oluşturmak için kullanılabilir, ancak bunun daha verimli olduğundan şüpheliyim.


@ Dev_123 Başlangıçtaki ~ işaretini kaldırın. Çekirdek, df1'deki satırların da df2'de olup olmadığının kesin bir listesini oluşturmaktır, bu nedenle df1'deki satırlar df1'e özgü değildir, ~ bunu df1'deki satırların df2'de oluşup oluşmadığının kesin bir listesine reddeder.
Rune Lyngsoe

11

İki veri çerçeveniz olduğunu, df_1 ve df_2'nin birden çok alana (sütun_adları) sahip olduğunu ve df_1 içinde bazı alanlara (df_2, fields_y gibi) yalnızca df_2'de olmayan girişleri bulmak istediğinizi varsayalım, aşağıdaki adımları izleyin.

Adım 1. Sırasıyla df_1 ve df_2'ye bir sütun anahtarı1 ve anahtar2 ekleyin.

Adım 2. Veri çerçevelerini aşağıda gösterildiği gibi birleştirin. field_x ve field_y istenen sütunlarımızdır.

Adım 3. Yalnızca df_1 öğesinden, anahtar1'in anahtar2'ye eşit olmadığı satırları seçin.

Adım 4. Anahtar 1 ve Anahtar 2'yi bırakın.

Bu yöntem sorununuzu çözer ve büyük veri kümelerinde bile hızlı çalışır. 1.000.000'dan fazla satırı olan veri çerçeveleri için denedim.

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)

Bunun teknik olarak ne istediğini düşünmüyorum - hangi satırların hangi df'ye özgü olduğunu bilmek istiyor. ancak, bu çözümün ilk df veya ikinci df için benzersiz olan bir satır df döndürdüğünü düşünüyorum.
Yasal Yığın


3

bunu isin (dict) yöntemini kullanarak yapabilirsiniz :

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

Açıklama:

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

Bu yanlış sonuç verir. Aşağıdaki açıklamama bakın.
Ted Petrou

2

Ayrıca df1, şunları da yapabilirsiniz df2:

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

ve sonra tüm kopyaları kaldırın:

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

StackOverflow'a hoş geldiniz: kod, XML veya veri örnekleri gönderiyorsanız, lütfen metin düzenleyicide bu satırları vurgulayın ve düzenleyici araç çubuğundaki "kod örnekleri" düğmesini ({}) veya güzel biçimlendirmek için klavyenizdeki Ctrl + K tuşlarını tıklayın ve sözdizimi vurgulayın!
WhatsThePoint

4
Bu, yalnızca df1'deki verileri değil, her iki kümedeki tüm verileri döndürür.
Jamie Marshall

1

Buna ne dersin:

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

İşte bunu çözmenin başka bir yolu:

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

Veya:

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

0

Bunu yapmanın yolu, bir veri çerçevesine özgü yeni bir sütun eklemek ve bunu bir giriş tutup tutmayacağınızı seçmek için kullanmaktır

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

Bu, df1'deki her girişin df1'e özgü ise - 0, her iki dataFrames'te ise 1 koduna sahip olmasını sağlar. Daha sonra bunu istediğinizle kısıtlamak için kullanırsınız

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

0
birleştirme işlevini kullanarak farklı satırları ayıkla
df = df.merge(same.drop_duplicates(), on=['col1','col2'], 
               how='left', indicator=True)
farklı satırları CSV'ye kaydetme
df[df['_merge'] == 'left_only'].to_csv('output.csv')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.