1
votes

Comment trouver efficacement une ligne de dataframe contenant des éléments de la liste?

Disons que j'ai l'exemple suivant

items = ['milk', 'bread', 'water']

df:
name     item1    item2    item3

items_1  milk     water
items_2  milk     rubber   juice
items_3  juice    paper    wood
items_4  bread
items_5  bread    water    milk
items_6  milk     juice

Dans cet exemple, je voudrais obtenir toutes les lignes df dont les membres sont complètement dans la liste des éléments, ce qui signifie:

  • items_1
  • items_4
  • items_5

Maintenant, le vrai dataframe "df" contiendra plusieurs millions de lignes, c'est-à-dire items_ *, d'où le "efficacement" dans le titre. Le nombre de colonnes de "df" sera compris entre 10 et 20. De plus, il y aura plusieurs milliers de listes "items" avec entre 10 et 20 éléments.

Quelqu'un peut-il m'aider s'il vous plaît sur celui-ci ?


2 commentaires

Quand vous dites complètement dans la liste, vous voulez dire le lait, le pain, l'eau doivent tous être dans la rangée, n'est-ce pas?


Prenez la ligne items_1, vérifiez si chaque élément de cette ligne est également dans la liste des éléments. dans ce cas, le lait et l'eau sont tous deux dans la liste des articles (lait, pain, eau) et c'est la ligne qui m'intéresse. De plus, tout ce qui se trouve sous la ligne items_4 (juste le pain dans ce cas) est contenu dans la liste des articles. J'espère que cela clarifie un peu le problème.


4 Réponses :


0
votes
    for item in dflist:
        if item not in items:
                print("this df list has an items that is not in the items list")
I know that the output isn't probably what you are looking to have as an output but your ideal output is unclear. What this for loop does is it will cycle through each item in your df lists (ex. items_1, items_2, etc.). It will look at each item in this list and will check if it is in the list of items you are checking against. If it finds an item that is not in the list of items you are checking against it will return that it has found an item not in your checking list. This seems what you are looking for, any value that is not in the first list of items labeled "items". So this checks for those and from here you could easily discard those.Generally when searching a big data set, binary search is the way to go, however this does not seem that feasible in this situation unless you can put the df lists in alphabetical order, if you cannot I would do what I wrote above.Hope this makes sense!

0 commentaires

0
votes

Nous devons trouver un moyen d'affirmer que les lignes sont complètement dans la liste items , tout en considérant les entrées nulles. Une combinaison de isin , sum et notna peut vous aider:

#set name as index
#allows us to focus on the items columns
#and later allows easy filtering
df = df.set_index("name")

#find rows that are in items
#and get the sum of the boolean
A = df.isin(items).sum(1)

#get the sum of rows
#that are not boolean
#this helps us narrow down
#items completely in the items list
#that are yet affected by null entries
B = df.notna().sum(1)

#compare A and B
#if they match, that implies complete entry in items list
cond = A.eq(B)

#let's see what cond looks : 

 cond

            name
items_1     True
items_2    False
items_3    False
items_4     True
items_5     True
items_6    False
dtype: bool

#filter df with condition to get your rows
df.loc[cond]


           item1    item2   item3
name            
items_1     milk    water   None
items_4     bread   None    None
items_5     bread   water   milk


0 commentaires

0
votes

Une autre solution:

Si votre dataframe ressemble à:

         item1  item2 item3
name                       
items_1   milk  water      
items_4  bread             
items_5  bread  water  milk

items = pd.Series(items + [''])
m = df.apply(lambda x: x.isin(items).all(), axis=1)
print(df[m])

Vous pouvez faire:

XXX

Impressions:

         item1   item2  item3
name                         
items_1   milk   water       
items_2   milk  rubber  juice
items_3  juice   paper   wood
items_4  bread               
items_5  bread   water   milk
items_6   milk   juice       


0 commentaires

2
votes

Utilisez ~ isin pour vérifier si la condition n'est PAS Vrai pour toutes les valeurs, récupérez l'index, utilisez l'indexation booléenne. Vous obtenez

true_names = df[~df.iloc[:, 1:].isin(items)].isnull().all(1)
df.loc[true_names, 'name']

0    name_1
3    name_4
4    name_5


1 commentaires

Merci d'avoir répondu. J'ai essayé votre proposition et cela a accéléré le temps d'exécution. J'essaierai également les autres réponses pour voir si une solution est encore plus rapide que la vôtre.