пʼятницю, 3 серпня 2012 р.

Аналіз інвестицій у технологічні компанії (Crunchbase з R та MongoDB).

При використанні пакету RMongo ми зіткнулися з обмеженнями при роботі з вкладеними структурами.
Тому якщо дані містять в собі інші вкладені підструкутри(що, власне, і притаманне MongoDB) доцільніше використовувати rmongodb.
В нашій базі містяться всі дані про компанії, які доступні на crunchbase.  Ознайомитись з інформацією про Facebook можна тут http://api.crunchbase.com/v/1/company/facebook.js.
Для аналізу нам будуть потрібні лише такі дані:
Назва компанії, сфера її діяльності, рік заснування, раунди фінансування цієї компанії, рік  та сума інвестицій у цьому раунді, кількість інвесторів та їх тип (фінансова організація, особа чи компанія).



Ці дані мають складну структуру:

name: Wetpaint
category: web
founded year: 2005
funding rounds:
1:
type of round: a
funded year: 2005
investors:
1:
type of investor: financial organization
name: Frazier Technology Ventures
2:
type of investor: financial organization
name: Trinity Ventures

Щоб провести подальший аналіз перетворимо отримані з MongoDB дані у датафрейм.
Для цього:
Встановимо rmongodb:
> install.packages(“rmongodb”)
> library(“rmongodb”)
Під'єднаємося до бази "crunch":
> mongo <- mongo.create(db = "crunch")
Вона знаходиться на локальній машині, тому використовуємо параметри з'єднання по замовчуванню.
Аргументи mongo.create():

  • host - хост та порт, де розташована MongoDB (хост за замовчуванням 127.0.0.1, порт 27017)
  • name - назви replset http://www.mongodb.org/display/DOCS/Replica+Sets
  • username - ім'я користувача
  • password - пароль користувача
  • db - назва бази даних
  • timeout – час в мілісекундах після якого якщо з'єднання не відбулось команда відміняється (по замовчуванню 0L)   

Якщо з'єднання відбулося успішно, виведемо кількість документів у колекції "company",  яка містить дані про компанії:
> if (mongo.is.connected(mongo)) {
+   print(mongo.count(mongo, "crunch.company"))
+ }
[1] 93194
Отже, маємо інформацію про 93194 компанії. Виберемо серед них ті, які були створені в період 2000-2011 роки та отримали фінансування. Опишемо наш запит та помістимо його у змінну query:
buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "total_money_raised")
mongo.bson.buffer.append(buf, "$ne", "$0")
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.start.object(buf, "founded_year")
mongo.bson.buffer.append(buf, "$gte", 2000)
mongo.bson.buffer.finish.object(buf)
query <- mongo.bson.from.buffer(buf)
Крім того, нам потрібні не всі дані про компанії, а лише набір, описаний вище. Тому визначимо поля, які потрібно вибрати та помістимо їх значення у поле fields:
buf <- mongo.bson.buffer.create()
mongo.bson.buffer.append(buf, "name", "true")
mongo.bson.buffer.append(buf, "category_code", "true")
mongo.bson.buffer.append(buf, "deadpooled_year", "true")
mongo.bson.buffer.append(buf, "funding_rounds.round_code", "true")
mongo.bson.buffer.append(buf, "funding_rounds.funded_year", "true")
mongo.bson.buffer.append(buf, "funding_rounds.raised_amount", "true")
mongo.bson.buffer.append(buf, "funding_rounds.investments.company.permalink", "true")
mongo.bson.buffer.append(buf, "funding_rounds.investments.financial_org.permalink", "true")
mongo.bson.buffer.append(buf, "funding_rounds.investments.person.permalink", "true")
fields <- mongo.bson.from.buffer(buf)
Підрахуємо кількість компаній, які відповідають критеріям, які описані в query та помістимо їх кількість у змінну count:
> mongo.count(mongo, "crunch.company", query)
[1] 9525
> count <- mongo.count(mongo, "crunch.company", query)
В публікації, присвяченій RMongo, ми вже рахували кількість компаній створених у цій період. Було засновано 43833 компаній, з них лише 20% отримали інвестиції.
Імпорт  з MongoDB відбувається за такою схемою:

  1. Отримуємо дані, які відповідають умовам нашого запиту використовуючи команду mongo.find(), результатом якої є об'єкт класу mongo.cursor”,
  2. Щоб видобути вміст mongo.cursor  використовуємо "mongo.cursor.value" в результаті отримуємо "mongo.bson" об'єкт,
  3. Перетворюємо "mongo.bson" у список.
Як бачимо, послідовність отримання даних аналогічна до MongoDB.
> cursor <- mongo.find(mongo, "crunch.company", query=query, field=fields, limit = count)

Обов'язкові аргументи mongo.find():
  • об'єкт, який створюється при з'єднанні з базою “mongo”,
  • колекція “company” в базі даних “crunch”,
  • запит, збережений в змінній “query”.
