Обновление / обновление таблицы данных с использованием python - PullRequest
2 голосов
/ 15 марта 2020

Мне хотелось бы получить несколько советов о том, как обновить / вставить новые данные в уже существующую таблицу данных с помощью Python / Databricks:


# Inserting and updating already existing data

# Original data

import pandas as pd

source_data = {'Customer Number':  ['1', '2', '3'],
        'Colour': ['Red', 'Blue', 'Green'],
         'Flow': ['Good', 'Bad', "Good"]
        }

df1 = pd.DataFrame (source_data, columns = ['Customer Number','Colour', 'Flow'])

print(df1)

# New data

new_data = {'Customer Number':  ['1', '4',],
        'Colour': ['Blue', 'Blue'],
         'Flow': ['Bad', 'Bad']
        }

df2 = pd.DataFrame (new_data, columns = ['Customer Number','Colour', 'Flow'])

print(df2)

# What the updated table will look like

updated_data = {'Customer Number':  ['1', '2', '3', '4',],
        'Colour': ['Blue', 'Blue', 'Green', 'Blue',],
         'Flow': ['Bad', 'Bad', "Good", 'Bad']
        }

df3 = pd.DataFrame (updated_data, columns = ['Customer Number','Colour', 'Flow'])

print(df3)

Здесь вы можете видеть, что у исходных данных три клиента. Затем я получаю 'new_data', который содержит обновление данных клиента 1 и новые данные для клиента 4, которого еще не было в исходных данных. Затем, если вы посмотрите на «updated_data», вы увидите, как должны выглядеть окончательные данные. Здесь 'Данные клиента 1 обновлены , а данные клиента 4 * вставлены .

Кто-нибудь знает, с чего мне начать? Какой модуль я мог бы использовать?

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

Редактировать: источник данных - .txt или CSV, вывод - JSON, но когда я загружаю данные в Cosmos DB, они автоматически конвертируются, так что не беспокойтесь об этом.

Спасибо

Ответы [ 4 ]

1 голос
/ 24 марта 2020

Есть много способов, но с точки зрения читабельности, я бы предпочел сделать это.

import pandas as pd

dict_source = {'Customer Number': ['1', '2', '3'],
               'Colour': ['Red', 'Blue', 'Green'],
               'Flow': ['Good', 'Bad', "Good"]
               }

df_origin = pd.DataFrame.from_dict(dict_source)

dict_new = {'Customer Number': ['1', '4', ],
            'Colour': ['Blue', 'Blue'],
            'Flow': ['Bad', 'Bad']
            }

df_new = pd.DataFrame.from_dict(dict_new)

df_result = df_origin.copy()
df_result.set_index(['Customer Number', ], inplace=True)
df_new.set_index(['Customer Number', ], inplace=True)
df_result.update(df_new)  # update number 1

# handle number 4
df_result.reset_index(['Customer Number', ], inplace=True)
df_new.reset_index(['Customer Number', ], inplace=True)
df_result = df_result.merge(df_new, on=list(df_result), how='outer')
print(df_result)
  Customer Number Colour  Flow
0               1   Blue   Bad
1               2   Blue   Bad
2               3  Green  Good
3               4   Blue   Bad
1 голос
/ 17 марта 2020

Текущая структура фрейма данных и 'pd.update'

При некоторой подготовке вы можете использовать функцию pandas ' update '. Во-первых, фреймы данных должны быть проиндексированы (это часто полезно в любом случае). Во-вторых, исходный фрейм данных должен быть расширен новыми индексами с фиктивными / NaN-данными, чтобы его можно было обновлять.

# set indices of original data frames
col = 'Customer Number'
df1.set_index(col, inplace=True)
df2.set_index(col, inplace=True)
df3.set_index(col, inplace=True)

# extend source data frame by new customer indices
df4 = df1.copy().reindex(index=df1.index.union(df2.index))

# update data
df4.update(df2)

