pandas: поиск значений столбца из одного df в другом столбце df, который содержит списки

#python-3.x #pandas #list #dataframe

#python-3.x #pandas #Список #dataframe

Вопрос:

Мне нужно выполнить поиск значений из столбца df1[‘numsearch’] в списках в df2 [‘Numbers’]. Если число есть в этих списках, то я хочу добавить значения из столбца df2 [‘Score’] в df1. Смотрите желаемый результат ниже.

 df1 = pd.DataFrame(
    {'Day':['M','Tu','W','Th','Fr','Sa','Su'],
     'numsearch':['1','20','14','99','19','6','101']
    })

df2 = pd.DataFrame(
    {'Letters':['a','b','c','d'],
     'Numbers':[['1','2','3','4'],['5','6','7','8'],['10','20','30','40'],['11','12','13','14']],
     'Score': ['1.1','2.2','3.3','4.4']})


desired output
  Day  numsearch            Score
0   M          1             1.1
1  Tu         20             3.3
2   W          4             4.4
3  Th         99          "No score"
4  Fr         19          "No score"
5  Sa          6             2.2 
6  Su        101          "No score"
  

Я написал цикл for, который работает с тестовыми данными.

 scores = []
for s,ns in enumerate(ppr_data['SN']):
    match = ''
    for k,q in enumerate(jcr_data['All_ISSNs']):    
        if ns in q:
            scores.append(jcr_data['Journal Impact Factor'][k])
            match = 1
        else:
            continue
    if match == "":
        scores.append('No score')
        match = ""
df1['Score'] = np.array(scores)
  

В моем небольшом тесте приведенный выше код работает, но при работе с файлами данных большего размера создаются дубликаты. Итак, это явно не лучший способ сделать это.

Я уверен, что есть более подходящая для pandas строка кода, которая заканчивается на .fillna("No score") .

Я пытался использовать loc инструкцию, но я зациклился на поиске значений одного фрейма данных в столбце, который содержит списки.

Кто-нибудь может пролить некоторый свет?

Ответ №1:

 df2=df2.explode('Numbers')#Explode df2 on Numbers
d=dict(zip(df2.Numbers, df2.Score))#dict Numbers and Scores
df1['Score']=df1.numsearch.map(d).fillna('No Score')#Map dict to df1 filling NaN with No Score
  

Можно сократить его следующим образом:

 df2=df2.explode('Numbers')#Explode df2 on Numbers
df1['Score']=df1.numsearch.map(dict(zip(df2.Numbers, df2.Score))).fillna('No Score')



   Day numsearch     Score
0   M         1       1.1
1  Tu        20       3.3
2   W        14       4.4
3  Th        99  No Score
4  Fr        19  No Score
5  Sa         6       2.2
6  Su       101  No Score
  

Комментарии:

1. Спасибо за это. Я забыл о «взрыве». Раньше я использовал эту функцию на другом языке, но это никогда не приходило мне в голову.

Ответ №2:

Вы можете попробовать левое соединение и заполнить:

 df1.merge(df2.explode('Numbers'), 
          left_on='numsearch', 
          right_on='Numbers', how='left')[['Day', 'numsearch', 'Score']].fillna("No score")
  

Вывод:

   Day numsearch     Score
0   M         1       1.1
1  Tu        20       3.3
2   W        14       4.4
3  Th        99  No score
4  Fr        19  No score
5  Sa         6       2.2
6  Su       101  No score
  

Комментарии:

1. Спасибо за этот ответ. Работает как шарм.