Додатково також можна вказати:
  • поля, які потрібно відобразити “fields”,
  • кількість записів у результаті “count” (по замовчуванню 1000),
  • як сортувати дані при відображенні,
  • скільки документів відкинути перед виконанням запиту,
  • особливі опції при виконанні запиту (await data, find slave тощо).   
Простий приклад отримання роботи з mongo.cursor:
while (mongo.cursor.next(cursor)){
  b <- mongo.cursor.value(cursor)    
  name <- mongo.bson.value (b, "name")
  category_code <- mongo.bson.value (b, "category_code") 
 }
Оскільки наші дані мають складну структуру, для перетворення їх на дата фрейм потрібно їх "розгорнути" починаючи з кінця (тобто починаючи з даних про інвесторів).
Тобто процедура наступна:

  1. Імпортувати дані використовуючи mongo.find(),
  2. Результат виконання перетворити на список(він в свою чергу буде містити вкладені списки), 
  3. "Розгорнути" отриманий список та  перетворити його на датафрейм.
Переглянути як це реалізовано можна на Github: https://github.com/energyfirefox/CrunchMongoR/blob/master/investments.R
Зауважу, що при перетвореннях списків та дата фреймів  використовувала пакет "plyr" який реалізує подібну до MapReduce стратегію. 
Отже, етап підготовки даних завершено.
Результат можна завантажити в .csv тут: 

З'ясуємо, який розподіл між типами інвесторів.

Очищуємо дані:
type_of_inv <- c("person", "financial_org", "company")
invest_companies <- invest_companies[invest_companies$investor_type %in% type_of_inv, ]
investorsdf <- invest_companies[ ,c("investor_type", "investor_name")]
investorsdf <- unique(investorsdf)
Та будуємо графік:
barplot(table(investorsdf$investor_type), main = "Types of investors")
Як бачимо, на ниві інвестицій найбільш чисельними є різні фінансові організації, за ними йдуть особи ("ангели"  і т.д.)


Як всі ці суб'єкти інвестують у різні галузі?


Групуємо дані за сферами:
types_of_investors <- aggregate(invest_companies$investor_type, by = list(invest_companies$investor_type, invest_companies$category_code), FUN = length)
Команда aggregate() є аналогом GROUP BY у SQL.
Будуємо графік кількості профінансованих компаній у різних сферах:
colnames(types_of_investors) <- c("type", "field", "count")
barchart(types_of_investors$type ~ types_of_investors$count | types_of_investors$field,
         xlab = "Count", main = "Funding by field")
Отже, фінансові організації не лише найчисельніша структура, але й найбільш активна у фінансуванні.

Визначимо найбільших інвесторів кожного типу:


> count_of_investors <- aggregate(invest_companies$investor_type, by = list(invest_companies$investor_name,invest_companies$investor_type), FUN = length)
> colnames(count_of_investors) <- c("name", "type", "count")
> 
> ## sorting count_of_investors by dec
> Ord <- order(count_of_investors$count, decreasing = TRUE)
> count_of_investors <- count_of_investors[Ord, ]
Поле count містить кількість здійснених вкладень (фінансування структури у компанію на різних етапах будемо вважати різними інвестиціями).
ТОП 10 осіб:
row.namesnamecount
17128ron-conway65
27028reid-hoffman45
35499david-cohen38
45476dave-mcclure34
56777naval-ravikant29
65725esther-dyson26
76287joshua-schachter25
85366chris-sacca23
95557david-tisch23
106336keith-rabois23
ТОП 10 компаній:

row.namesnamecount
1894techstars80
21048y-combinator62
3125betaworks41
4791seedcamp23
5193cisco18
6722qualcomm16
7772safeguard-scientifics14
8776salesforce13
950amazon12
10275ebay12



ТОП 10 фінансових організацій:
row.namesnamecount
14052sequoia-capital234
22029draper-fisher-jurvetson230
31100accel-partners229
42788intel-capital225
53409new-enterprise-associates212
62265first-round-capital178
72977kleiner-perkins-caufield-byers173
81459benchmark-capital162
92500greylock142
101470bessemer-venture-partners135


Перейдемо до аналізу раундів фінансування.
Дані про інвесторів нам вже не потрібні, відкидаємо їх:
> invest_companies2 <- invest_companies[ , c("name","category_code", "code_type", "raised_amount", "funded_year", "number_investors")]
> invest_companies2 <- unique(invest_companies2)

З'ясуємо, як мінялась сума фінансувань по роках.
Очищуємо дані:

invest_companies2 <- invest_companies2[invest_companies2$funded_year >= 2000, ]
invest_companies2 <- invest_companies2[invest_companies2$funded_year != "unknown year", ]
invest_companies2 <- invest_companies2[!is.na(invest_companies2$funded_year), ]
Суми фінансувань будемо рахувати в тисячах доларів:

