Автор оригинала: Ayush Pandey.
В последние годы программная реклама захватывает индустрию онлайн-рекламы. Чтобы обеспечить автоматическую продажу и покупку показов рекламы между рекламодателями и издателями с помощью аукционов в режиме реального времени, торги в режиме реального времени (RTB) быстро становятся ведущим методом.
В отличие от традиционного рынка онлайн-рекламы, где определенное количество показов продается по фиксированной ставке, RTB позволяет рекламодателям делать ставки на каждый показ индивидуально в режиме реального времени по стоимости, основанной на функциях уровня показов. Торги в режиме реального времени (RTB)-это способ проведения транзакций с медиа, который позволяет выставлять отдельные показы объявлений на торги в режиме реального времени. Это делается с помощью программного аукциона на месте , который аналогичен тому, как работают финансовые рынки. RTB позволяет использовать адресную рекламу; возможность показывать рекламу потребителям непосредственно на основе их демографических, психографических или поведенческих характеристик.
Многие DSP (Платформы со стороны спроса) выступают в качестве агентов для рекламодателей и принимают участие в аукционе в режиме реального времени от их имени. Для того, чтобы обеспечить ставки в режиме реального времени и предоставить рекламодателям клики по самой низкой цене, DSP разрабатывают свои собственные алгоритмы машинного обучения, используя такие методы, как трюк хеширования , комбинации функций, стохастический градиентный спуск и т.д.
Мотивация
Как и стандартная практика в большинстве случаев использования науки о данных, всякий раз, когда разрабатывается новый алгоритм, они подвергаются A/B-тестированию против уже существующего алгоритма в производстве (по крайней мере, в течение нескольких дней), чтобы определить, какой алгоритм лучше соответствует бизнес-метрикам.
Из-за огромного объема запросов на участие в торгах (около миллиона запросов на участие в торгах в секунду) объем данных, собранных во время AB, составляет порядка 100 Гб. Библиотека Python Pandas обладает практически всеми функциями, необходимыми для автономного анализа собранных данных с точки зрения CPC, расходов, кликов, CTR, AUC и т. Д.
Но у Pandas есть огромная проблема, она должна загрузить весь набор данных в память, чтобы выполнить на нем некоторые вычисления. По моему опыту, Pandas требует, чтобы размер оперативной памяти был в 3 раза больше размера набора данных , и он не может быть запущен в распределенную среду в качестве кластера машин a. Именно здесь Apache Spark полезен, поскольку он может обрабатывать наборы данных, размер которых превышает размер оперативной памяти. Этот блог не будет охватывать внутренние компоненты Apache Spark и то, как он работает, скорее я перейду к тому, как код анализа CTR Pandas может быть легко преобразован в анализ spark с небольшими изменениями синтаксиса.
Миграция в Искру от панд
В новых версиях Spark начал поддерживать фреймы данных, которые концептуально эквивалентны фрейму данных в R/Python. Поддержка фреймов данных в Spark позволила пользователям сравнительно легко переключаться на Spark из Pandas, используя очень похожий синтаксис. В этом разделе я бы перешел к кодированию и показал, как анализ CTR, выполняемый в Pandas, может быть перенесен в Spark.
Прежде чем я перейду к кодированию, я хотел бы представить некоторые ключевые слова, используемые в коде:
Эффективная цена за клик : Общее количество потраченных денег/Общее количество кликов
Метка : это либо 0, либо 1 (1 означает, что щелчок произошел, а 0 означает отсутствие щелчка)
Цена выигрыша : Цена, уплаченная за победу на аукционе на месте
Bid CPC : Цена, которую рекламодатель готов заплатить за показ
CTR : Количество кликов/Общее количество показов
Чем цена выигрыша отличается от цены предложения?
Если биржа использует Аукцион по первой цене , выигрышная цена и цена предложения одинаковы , но если биржа использует Аукцион по второй цене , рекламодатель с самой высокой ценой предложения выигрывает, но он платит цену, эквивалентную второй самой высокой цене предложения, следовательно, цена выигрыша меньше цены предложения.
Настройка записной книжки и импорт библиотек
Панды
import pandas as pd
Искра
import os import sys os.environ['SPARK_HOME'] = "/home/spark-2.3.2-bin-hadoop2.7" os.environ['JAVA_HOME'] = "/home/jdk1.8.0_181" spark_home = os.environ.get("SPARK_HOME") sys.path.insert(0, spark_home + "/python") sys.path.insert(0, os.path.join(spark_home, "python/lib/py4j-0.10.7-src.zip")) from pyspark import SparkContext from pyspark.conf import SparkConf CLUSTER_URL = "spark://address:7077" conf = SparkConf() conf.setMaster(CLUSTER_URL).setAppName("CTR Analysis").set("spark.executor.memory", "120g") sc = SparkContext(conf=conf) print(sc.version)
Чтение CSV-файла
Панды
df = pd.read_csv(data_file_path, names=cols, error_bad_lines=False, warn_bad_lines=True, sep=',')
Искра
from pyspark.sql.types import StructType, StructField from pyspark.sql.types import DoubleType, IntegerType, StringType file_location = "hdfs://address:port/hadoop/dataNode/pyspark/data.csv" df = spark.read.csv(file_location, header=False, schema=schema, sep=",") # df = spark.read.csv(file_location, header=False, inferSchema=True, sep=",") # df.cache()
Очистка данных
Панды
numeric_cols = ['label','win_price','ctr','bid_cpc'] df[numeric_cols] = df[numeric_cols].convert_objects(convert_numeric=True) df.dropna(inplace=True, subset=numeric_cols)
Искра
numeric_cols = ['label','win_price','ctr','bid_cpc'] df = df.dropna(subset=numeric_cols)
Расчет Расходов, CTR, CPC На Algo
Панды
data = df.groupby(['algo']).agg({'win_price': np.sum, c_label:{'clicks':np.sum, 'wins':'count'}}).reset_index() data[('win_price','sum')] = data[('win_price','sum')] / 1000. data['ecpc'] = data[('win_price','sum')] / data[('label,'clicks')] data = pd.DataFrame(data.to_records()) data.columns = ['', algo, 'spend', 'number of impressions', 'number of clicks', 'effective cpc']
Искра
from pyspark.sql.functions import udf import pyspark.sql.functions as f def divide_by_1000(x): return x/1000.0 udf divide_by_1000 = udf(divide_by_1000, DoubleType()) data_wins = df.groupby(['algo']).agg( {'win_price': 'sum', 'label: 'count'}) data_clicks = df.groupby(['algo']).agg({'label: 'sum'}) # print data_wins.columns # print data_clicks.columns # Rename the columns data_wins = data_wins.withColumnRenamed("sum(win_price)","win_price").withColumnRenamed("count(label)", "wins") # print data_wins.schema # data_wins['win_price'] = data_wins.win_price/1000. data_wins = (data_wins.withColumn("win_price",udf divide_by_1000("win_price"))) data_clicks = data_clicks.withColumnRenamed("sum(label)", "clicks") # print data_wins.columns # print data_clicks.columns data = data_wins.join(data\_clicks, on = 'algo', how='inner') data = (data.withColumn("effective cpc", f.col("win_price")/100))