git конспект

Вот отсюда https://ru.hexlet.io/courses/intro_to_git/lessons/intro/theory_unit

sudo apt install git
git config —global user.name «Sergei Makarov»
git config —global user.email «s.makarov@petrovich.ru»

mkdir example
cd example/
cat .git/config

touch README.md # Создаем файл
echo ‘# Hi’ > README.md # Меняем содержимое

# Первая git add подготавливает измененный или добавленный файл к коммиту. Без её выполнения сделать коммит не получится.
git add README.md # Так гит увидит новый файл

#А вот команда git commit непосредственно фиксирует изменения в репозитории
git commit -m ‘init project’ # Коммит с сообщением ‘init project’

#История коммитов
git log

# И просмотр изменений
git show 97d07816c757f3d548bddeb9acd5eddb824b3f3b

Если перед коммитов сделать git status

On branch master
Your branch is up-to-date with ‘origin/master’.
Changes to be committed: # Изменения попадающие в следующий коммит

new file: .editorconfig
modified: Dockerfile

Changes not staged for commit: # Изменения которые не попадут в коммит

modified: docker-compose.yml
deleted: rebar.lock

Untracked files: # Неотслеживаемые файлы

Procfile
Untracked – это новый файл, который не был добавлен для отслеживания командой git add. Все остальные файлы являются tracked.

С непривычки такое поведение может показаться странным. Почему бы сразу не давать возможность коммитить, без необходимости добавлять файл в отслеживаемые?
На самом деле такое поведение очень важно. Как вы убедитесь в своей практике, множество инструментов генерирует свои файлы (например, редакторы, операционная система, пакетные менеджеры), а запуск программ порождает файлы с логами и другие артефакты. И если бы git commit автоматически включал все новые файлы, в репозиторий после коммитов постоянно попадали бы ненужные данные.

Про tracked файлы

С unmodified все просто. Если файл в рабочей копии точно такой же как и в репозитории, то считается что его не модифицировали. Любой файл после коммита переходит в состояние unmodified.
Modified тоже интуитивно понятен. Как только мы изменили любой файл, он автоматически становится modified.
Но в коммит попадут только staged файлы, это те к кторым мы применили git add

git reset path/to/file переводит файл из состояния staged в modified
git checkout path/to/file переводит файл из состояния modified в unmodified, то есть по сути эта команда сбрасывает изменения.

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

git branch показывает в какой ветке работаю

Предположим, что вы реализовали фичу и теперь хотите, чтобы этот код оказался в мастере. Делается это командой git merge, которая сливает ветки между собой.
Как получить копию удаленного репрезитория

example$ git init
example$ cd /tmp
git clone ~/example

Давайте теперь посмотрим главное — то, как отправлять изменения:
example$ echo ‘# Hello’ > README.md
example$ git commit -am ‘replace readme’
example$ git push

Как я скачал через GIT mlcourse

  1. Скопировал репрезиторий с гита. Т.е. я зашел на https://github.com/Yorko/mlcourse_open и нажал fork
  2. Зашел к себе на машину и установил гит
    sudo apt install git
    git config —global user.name «Sergei Makarov»
    git config —global user.email «s.makarov@petrovich.ru»
  3. создал папку где хочу видеть файлы курса
    mkdir Git
  4. Теперь пробуем скопировать с помощью команды git clone, но гит не даст этого сделать так как у нас нет доступа.
  5. Чтобы выдать нам доступ нужно сделать ssh ключ и привязать его к гиту:
    cd ~/.ssh
    ssh-keygen (тут мы генерим ключ и пароль к нему)
    cat ~/.ssh/id_rsa.pub (вот отсюда забираем ключ и копируем его в GIT)
    Подробнее тут
  6. Еще раз запускаем git clone git@github.com:SergeiMakarovWeb/mlcourse_open.git и начинается скачка файла
  7. Теперь нужно установить анаконду, чтобы манипулировать файлами
    Анаконду устанавливаем по этому туториалу https://www.digitalocean.com/community/tutorials/how-to-install-the-anaconda-python-distribution-on-ubuntu-16-04
    а юпитер по этому https://www.digitalocean.com/community/tutorials/how-to-set-up-a-jupyter-notebook-to-run-ipython-on-ubuntu-16-04
  8. Все готово!

Атрибуция

Новых считаем по первому клику, старых — как хотите. Для новых реально важен первый канал, откуда он приплыл

Проблема остается в том, что масштабировать каналы retention почти невозможно. Здесь мне кажется позиция Тимофея Шиколенкова о том, что каналы retention не должны впрямую участвовать в дележе стоимости конверсии согласно мультиканальной атрибуции логичной

Только в пределах выбранной модели атрибуции, в итоге все равно всегда есть погрешность ) Я к атрибуции отнушусь больше как к теории, потому что для разных источников и задач — разная атрибуция. Вполне очевидно что контекст интересен как источник новых клиентов, а любой ретаргетинг — для ретеншена и удержания. Но в одну модель это строить нельзя, потому что данные все равно будут кривые. Любое занижение эффективности первого клика приведет к занижению кол-ва новых клиентов и снижению общей выручки в будущем )
При этом в русском екоме до сих пор на первый клик все кладут, а топовые агентства строят свои отчеты по ласт-клику

