Итеративное добавление вычисляемых столбцов, а затем просто новых данных в фрейм данных Pandas (python 3.7.1) - PullRequest
5 голосов
/ 14 марта 2019

У меня есть один начальный кадр данных df1:

    df1 = pd.DataFrame(np.array([[1, 'B', 'C', 'D', 'E'], [2, 'B', 'C', 'D', 'E'], [3, 'B', 'C', 'D', 'E'], [4, 'B', 'C', 'D', 'E'], [5, 'B', 'C', 'D', 'E']]), columns=['a', 'b', 'c', 'd', 'e'])

        a   b   c   d   e
    0   1   B   C   D   E
    1   2   B   C   D   E
    2   3   B   C   D   E
    3   4   B   C   D   E
    4   5   B   C   D   E

Затем я вычисляю некоторые новые параметры на основе значений столбца df1, создаю новый df2 и объединяюсь с df1 для имени столбца «a».

    df2 = pd.DataFrame(np.array([[1, 'F', 'G'], [2, 'F', 'G']]), columns=['a', 'f', 'g'])

        a   f   g
    0   1   F   G
    1   2   F   G
    df1 = pd.merge(df1, df2,  how='left', left_on=['a'], right_on = ['a'])

        a   b   c   d   e   f   g
    0   1   B   C   D   E   F   G
    1   2   B   C   D   E   F   G
    2   3   B   C   D   E   NaN NaN
    3   4   B   C   D   E   NaN NaN
    4   5   B   C   D   E   NaN NaN

Это прекрасно работает, но в другом событии цикла я создаю df3 с теми же столбцами, что и df2, но слияние в этом случае не работает, оно не учитывает, что те же столбцы уже есть в df1.

ВАЖНОЕ ЗАМЕЧАНИЕ : Это только для иллюстрации, добавляются тысячи новых информационных фреймов, по одному на шаг цикла.

    df3 = pd.DataFrame(np.array([[3, 'F', 'G']]), columns=['a', 'f', 'g'])

        a   f   g
    0   3   F   G
df1 = pd.merge(df1, df3,  how='left', left_on=['a'], right_on = ['a'])

        a   b   c   d   e   f_x g_x f_y g_y
    0   1   B   C   D   E   F   G   NaN NaN
    1   2   B   C   D   E   F   G   NaN NaN
    2   3   B   C   D   E   NaN NaN F   G
    3   4   B   C   D   E   NaN NaN NaN NaN
    4   5   B   C   D   E   NaN NaN NaN NaN

Я только один, чтобы заполнить пропущенные пробелы, используя уже существующие столбцы. Этот подход создает новые столбцы (f_x, g_x, f_y, g_y).

Добавление и контакт также не работают, поскольку они повторяют информацию (повторяющиеся строки на «а»).

Какой-нибудь совет, как это решить? Окончательный результат после слияния df1 с df2, а после с df3 должен быть:

        a   b   c   d   e   f   g
    0   1   B   C   D   E   F   G
    1   2   B   C   D   E   F   G
    2   3   B   C   D   E   F   G
    3   4   B   C   D   E   NaN NaN
    4   5   B   C   D   E   NaN NaN

В конечном итоге все столбцы будут заполнены во время цикла, поэтому при первом добавлении (df2) будут добавлены новые столбцы, а с df3 и далее только новые данные для заполнения всего NaN. Цикл выглядит так:

df1 = pd.DataFrame(np.array([[1, 'B', 'C', 'D', 'E'], [2, 'B', 'C', 'D', 'E'], [3, 'B', 'C', 'D', 'E'], [4, 'B', 'C', 'D', 'E'], [5, 'B', 'C', 'D', 'E']]), columns=['a', 'b', 'c', 'd', 'e'])
for num, item in enumerate(df1['a']):
    #compute df[num] (based on values on df1)
    df1 = pd.merge(df1, df[num],  how='left', left_on=['a'], right_on = ['a'])

Ответы [ 3 ]

3 голосов
/ 14 марта 2019

Одним из возможных решений является concat все малое DataFrame с, а затем только один раз merge:

df4 = pd.concat([df2, df3])
print (df4)
   a  f  g
0  1  F  G
1  2  F  G
0  3  F  G

df1 = pd.merge(df1, df4,  how='left', on = 'a')
print (df1)
   a  b  c  d  e    f    g
0  1  B  C  D  E    F    G
1  2  B  C  D  E    F    G
2  3  B  C  D  E    F    G
3  4  B  C  D  E  NaN  NaN
4  5  B  C  D  E  NaN  NaN

Другое возможное решение - использование DataFrame.combine_first с DataFrame.set_index:

df1 = (df1.set_index('a')
         .combine_first(df2.set_index('a'))
         .combine_first(df3.set_index('a')))
print (df1)
   b  c  d  e    f    g
a                      
1  B  C  D  E    F    G
2  B  C  D  E    F    G
3  B  C  D  E    F    G
4  B  C  D  E  NaN  NaN
5  B  C  D  E  NaN  NaN
1 голос
/ 14 марта 2019

Другой способ - тоже использовать fillna, затем отбросить лишние столбцы, которые вам больше не нужны:

# Fill NaN with the extra columns value
df1.f_x.fillna(df1.f_y, inplace=True)
df1.g_x.fillna(df1.g_y, inplace=True)

   a  b  c  d  e  f_x  g_x  f_y  g_y
0  1  B  C  D  E    F    G  NaN  NaN
1  2  B  C  D  E    F    G  NaN  NaN
2  3  B  C  D  E    F    G    F    G
3  4  B  C  D  E  NaN  NaN  NaN  NaN
4  5  B  C  D  E  NaN  NaN  NaN  NaN

# Slice of the last two columns
df1 = df1.iloc[:, :-2]
# Rename the columns correctly
df1.columns = df1.columns.str.replace('_x', '')

Вывод

   a  b  c  d  e    f    g
0  1  B  C  D  E    F    G
1  2  B  C  D  E    F    G
2  3  B  C  D  E    F    G
3  4  B  C  D  E  NaN  NaN
4  5  B  C  D  E  NaN  NaN
0 голосов
/ 14 марта 2019

Я бы просто использовал подмножество df1 при слиянии с df3, или, в качестве альтернативы, я бы оставил копию исходного df1.

  1. подмножество:

    df1.fillna(pd.merge(df1.loc(1)['a':'e'], df3, how='left',
                        left_on=['a'], right_on = ['a']),
               inplace=True)
    
  2. копия оригинальных данных

    df1_orig = df1           # before merging with df2
    ...
    df1.fillna(pd.merge(df1_orig, df3, how='left',
                        left_on=['a'], right_on = ['a']),
               inplace=True)
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...