Mam ramkę danych z dwiema kolumnami:

import pandas as pd
data={'A':['x','y','z','r','x','z'],'B':[1,2,3,4,1,7]}
df=pd.DataFrame(data)

To mnie dostaje:

A | B
x | 1
y | 2
z | 3
r | 4
x | 1
z | 7

Następnie lista z n listami dwóch elementów:

list_of_lists=[['x',1],['x',4],['z',3],['y',1]]

Chcę się dowiedzieć, czy element 1. każdej sub_list pasuje do kolumny A , a drugi element do kolumny B , otrzymując coś takiego:

A | B | Match
x | 1 | True
y | 2 | False
z | 3 | True
r | 4 | False
x | 1 | True
z | 7 | False

Pomyślałem o stworzeniu dwóch list dla każdego elementu list i zrobieniu czegoś takiego jak np. Gdzie z obydwoma warunkami, ale musi być bardziej przejrzysty sposób.

4
Alejandro A 18 grudzień 2019, 13:48

5 odpowiedzi

Możesz spróbować:

>>> df2 = pd.DataFrame(data = list_of_lists, columns = df.columns)
# less readable but slightly faster
# df2 = pd.DataFrame(dict(zip(['A','B'],zip(*list_of_lists))))
>>> df['Match'] = np.isin(df, df2).all(1)
>>> df
   A  B  Match
0  x  1   True
1  y  2  False
2  z  3   True
3  r  4  False
4  x  1   True
5  z  7  False
3
Sayandip Dutta 18 grudzień 2019, 14:19

Możesz użyć metody apply:

df['Match'] = df.apply(lambda r: r.tolist() in list_of_lists, axis=1)
df
   A  B   Match
0  x  1   True
1  y  2  False
2  z  3   True
3  r  4  False
4  x  1   True
5  z  7  False

Aby to zrozumieć, możesz wykonać krok pośredni i sprawdzić wynik:

df['temp'] = df.apply(lambda r: r.tolist(), axis=1)
df

   A  B    temp
0  x  1  [x, 1]
1  y  2  [y, 2]
2  z  3  [z, 3]
3  r  4  [r, 4]
4  x  1  [x, 1]
5  z  7  [z, 7]

Następnie

df['Match'] = df.apply(lambda r: r['temp'] in list_of_lists, axis=1)
df
   A  B    temp  Match
0  x  1  [x, 1]   True
1  y  2  [y, 2]  False
2  z  3  [z, 3]   True
3  r  4  [r, 4]  False
4  x  1  [x, 1]   True
5  z  7  [z, 7]  False
2
FBruzzesi 18 grudzień 2019, 14:00
1
Dzięki za odpowiedzi, na końcu poszedłem z odmianą tego!
 – 
Alejandro A
18 grudzień 2019, 15:04

Użyj DataFrame.merge z helperem DataFrame z lewym złączeniem i parametrem indicator=True, a następnie porównaj wartość both:

df1 = df.merge(pd.DataFrame(list_of_lists, columns=df.columns), how='left', indicator=True)

df['Match'] = df1['_merge'].eq('both')
print (df)
   A  B  Match
0  x  1   True
1  y  2  False
2  z  3   True
3  r  4  False
4  x  1   True
5  z  7  False
3
jezrael 18 grudzień 2019, 14:17
1
Pisałem coś dokładnie do tego, to jest właściwy sposób to zrobię, zmienię : columns = df.columns
 – 
ansev
18 grudzień 2019, 14:15

Spróbuj tego:

 df.apply(list, axis=1).apply(lambda x: True if x in list_of_lists else False) 

0     True
1    False
2     True
3    False
4     True
5    False
dtype: bool

2
oppressionslayer 18 grudzień 2019, 14:29

Moje podejście:

  • Utwórz ramkę danych z dopasowaniami
  • Połącz z oryginalnymi danymi
  • Brakuje niezgodności, więc w przypadku brakujących wartości musimy wpisać False

Uważam, że to podejście można skalować w górę, nawet jeśli lista dopasowań jest duża (więc pod względem elementów apply może być czasochłonne, ale łączenie lewostronne jest łatwe do zarządzania)

# data
data='''A|B
x|1
y|2
z|3
r|4
x|1
z|7'''
with open("a.txt", 'w') as f:
    print(data, file=f)
df1 = pd.read_csv("a.txt", sep="|")
list_of_lists=[['x',1],['x',4],['z',3],['y',1]]


# First, create a data frame of matches
matches = pd.DataFrame(list_of_lists, columns=['A', 'B'])
matches['Match'] = True

# left join with the original data, non-matches will be missing, so fill with False
df1.merge(matches, on=['A', 'B'], how='left').fillna(False)

Wynik:

   A  B  Match
0  x  1   True
1  y  2  False
2  z  3   True
3  r  4  False
4  x  1   True
5  z  7  False
1
9mat 18 grudzień 2019, 14:31