Зависит от типичного сценария привлечения и конверсии клиента. На мой взгляд самые ценные переходы — первый и последний. В Analytics есть атрибуция, 40% на первый, 40% на последний, и 20% равномерно на все остальные. Называется «Атрибуция с привязкой к позиции»: https://support.google.com/analytics/answer/1665189?hl=ru

Снова про MP

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

Например, пользователь пришле из yandex / cpc, сделал заказ. Ему позвонил на след. день менеджер и изменил статус заказа. Пользователь, например, вернулся по ретаргетингу по google / cpc или другим способом на сайт на след. день. Еще через день менеджер опять позвонил и заказ по каким-то причинам отменился. в GA уйдет транзакция и запишеться на google / cpc.
на всякий для всех написал, так как это очень частотный вопрос.
Если кто знает придумает другой способ, с удовольствием узнаю (видел порядка 5-7 архитектур и способов все не работающие, в том числе склеивание через Import Data protocol, но с удовольствием узнаю, если я что-то не учитываю или появился новый способ)

Гугл делает сервис аналитики для Adwords, Googl Analytics не создавался как инструмент бизнес или продуктовой аналитики
Он ничего не знает про юнит-экономику, ARPU, ARPPU, все еще работает в основном по сессиям (хотя API 4 года как переводят на user-base аналитику и последние новости в блоге радуют). GA — в первую очередь API first разработку делают и они ок работать с доп. сервисами — Гуглу это выгодно иначе пользователи передут на другие user base системы аналитики и гугл потеряет возможность использовать данные для анализа что люди ищут и для продажи Adwords
Вместе с тем GA действительно улучшается, просто очень медлено.
edited
Сложного в MP полно, объясните разработчикам (хотя это есть в справке), почему при отправке eventAction с не целым eventValue (например 2.0 — число почти целое, но просто разработчик тип не проверил) в ответ на post запрос вы получите 200 ОК, но событие не будет записана
объясните что питон библиотеки, которые разработчики правильно берут с гитхаба для работы с MP часто записывают свой user-agent и по этой причине легко увидеть в GA что транзакции были отправлены с браузера или устройства: Python
Объясните чем “” отличается от (not set), и почему если использовать Core API вы выгружаете данные с запросом с dimension=ga:sourceMedium, ga:campaign, ga:keyword — вы получите меньше строчек чем через dimension=ga:sourceMedium, ga:campaign — потому что пустые “” keyword не передадуться в отличие от (not set)
ну и реально еще 50 таких примеров, могу в личке рассказать.
А еще попробуйте своими силами передавать транзакции, которые в CRM были получены через jivosite, calltracking и т.д. да еще правильно положив их в GA — практика показывает, что у 90 из 100 компаний это не получается или стоит очень дорого
и нафиг ломается и падает точность статистики, если кто-то из маркетологов забыл и выложил лендинг с неверно поставленным счетчиком через ga_clientID

Или поставил счетчик через GTM (еще недавно там погрешность была 10-15% при записи ga_clientID — теперь с помощью custom Task можно ставить счетчик через GTM почти без погрешности)

Мера новых клиентов в DAX

новый клиент = COUNTROWS(
 FILTER(VALUES(mysql_transactions_facts[userPhone]); 
 CALCULATE(DISTINCTCOUNT(mysql_transactions_facts[orderId]); 
 FILTER(ALL('calendar'); 
 'calendar'[Date]<MAX('calendar'[Date])
 )
 )>1 &&
 CALCULATE(COUNTROWS('mysql_transactions_facts'))=1
 )
 )

или так

COUNTROWS (
 FILTER (
 ADDCOLUMNS (
 VALUES ( mysql_transactions_facts[userPhone] ),
 "PreviousSales", CALCULATE (
 COUNTROWS ( mysql_transactions_facts),
 FILTER (
 ALL ( 'calendar' ),
 'calendar'[Date]< MIN ( 'calendar'[Date] )
 )
 )
 ),
 [PreviousSales] = 0
 )
)

а вот так вернувшийся клиент:

COUNTROWS (
 CALCULATETABLE (
 VALUES ( mysql_transactions_facts[userPhone] ),
 VALUES ( mysql_transactions_facts[userPhone]),
 FILTER (
 ALL ( 'calendar' ),
 'calendar'[Date]< MIN ( 'calendar'[Date] )
 )
 )
)

Как искать аутлаеров

В PBI:

Создаем отдельную табличку:

without_outliers = FILTER(SUMMARIZE(Query1;Query1[card];"count";COUNT(Query1[card]));[count]<40)

С помощью SUMMARIZE создаем сводную табличку и фильтруем аутлаеров с помощью FILTER

Потом связываем

 

В R:

boxplot(dataset$count)
out = boxplot(dataset$count)$out
out_data = as.data.frame(out)

 

 

Настройка удаленного сервера для работы

Вводная часть здесь: https://data36.com/data-coding-101-install-python-sql-r-bash/