> invest_companies2$raised_amount <- invest_companies2$raised_amount / 1000
Будуємо коробчасту діаграму для кожного року:
> boxplot(invest_companies2$raised_amount ~ invest_companies2$funded_year, outline= T,
+         xlab = "Year", ylab = "Raised amount (in thousands $)",
+         main = "Raised by years")
Велика кількість "викидів" не дозволяє детальніше побачити картину фінансування, тому побудуємо графік без "викидів":
> boxplot(invest_companies2$raised_amount ~ invest_companies2$funded_year, outline= F,
+         xlab = "Year", ylab = "Raised amount (in thousands $)",
+         main = "Raised by years")
>         )
Спостерігаємо зниження обсягу інвестицій після кризи 2008. З 2010 суми знову почали зростати.


Скільки компанії отримують на різних стадіях росту?
Дана схема ілюструє процес фінансового зростання компанії (джерело:  http://en.wikipedia.org/wiki/Seed_funding)
Першу стадію зростання ще називають "долиною смерті", оскільки більшість новостворених компаній припиняє свою діяльність, так і не отримавши прибутків.  Фінансування на цьому етапі: гранти, ангельські інвестиції та посів. 
Вийшовши з "долини смерті" компанії переходять у стадію стрімкого зростання (перший та другий транш інвестиції) та сповільнення росту (подальші транші інвестицій). Після цього виходять на ІРО.
Проаналізуємо розмір інвестицій на кожній стадії зростання:
Додамо поле "stage" до наших даних:
> invest_companies2 <- cbind( invest_companies2, "stage")
Виберемо дані першої фази (ангельські інвестиції, посів, гранти):
> invest_companies2 <- cbind( invest_companies2, "stage")
> inestments1 <- c("angel", "seed", "grant")
> invest_companies2vd <- invest_companies2[invest_companies2$code_type %in% inestments1 , ]
> invest_companies2vd$stage <- "stage 1"
Вище ми вже стикнулися з проблемою "викидів", тому одночасно будуємо графік з "викидами" та без:
> par(mfrow=c(1,2))
> boxplot(invest_companies2vd$raised_amount ~ invest_companies2vd$code_type, outline= T,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "With outliers")
> boxplot(invest_companies2vd$raised_amount ~ invest_companies2vd$code_type, outline= F,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "Without outliers")
Бачимо, що гранти мають найменший розмір, середній розмір посіву 250 000 $, а середній розмір ангельського фінансування 500 000 $.
Статистика для першої стадії (в тисячах доларів):
> summary(invest_companies2vd$raised_amount)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
     0.0     50.0    300.0    827.2    905.0 150000.0 

Аналогічні дії  для ранньої стадії росту:
> inestments2 <- c("a", "b")
> invest_companies2ab <- invest_companies2[invest_companies2$code_type %in% inestments2 , ]
> invest_companies2ab$stage <- "stage 2"
> ### remove exessive factors
> invest_companies2ab$code_type <- as.factor(as.character(invest_companies2ab$code_type))
> par(mfrow=c(1,2))
> boxplot(invest_companies2ab$raised_amount ~ invest_companies2ab$code_type, outline= T,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "With outliers")
> boxplot(invest_companies2ab$raised_amount ~ invest_companies2ab$code_type, outline= F,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "Without outliers")
Кошти другого траншу суттєво перевищують кошти першого, хоча й бувають винятки.
Статистика для стадії раннього зростання:
> summary(invest_companies2ab$raised_amount)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0    2600    5300    8441   10000  400000 

Поглянемо на пізню стадію росту:
> inestments3 <- c("c", "d", "e", "f")
> invest_companies2cd <- invest_companies2[invest_companies2$code_type %in% inestments3 , ]
> invest_companies2cd$stage <- "stage 3"
> ### remove exessive factors
> invest_companies2cd$code_type <- as.factor(as.character(invest_companies2cd$code_type))
> par(mfrow=c(1,2))
> boxplot(invest_companies2cd$raised_amount ~ invest_companies2cd$code_type, outline= T,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "With outliers")
> boxplot(invest_companies2cd$raised_amount ~ invest_companies2cd$code_type, outline= F,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "Without outliers")
І знову суми зростають з кожним раундом.
Статистика для цієї фази:
> summary(invest_companies2cd$raised_amount)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0    8000   13150   20470   22000  950000 
Розглянемо динаміку зростання коштів для трьох фаз:
Об'єднаємо всі дані разом:
> icompany <- rbind(invest_companies2ab, invest_companies2cd, invest_companies2vd)
Побудуємо результат з викидами і без:
> boxplot(icompany$raised_amount ~ icompany$stage, outline= T,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "With outliers")  
> boxplot(icompany$raised_amount ~ icompany$stage, outline= F,
+         xlab = "Round", ylab = "Raised amount (in thousands $)", main = "Without outliers")
Бачимо, що суми коштів на кожній стадії разюче відрізняються.
Отже,

  • найбільш активними інвесторами є фінансові організації;
  • лише 20% компаній отримують фінансування;
  • з кожним траншем суми інвестування значно збільшуються.

Немає коментарів:

Дописати коментар