Добавить два новых столбца в зависимости от другого dafaframe в pandas

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

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

Вопрос:

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

Вот основной фрейм данных, в который мы будем добавлять столбцы :

df1

 Name        start1 end1 strand length 
OK0100087.1 187    250         63
OK0100087.1 830    750  -      80
OK0100087.1 500    625         125
OK0100087.1 375    275  -      100   
OK0100087.1 150    20   -      120
OK0100088.1 600    1000        400
  

из этого df я хотел бы добавить 2 столбца с именем Newstart и `Newend` `
df2

 Name        start1 end1 strand length Newstart Newend 
OK0100087.1 187    250         63
OK0100087.1 830    750  -      80
OK0100087.1 500    625         125
OK0100087.1 375    275  -      100   
OK0100087.1 150    20   -      120
OK0100088.1 600    1000        400
  

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

df2

 Name        start_plus end_plus start_minus end_minus 
OK0100087.1_0 0          375      1000        625
OK0100087.1_1 376        750      624         250 
OK0100087.1_3 751        1000     249         0 
OK0100088.1   0          12000    0           12000
OK0100089.1_0 0          566      3000        2433
OK0100089.1_1 567        3000     2432        0
  

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

 if df1.strand.eq("-"):
   df1.Newstart = df1.start1 - df2.end_minus
   df1.Newend = df1.Newstart - df1.length

if df1.strand.eq(" "):
   df1.Newstart = df1.start1 - df2.start_plus
   df1.Newend = df1.Newstart   df1.length
  

итак, давайте возьмем в качестве примера, чтобы лучше понять:

первая Name группа OK0100087.1 в df1

 Name        start1 end1 strand length Newstart Newend 
OK0100087.1 187    250         63
OK0100087.1 830    750  -      80
OK0100087.1 500    625         125
OK0100087.1 375    275  -      100   
OK0100087.1 150    20   -      120
  

первая строка представляет собой цепочку, затем df1.end1 = 250

в df2 мы сохраняем только df2.Names.str.contains(df1.Name) значение и 250 находится в пределах интервала

 Name          start_plus end_plus 
OK0100087.1_0 0          375
  

(Я взял start_plus и end_plus в качестве интервала, потому что это strand).

итак

 if df1.strand.eq(" "):
   df1.Newstart = df1.start1 - df2.start_plus
   (df1.Newstart = 187 - 0 = 187
   df1.Newend = df1.Newstart   df1.length
   (df1.Newend =187 63 = 250)
  

что дает:

 Name        start1 end1 strand length Newstart Newend 
OK0100087.1 187    250         63     187      250
OK0100087.1 830    750  -      80
OK0100087.1 500    625         125
OK0100087.1 375    275  -      100   
OK0100087.1 150    20   -      120
OK0100088.1 500    700         200
  

теперь давайте сделаем это для второй строки:

strand.eq("-") , так df1.start1 что (830) находится в пределах интервала :

 Name          start_minus end_minus 
OK0100087.1_0 1000        625
  

итак

 if df1.strand.eq("-"):
   df1.Newstart = df1.start1 - df2.end_minus
   (df1.Newstart = 830 - 625 =205)
   df1.Newend = df1.Newstart - df1.length
   df1.Newend = 205 - 80 = 125) 
  

что дает:

 Name        start1 end1 strand length Newstart Newend 
OK0100087.1 187    250         63     187      250
OK0100087.1 830    750  -      80     205      125
OK0100087.1 500    625         125
OK0100087.1 375    275  -      100   
OK0100087.1 150    20   -      120
OK0100088.1 500    700         200
  

и так далее …

 Name        start1 end1 strand length Newstart Newend 
OK0100087.1 187    250         63     187      250
OK0100087.1 830    750  -      80     205      125
OK0100087.1 500    625         125    125      250
OK0100087.1 375    275  -      100    125      25
OK0100087.1 150    20   -      120    150      20
OK0100088.1 600    1000        200    33       433
  

Если у кого-то есть какая-то идея, как это сделать, это было бы потрясающе.
большое вам спасибо

Ответ №1:

Из вашего примера неясно, уникальны ли имена или нет, и что делать, если какое-то имя из df1 совпадает с несколькими именами из df2.

В любом случае, процедура, которую я бы рекомендовал, — это использование DataFrame.apply метода. Этот метод получает функцию, которую он будет применять для каждой строки (укажите axis=1 в аргументах, в противном случае значение по умолчанию равно 0) при добавлении нового столбца в каждую строку (ваши атрибуты Newstart и Newend).

Пример:

 def func(row-from-df):
    df2Portion = d2[d2[Name].str.contains(row-from-df[Name], na=False)]  # using vectorize string

    if row-from-df.strand.eq(' '):
        # your logic here, you can add rows etc..
    else:
        # your logic here

    return row-from-df

df1.apply(func, axis=1)
  

Обратите внимание, что вы должны вернуть строку, которую вы изменили.

Также обратите внимание, что возвращаемое значение представляет собой новый фрейм данных, он не является inplace, который изменяет исходный df1.

Вы можете прочитать больше здесь