Как использовать df.apply (), передавая выбранные столбцы данных в другую функцию - PullRequest
0 голосов
/ 20 марта 2019

У меня есть датафрейм с несколькими столбцами. Два столбца в кадре данных - это имя_таблицы и имя_столбца. Мне нужно проверить, доступно ли column_name в table_name в базе данных SQL Server.

Теперь у меня есть функция check_column_existence () для этого, которая, кажется, работает нормально, если я использую традиционный метод чтения файла csv и вызова функции:

def check_column_existence(dbHost, dbPort, dbName, dbUser, dbPassword, table_name, column_name):
    sqlQuery="""select count(*) from 
INFORMATION_SCHEMA.columns 
where table_name='{}' and column_name='{}';""".format(table_name, column_name)
    conn = pymssql.connect(host=dbHost, port=dbPort, user=dbUser, password=dbPassword, database=dbName)
    cursor = conn.cursor()
    sql = sqlQuery.encode('utf-8')
    cursor.execute(sql)
    for row in cursor:
        if row[0] == 1:
            result = True
        else:
            result = False
    print(result)
    return result

def populate_db_attribute_existence(dbHost, dbPort, dbName, dbUser, dbPassword, input_csv_file_path):
    input_csv_file_path = os.path.abspath(input_csv_file_path)
    input_csv_folder_path = os.path.dirname(input_csv_file_path)
    input_csv_file_name = os.path.basename(input_csv_file_path)
    temp1_output_file_path = "{}/temp1_{}".format(input_csv_folder_path, input_csv_file_name)
    temp2_output_file_path = "{}/temp2_{}".format(input_csv_folder_path, input_csv_file_name)

    df = pd.read_csv(input_csv_file_path)
    df['DB_Entity'] = df['DB_Entity'].str.replace(' ', '')
    df['DB_Attributes'] = df['DB_Attributes'].str.replace(' ', '')
    df2 = df[['API_Attributes', 'DB_Entity', 'DB_Attributes']]
    df2.to_csv(temp1_output_file_path, index=False, encoding='utf-8')

    with open(temp1_output_file_path,'r') as ftemp1, open(temp2_output_file_path,'w') as ftemp2:
        i = 1
        for row in ftemp1:
            if i > 1:
                row = row.strip()
                list_columns = row.split(',')
                api_attr_name = list_columns[0]
                db_entity_name = list_columns[1]
                c_name = list_columns[2]
                t_name = 'dbo.{}'.format(db_entity_name)
                result = check_column_existence(dbHost, dbPort, dbName, dbUser, dbPassword, t_name, c_name)
                ftemp2.write(','.join([api_attr_name, db_entity_name, c_name, str(result)])+'\n')
            i += 1



    del(df2)
    df2 = pd.read_csv(temp2_output_file_path, names=['API_Attributes', 'DB_Entity', 'DB_Attributes', 'DB_Attr_Exist'])
    merge_key = ['API_Attributes', 'DB_Attributes']
    merged_df = pd.merge(df, df2, on=merge_key, how='outer')
    merged_df.to_csv(input_csv_file_path, index=False, encoding='utf-8')
    os.remove(temp1_output_file_path)
    os.remove(temp2_output_file_path)
    print("Completed DB Attributes existence check: {}".format(input_csv_file_path))

Обновлен этот вопрос с моим текущим подходом. Пожалуйста, порекомендуйте, если есть более быстрые способы достичь того же. Как мне использовать df.apply () или лямбда-функцию в этом контексте, если это возможно?

Заранее признательны за вашу помощь или рекомендацию.

1 Ответ

0 голосов
/ 20 марта 2019

В вашем коде возможны различные улучшения.

Во-первых (это ваш вопрос), вы используете временные CSV-файлы только для просмотра строки данных. apply плохо, как объясняет @coldspeed, но использование диска еще хуже.

Поскольку у вас уже есть функция Python, которую вы хотите применить по строкам к существующему фрейму данных, чтобы добавить новый столбец, это приемлемый вариант использования для apply. Прямой доступ к базовым массивам numpy, безусловно, быстрее, но pandas был создан, чтобы иметь удобный фреймворк, а удобство обходится дорого. Так что здесь вы можете добавить новый столбец к вашему фрейму данных с помощью:

df = pd.read_csv(input_csv_file_path)
df['DB_Entity'] = df['DB_Entity'].str.replace(' ', '')
df['DB_Attributes'] = df['DB_Attributes'].str.replace(' ', '')
df['DB_Attr_Exist'] = df.apply(lambda x: check_column_existence(
                          dbHost, dbPort, dbName, dbUser, dbPassword,
                          'dbo'+x['DB_Entity'], x['DB_Attributes'])

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...