Повторение двух фреймов данных и предоставление минимального ранга при нескольких условиях

#python #pandas #for-loop

#python #pandas #для цикла

Вопрос:

Я хочу выполнить итерацию по двум фреймам данных, один из которых большой (с несколькими столбцами и ненулевым значением cols), а другой маленький (с некоторыми общими cols и нулевым значением в нем).

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

Фрейм данных Lager выглядит следующим образом —

 CUST_ID,DTL1,DTL2,DTLS3,AGE_BAND,SCORE,STATE,ATTR_1,ATTR_2,ATTR_3
1,xx,xx,xx,A1,S1,MH,1,1,6
2,xx,xx,xx,A1,S2,MH,1,2,7
3,xx,xx,xx,A2,S3,GJ,2,2,7
4,xx,xx,xx,A3,S1,RJ,1,2,6
5,xx,xx,xx,A2,S1,GJ,2,1,6
6,xx,xx,xx,A3,S3,RJ,1,2,7
  

и данные ранжирования —

 Rank,AGE_BAND,SCORE,STATE,ATTR_1,ATTR_2
1,A1,S1,MH,Null,Null
2,A1,Null,MH,Null,1
3,Null,S1,GJ,Null,1
4,Null,S1,GJ,2,Null
  

Здесь, если мы видим, то cust_1 удовлетворяет как для ранга 1, так и для ранга 2, но мы бы выбрали минимум, т. Е. 1. То же самое касается Cust_5, ранга 3.

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

Я ищу способ определить, что «имя_получателя» и «значение» в моем маленьком фрейме данных, которое соответствует моему большому фрейму данных, когда оно не равно null, а затем присвоить ему минимальный ранг.

Я пытаюсь написать что-то вроде приведенного ниже:

 for cust in Data_Cust.iterrows():       
    for rank in Data_rank.iterrows():       #if we can eliminate columns where its value are null for individual rank
        if rank.col_name == cust.col_name amp;amp; rank.col_value == cust.value  ##something from which we can match col/val name with col/value name of both dfs
        
            #create a list and appended all eligible ranks
            #selecting minimun rank at the end
            #appending list and min rank in Data_cust 
  

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

1. покажите свою работу / код и то, что вы сделали, а также каков ваш ожидаемый результат

2. На данный момент я не смог написать полный исполняемый код, но пытаюсь создать что-то вроде упомянутого в вопросе. @Jimmar

3. Я не совсем уверен, что вы пытаетесь сделать. Вам нужен способ сравнить каждый элемент из df1 с каждым элементом df2, а затем вычислить наилучший результат?

4. @MLAlex Это правильно! Каждый элемент из df1 должен сравниваться с df2, если он не равен нулю, а затем выбирается минимальный ранг.

5. Вы можете попробовать использовать вложенную функцию apply. Например, используйте .apply для первого столбца, чтобы получить каждый элемент сразу, а после этого вы используете функцию apply для другого столбца. Таким образом, вы можете сравнить первый элемент столбца 1 с каждым элементом столбца 2, а затем получить следующий элемент столбца 1.

Ответ №1:

Один из способов сделать это — создать ряд, который сопоставляет значения в столбцах с минимальным рангом для этого значения. Затем используйте этот ряд для сопоставления значений в строке для клиента.

 cols=['AGE_BAND', 'SCORE', 'STATE']
m = pd.concat([df_rank[[i, 'Rank']].replace('Null', np.nan).drop_duplicates([i], keep='first').dropna()
       .set_index(i)['Rank'] for i in cols])
m 
  

Затем,

 df.set_index('CUST_ID')[['AGE_BAND', 'SCORE', 'STATE']].stack().map(m).unstack()
  

Вывод:

          AGE_BAND  SCORE  STATE
CUST_ID                        
1             1.0    1.0    1.0
2             1.0    NaN    1.0
3             NaN    NaN    3.0
4             NaN    1.0    NaN
5             NaN    1.0    3.0
6             NaN    NaN    NaN
  

Минимальный ранг для каждого клиента:

 CUST_ID
1    1.0
2    1.0
3    3.0
4    1.0
5    3.0
6    NaN
dtype: float64
  

Ответ №2:

Вы можете использовать сравнение матриц для быстрого сопоставления и систему взвешивания для определения приоритетности порядка столбцов (необязательно).

 import pandas as pd
import numpy as np
id_df = pd.read_csv('id.txt', index_col=0)
rank_df = pd.read_csv('rank.txt', index_col=0)

cols_of_interest = id_df.iloc[:, [3,4,5,6,7]] # because you're not using all the columns
scaling = np.array([5,4,3,2,1])

final_ranks = []

for i in cols_of_interest.index:
    current_row = cols_of_interest.loc[i,:] # get the row of interest
    diff = (rank_df == current_row) # compare current row to ALL the rows in RANK_DF
    diff = diff * scaling # scale the columns by multiplying by the scale array (same length as number of columns)
    scores = diff.sum(axis=1) # sum up the scores by row
    final_ranks.append(scores.idxmax()) # get the index (ie rank) of the first occurrence of the max score, which if RANK_DF is sorted, should give you the small rank that meets the criteria.

print(final_ranks)
  

Приводит к:

 [1, 1, 3, 1, 3, 1]