R лучше устанавливать по этому туториалу: https://www.digitalocean.com/community/tutorials/how-to-install-r-on-ubuntu-16-04-2

Rstudio также отсюда https://data36.com/data-coding-101-install-python-sql-r-bash/ , только можно версию по свежее.

Mysql по этому туториалу: https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04 Там же нужно будет создать юзера для mysql , можно сделать это вот так https://www.digitalocean.com/community/tutorials/mysql-ru

 

 

 

Как скачать данные из GA c помощью R и сохранить в MySQL на своей машине

План прост:

1. Поставить Mysql на машину
2. Создать там нужное бд и таблицы
3. Загрузить данные за позавчерашний день через R
4. Настроить скрипт загрузки с динамическими датами http://sotnik.biz.ua/blog/ppc_in_power_bi/
5. Запустить по крону его через 5 минут https://2steps.pro/r-script-launching-with-task-scheduler.html
6. Если все ок, то ставим крон на 9.30

 

 

1. Поставить Mysql на машину

Скачиваем mysql-installer-web-community-5.7.19.0 и следуем установщику. Если что, то гуглим.

Чтобы войти в мускул:

mysql -u root -p

2. Создать там нужное бд и таблицы

Так как кодировка R и винды cp1251, то нужно создать дб в этой же кодировки.

Важно чтобы кодировка в скрипте и в БД была одинаковая. Проверить кодировку в R можно так Sys.getlocale()

CREATE DATABASE organic_data1 CHARACTER SET cp1251 COLLATE cp1251_general_ci;

А затем нужные таблицы:

CREATE TABLE ga_organic_data(
 date DATE,
 sourceMedium VARCHAR(256),
 landingPagePath VARCHAR(256),
 deviceCategory VARCHAR(256),
 hostname VARCHAR(256),
 sessions INTEGER,
 transactions INTEGER,
 transactionRevenue DECIMAL
 );

3. Загрузить данные за позавчерашний день через R

Коннектимся к бд и загружаем:

conMySQL1 <- dbConnect(MySQL(), dbname = "organic_data1", user = "root", password = "makarovs", host = "localhost",port=3306)

dbWriteTable (conMySQL1, "ga_organic_data", ga_organic_data, row.names = FALSE, append = TRUE)

Сложность была в определении hostname и имени пользователя. Помогла статья: https://stackoverflow.com/questions/4093603/how-do-i-find-out-my-mysql-url-host-port-and-username 

4. Настроить скрипт загрузки с динамическими датами

library(RMySQL)
library("googleAuthR")
library("googleAnalyticsR")
library("jsonlite")


conMySQL1 <- dbConnect(MySQL(), dbname = "organic_data1", user = "root", password = "makarovs", host = "localhost",port=3306)

old_data <- dbReadTable(conMySQL1, "ga_organic_data")
last_date <- max(old_data$date)
start_date <- as.character.Date(as.Date(last_date)+1)
end_date <- as.character.Date(Sys.Date() - 1)


# Сюда вставить то, что в json-файле. Обязательно заменить обратный слеш \ на двойной \\
json <- '{

}
'

# функция для авторизации
gar_auth_service <- function(json, scope = getOption("googleAuthR.scopes.selected")){
 
 endpoint <- httr::oauth_endpoints("google")
 
 secrets <- jsonlite::fromJSON(json)
 scope <- paste(scope, collapse=" ")
 
 if(is.null(secrets$private_key)){
 stop("$private_key not found in JSON - have you downloaded the correct JSON file? 
 (Service Account Keys, not service account client)")
 }
 
 google_token <- httr::oauth_service_token(endpoint, secrets, scope)
 
 Authentication$set("public", "token", google_token, overwrite=TRUE)
 Authentication$set("public", "method", "service_json", overwrite=TRUE)
 
 return(invisible(Authentication$public_fields$token))
 
 }

# авторизируемся
gar_auth_service(
 json = json,
 scope = "https://www.googleapis.com/auth/analytics"
)

# id представления GA
ga_view <- '46195197'


df <- dim_filter("sourceMedium","REGEXP","(google / organic|yandex / organic)")
fc <- filter_clause_ga4(list(df))


# Выгружаем данные
ga_organic_data <- google_analytics_4(ga_view, 
 date_range = c(start_date,end_date),
 dimensions=c('date','sourceMedium','landingPagePath','deviceCategory','hostname'), 
 metrics = c('sessions','transactions','transactionRevenue'),
 dim_filters = fc,
 anti_sample = TRUE)


dbWriteTable (conMySQL1, "ga_organic_data", ga_organic_data, row.names = FALSE, append = TRUE)

dbDisconnect(conMySQL1)

5. Запустить по крону его через 5 минут 

 

Дебаг с помощью Google Tag Assistant

Врубаем record: http://joxi.ru/bmo6zYouxe5j4r и выполняем нужные действия, а потом смотрим отчет: http://joxi.ru/V2VRL5nSxRza72
Очень удобно смотреть что записалось в кастом деменшен или какая текущая кампания/канал. Также можно тестить кроссдоменное отслеживание.