Find common values within a column containing list of items

 ̄綄美尐妖づ 提交于 2019-12-06 06:36:19

问题


I have a dataset that contains a few columns that are a list of items. I have given an example below. I am trying to find the entries that have items within the list with a 100% match. I would like to find the ones that have 90% or lower.

>>> df2 = pd.DataFrame({ 'ID':['1', '2', '3', '4', '5', '6', '7', '8'], 'Productdetailed': [['Phone', 'Watch', 'Pen'], ['Pencil', 'fork', 'Eraser'], ['Apple', 'Mango', 'Orange'], ['Something', 'Nothing', 'Everything'], ['Eraser', 'fork', 'Pencil'], ['Phone', 'Watch', 'Pen'],['Apple', 'Mango'], ['Pen', 'Phone', 'Watch']]})

>>> df2
ID                   Productdetailed
0  1               [Phone, Watch, Pen]
1  2            [Pencil, fork, Eraser]
2  3            [Apple, Mango, Orange]
3  4  [Something, Nothing, Everything]
4  5            [Eraser, fork, Pencil]
5  6               [Phone, Watch, Pen]
6  7                    [Apple, Mango]
7  8               [Pen, Phone, Watch]

If you notice the index 0 and index 7 in df2, have the same set of items but in different order. Where as index 0 and index 5 have same items in same order. I would like to consider both of them as a match. I tried groupby and series.isin(). I also tried intersection by splitting the dataset into two but it fails with type error.

First I would like to count the number of exact matched items(number of matched row count will do) along with the row index numbers it matched to. But when there are items that have only partially matched like index 2 and index 6 in df2. I would like to say the percent of items that have matched and against which column numbers.

I mentioned. I tried to split the data on specific column value into two parts. Then

applied df2['Intersection'] = 
     [list(set(a).intersection(set(b))) 
         for a, b in zip(df2_part1.Productdetailed, df2_part2.Productdetailed)
     ]

, where a and b are the Productdetailed column from the broken pieces of df2_part1 and df2_part2.

Is there a way to do this? Please help


回答1:


This solution solves the exact match task (Code complexity is very high and not recommended):

#First create a dummy column of Productdetailed which is sorted
df2['dummy'] = df2['Productdetailed'].apply(sorted)
#Create Matching column which stores index of first matched list
df2['Matching'] = np.nan

#Code for finding the exact matches and assigning indices in Matching column
for index1,lst1 in enumerate(df2['dummy']):
    for index2,lst2 in enumerate(df2['dummy']):
        if index1<index2:
            if (lst1 == lst2):
                if np.isnan(df2.loc[index2,'Matching']):
                    df2.loc[index1,'Matching'] = index1
                    df2.loc[index2,'Matching'] = index1

#Finding the sum of total exact matches
print(df2['Matching'].notnull().sum())
5

#Deleting the dummy column
del df2['dummy']

#Final Dataframe
print(df2)

  ID                   Productdetailed  Matching
0  1               [Phone, Watch, Pen]       0.0
1  2            [Pencil, fork, Eraser]       1.0
2  3            [Apple, Mango, Orange]       NaN
3  4  [Something, Nothing, Everything]       NaN
4  5            [Eraser, fork, Pencil]       1.0
5  6               [Phone, Watch, Pen]       0.0
6  7                    [Apple, Mango]       NaN
7  8               [Pen, Phone, Watch]       0.0

For both Fully and Partially Match use (If atleast 2 values matches it is partially matched, can also be changed):

#First create a dummy column of Productdetailed which is sorted
df2['dummy'] = df2['Productdetailed'].apply(sorted)
#Create Matching column which stores index of first matched list
df2['Matching'] = np.nan
#Create Column Stating Status of Matching
df2['Status'] = 'No Match'

#Code for finding the exact matches and assigning indices in Matching column
for index1,lst1 in enumerate(df2['dummy']):
    for index2,lst2 in enumerate(df2['dummy']):
        if index1<index2:
            if (lst1 == lst2):
                if np.isnan(df2.loc[index2,'Matching']):
                    df2.loc[index1,'Matching'] = index1
                    df2.loc[index2,'Matching'] = index1
                    df2.loc[[index1,index2],'Status'] = 'Fully Matched'
            else:
                count = sum([1 for v1 in lst1 for v2 in lst2 if v1==v2])
                if count>=2:
                    if np.isnan(df2.loc[index2,'Matching']):
                        df2.loc[index1,'Matching'] = index1
                        df2.loc[index2,'Matching'] = index1
                        df2.loc[[index1,index2],'Status'] = 'Partially Matched'

#Finding the sum of total exact matches
print(df2['Matching'].notnull().sum())

7

#Deleting the dummy column
del df2['dummy']

#Final Dataframe
print(df2)

  ID                   Productdetailed  Matching             Status
0  1               [Phone, Watch, Pen]       0.0      Fully Matched
1  2            [Pencil, fork, Eraser]       1.0      Fully Matched
2  3            [Apple, Mango, Orange]       2.0  Partially Matched
3  4  [Something, Nothing, Everything]       NaN           No Match
4  5            [Eraser, fork, Pencil]       1.0      Fully Matched
5  6               [Phone, Watch, Pen]       0.0      Fully Matched
6  7                    [Apple, Mango]       2.0  Partially Matched
7  8               [Pen, Phone, Watch]       0.0      Fully Matched



回答2:


To know the exact match:

df2["Productdetailed"]=df2["Productdetailed"].sort_values()
# create new colum from the sorted list. More easy to work with pivot table
df2['Productdetailed_str'] = df2['Productdetailed'].apply(lambda x: ', '.join(x))
df2["hit"] = 1
df3 = (df2.pivot_table(index=["Productdetailed_str"],
                 values=["ID", "hit"],
                aggfunc={'ID': lambda x: ', '.join(x), 'hit': 'sum'}
               ))

Hit is number of occurrences. result df3:

                                  ID  hit
Productdetailed_str                      
Apple, Mango                       7    1
Apple, Mango, Orange               3    1
Eraser, fork, Pencil               5    1
Pen, Phone, Watch                  8    1
Pencil, fork, Eraser               2    1
Phone, Watch, Pen               1, 6    2
Something, Nothing, Everything     4    1

The partial match is more difficult but you can start splitting the list and play with the pivot table:

test = df2.apply(lambda x: pd.Series(x['Productdetailed']),axis=1).stack().reset_index(level=1, drop=True).to_frame(name='list').join(df2)

If you run test. You have in "list column" the word that is in "Productdetailed column" list. Also, you have the ID... so I think that with pivot table you can extract the info..



来源:https://stackoverflow.com/questions/52590439/find-common-values-within-a-column-containing-list-of-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!