# verify that new approach yields correct results
assert all(df3 == df4)

Текущая структура фрейма данных и 'pd.concat'

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

df5 = pd.concat([df1, df2])
df5 = df5.loc[~df5.index.duplicated(keep='last')].sort_index()
assert all(df3 == df5)

Альтернативная структура данных

Учитывая, что «Номер клиента» является ключевым атрибутом ваших данных, Вы можете также рассмотреть возможность реструктуризации своих исходных словарей следующим образом:

{'1': ['Red', 'Good'], '2': ['Blue', 'Bad'], '3': ['Green', 'Good']}

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

# define function to restructure data, for demonstration purposes only
def restructure(data):
    # transpose original data
    # https://stackoverflow.com/a/6473724/5350621
    vals = data.values()
    rows = list(map(list, zip(*vals)))
    # create new restructured dictionary with customers as keys
    restructured = dict()
    for row in rows:
        restructured[row[0]] = row[1:]
    return restructured

# restructure data
source_restructured = restructure(source_data)
new_restructured = restructure(new_data)

# simply (re)set new keys
final_restructured = source_restructured.copy()
for key, val in new_restructured.items():
    final_restructured[key] = val

# convert to data frame and check results
df6 = pd.DataFrame(final_restructured, index=['Colour', 'Flow']).T
assert all(df3 == df6)

PS: при установке 'df1 = pd.DataFrame (source_data, columns = [...])' вам не нужно ' Аргумент столбцов, потому что ваши словари имеют правильные имена, а ключи автоматически воспринимаются как имена столбцов.

1 голос
/ 17 марта 2020

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

Затем вы можете сначала обновить начальные строки фрейма данных, перебирая точки пересечения номера Costumer, а затем объединить начальный фрейм данных только с новыми строками фрейма данных с новыми значениями.

# same name column for clarity  
cn = 'Customer Number'

# convert Consumer Number values into integer to use set
CusNum_df1 = [int(x) for x in df1[cn].values]
CusNum_df2 = [int(x) for x in df2[cn].values]

# find Customer Numbers to update and to add
CusNum_to_update = list(set(CusNum_df1).intersection(set(CusNum_df2)))
CusNum_to_add = list(set(CusNum_df2) - set(CusNum_df1))

# update rows in initial data frame 
for num in CusNum_to_update:
    index_initial = df1.loc[df1[cn]==str(num)].index[0]
    index_new = df2.loc[df2[cn]==str(num)].index[0]
    for col in df1.columns:
        df1.at[index_initial,col]= df2.loc[index_new,col]

# concatenate new rows to initial data frame 
for num in CusNum_to_add:
    df1 = pd.concat([df1, df2.loc[df2[cn]==str(num)]]).reset_index(drop=True)


out:
      Customer Number Colour  Flow
0               1   Blue   Bad
1               2   Blue   Bad
2               3  Green  Good
3               4   Blue   Bad
0 голосов
/ 17 марта 2020

Вы можете использовать 'Customer Number' как index и использовать update метод:

import pandas as pd

source_data = {'Customer Number':  ['1', '2', '3'],
        'Colour': ['Red', 'Blue', 'Green'],
         'Flow': ['Good', 'Bad', "Good"]
        }

df1 = pd.DataFrame (source_data, index=source_data['Customer Number'], columns=['Colour', 'Flow'])

print(df1)

# New data

new_data = {'Customer Number':  ['1', '4',],
        'Colour': ['Blue', 'Blue'],
         'Flow': ['Bad', 'Bad']
        }

df2 = pd.DataFrame (new_data, index=new_data['Customer Number'], columns=['Colour', 'Flow'])

print(df2)

df3 = df1.reindex(index=df1.index.union(df2.index))

df3.update(df2)

print(df3)
  Colour  Flow
1   Blue   Bad
2   Blue   Bad
3  Green  Good
4   Blue   Bad
...