Π’ΠΎΠΊΡ€ΡƒΠ³ data.table

Π­Ρ‚Π° Π·Π°ΠΌΠ΅Ρ‚ΠΊΠ° Π±ΡƒΠ΄Π΅Ρ‚ интСрСсна для Ρ‚Π΅Ρ…, ΠΊΡ‚ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ‚Π°Π±Π»ΠΈΡ‡Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… для R β€” data.table, ΠΈ, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π΄ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ Π΅Π΅ примСнСния Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ….

Π’Π΄ΠΎΡ…Π½ΠΎΠ²ΠΈΠ²ΡˆΠΈΡΡŒ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ ΠΊΠΎΠ»Π»Π΅Π³ΠΈ, ΠΈ надСясь, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΡƒΠΆΠ΅ ΠΏΠΎΡ‡ΠΈΡ‚Π°Π»ΠΈ Π΅Π³ΠΎ ΡΡ‚Π°Ρ‚ΡŒΡŽ, ΠΏΡ€Π΅Π΄Π»Π°Π³Π°ΡŽ Π³Π»ΡƒΠ±ΠΆΠ΅ ΠΊΠΎΠΏΠ½ΡƒΡ‚ΡŒ Π² сторону ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΊΠΎΠ΄Π° ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π½Π° основС data.table.

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅: ΠΎΡ‚ΠΊΡƒΠ΄Π° ΠΈΠ΄Π΅Ρ‚ data.table?

Π›ΡƒΡ‡ΡˆΠ΅ всСго Π½Π°Ρ‡Π°Ρ‚ΡŒ знакомство с Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΈΠ·Π΄Π°Π»Π΅ΠΊΠ°, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ, со структур Π΄Π°Π½Π½Ρ‹Ρ…, ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ data.table (Π΄Π°Π»Π΅Π΅, Π”Π’).

Массив

Код

## arrays ---------

arrmatr <- array(1:20, c(4,5))

class(arrmatr)

typeof(arrmatr)

is.array(arrmatr)

is.matrix(arrmatr)

Одна ΠΈΠ· Ρ‚Π°ΠΊΠΈΡ… структур β€” это массив (?base::array). Как ΠΈ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… языках массивы здСсь ΠΌΠ½ΠΎΠ³ΠΎΠΌΠ΅Ρ€Π½Ρ‹. Однако интСрСсным являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Π²ΡƒΠΌΠ΅Ρ€Π½Ρ‹ΠΉ массив Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ свойства ΠΎΡ‚ класса ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ (?base::matrix), Π° ΠΎΠ΄Π½ΠΎΠΌΠ΅Ρ€Π½Ρ‹ΠΉ массив, Ρ‡Ρ‚ΠΎ Ρ‚ΠΎΠΆΠ΅ Π²Π°ΠΆΠ½ΠΎ, Π½Π΅ наслСдуСт ΠΎΡ‚ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° (?base::vector).

ΠŸΡ€ΠΈ этом Π½Π°Π΄ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…, содСрТащихся Π² ΠΊΠ°ΠΊΠΎΠΌ-Π»ΠΈΠ±ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π΅ слСдуСт ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ base::typeof, которая Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π΅ описаниС Ρ‚ΠΈΠΏΠ° согласно R Internals β€” ΠΎΠ±Ρ‰ΠΈΠΌ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»ΠΎΠΌ языка, связанным с ΠΏΠ΅Ρ€Π²ΠΎΡ€ΠΎΠ΄Π½Ρ‹ΠΌ C.

Π•Ρ‰Π΅ ΠΎΠ΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°, для опрСдСлСния класса ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, base::class, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π² случаС Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΎΠ² Π²Π΅ΠΊΡ‚ΠΎΡ€Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ (ΠΎΠ½ отличаСтся Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΎΡ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ, Π½ΠΎ позволяСт Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠ½ΡΡ‚ΡŒ Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…).

Бписок

Из Π΄Π²ΡƒΠΌΠ΅Ρ€Π½ΠΎΠ³ΠΎ массива, ΠΎΠ½ ΠΆΠ΅ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Π°, ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ списку (?base::list).

Код

## lists ------------------

mylist <- as.list(arrmatr)

is.vector(mylist)

is.list(mylist)

ΠŸΡ€ΠΈ этом происходят нСсколько Π²Π΅Ρ‰Π΅ΠΉ сразу:

  • БхлопываСтся Π²Ρ‚ΠΎΡ€ΠΎΠ΅ ΠΈΠ·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠ΅ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ ΠΈ список ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€.
  • Бписок, Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, наслСдуСт ΠΎΡ‚ этих классов. Надо ΠΈΠΌΠ΅Ρ‚ΡŒ Π² Π²ΠΈΠ΄Ρƒ, Ρ‡Ρ‚ΠΎ элСмСнту списка Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎ (скалярноС) Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ· ячСйки ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹-массива.

Благодаря Ρ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ список это Ρ‚Π°ΠΊΠΆΠ΅ ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€, ΠΊ Π½Π΅ΠΌΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΎΠ².

Π”Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌ

ΠžΡ‚ списка, ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ ΠΈΠ»ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌΡƒ (?base::data.frame).

Код

## data.frames ------------

df <- as.data.frame(arrmatr)
df2 <- as.data.frame(mylist)

is.list(df)

df$V6 <- df$V1 + df$V2

Π§Ρ‚ΠΎ Π² Π½Π΅ΠΌ интСрСсно: Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌ наслСдуСт ΠΎΡ‚ списка! Колонки Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌΠ° ΡΠ²Π»ΡΡŽΡ‚ΡΡ ячСйками списка. Π­Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π²Π°ΠΆΠ½ΠΎ Π² дальнСйшСм, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, примСняСмыС ΠΊ спискам.

data.table

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π”Π’ (?data.table::data.table) ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ· Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌΠ°, списка, Π²Π΅ΠΊΡ‚ΠΎΡ€Π° ΠΈΠ»ΠΈ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹. НапримСр, Π²ΠΎΡ‚ Ρ‚Π°ΠΊ (in place).

Код

## data.tables -----------------------
library(data.table)

data.table::setDT(df)

is.list(df)

is.data.frame(df)

is.data.table(df)

ПолСзно Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ, ΠΊΠ°ΠΊ ΠΈ Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌ, Π”Π’ наслСдуСт свойства списка.

Π”Π’ ΠΈ ΠΏΠ°ΠΌΡΡ‚ΡŒ

Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ всСх ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² R base, Π”Π’ ΠΏΠ΅Ρ€Π΅Π΄Π°ΡŽΡ‚ΡΡ ΠΏΠΎ ссылкС. Если Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² Π½ΠΎΠ²ΡƒΡŽ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ памяти, Π½ΡƒΠΆΠ½Π° функция data.table::copy Π»ΠΈΠ±ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ ΠΈΠ· старого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.

Код

df2 <- df

df[V1 == 1, V2 := 999]

data.table::fsetdiff(df, df2)

df2 <- data.table::copy(df)

df[V1 == 2, V2 := 999]

data.table::fsetdiff(df, df2)

На этом Π²Π²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΊ ΠΊΠΎΠ½Ρ†Ρƒ. Π”Π’ β€” это ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΈΠ΅ развития структур Π΄Π°Π½Π½Ρ‹Ρ… Π² R, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ прСимущСствСнно происходит Π·Π° счСт Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ ΠΈ ускорСния ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Π½Π°Π΄ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ класса Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌ. ΠŸΡ€ΠΈ этом сохраняСтся наслСдованиС ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²ΠΎΠ².

НСкоторыС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования свойств data.table

Как список…

Π˜Ρ‚Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎ строкам Π΄Π°Ρ‚Π°Ρ„Ρ€Π΅ΠΉΠΌΠ° ΠΈΠ»ΠΈ Π”Π’ Π½Π΅ Π»ΡƒΡ‡ΡˆΠ°Ρ идСя, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΠ΄ Ρ†ΠΈΠΊΠ»Π° Π½Π° языкС R Π³ΠΎΡ€Π°Π·Π΄Π½ΠΎ ΠΌΠ΅Π΄Π»Π΅Π½Π΅Π΅ C, Π° ΠΏΡ€ΠΎΠΉΡ‚ΠΈΡΡŒ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΏΠΎ столбцам, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ…, ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ, Π³ΠΎΡ€Π°Π·Π΄Π½ΠΎ мСньшС, Π²ΠΏΠΎΠ»Π½Π΅ ΠΌΠΎΠΆΠ½ΠΎ. Идя ΠΏΠΎ столбцам, ΠΏΠΎΠΌΠ½ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ столбСц это элСмСнт списка, содСрТащий, ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Π²Π΅ΠΊΡ‚ΠΎΡ€. А ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π°Π΄ Π²Π΅ΠΊΡ‚ΠΎΡ€Π°ΠΌΠΈ Ρ…ΠΎΡ€ΠΎΡˆΠΎ Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠ·ΠΎΠ²Π°Π½Ρ‹ Π² Π±Π°Π·ΠΎΠ²Ρ‹Ρ… функциях языка. Π’Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹ Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ, свойствСнныС спискам ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€Π°ΠΌ: `[[`, `$`.

Код

## operations on data.tables ------------

#using list properties

df$'V1'[1]

df[['V1']]

df[[1]][1]

sapply(df, class)

sapply(df, function(x) sum(is.na(x)))

ВСкторизация

Если Π΅ΡΡ‚ΡŒ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΎΠΉΡ‚ΠΈ ΠΏΠΎ строкам большого Π”Π’, Π»ΡƒΡ‡ΡˆΠΈΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ написаниС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ с Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ. Но Ссли это Π½Π΅ получаСтся, Ρ‚ΠΎ слСдуСт ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ†ΠΈΠΊΠ» Π²Π½ΡƒΡ‚Ρ€ΠΈ Π”Π’ всС Ρ€Π°Π²Π½ΠΎ быстрСС Ρ†ΠΈΠΊΠ»Π° Π² R, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ выполняСтся Π½Π° C.

ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½Π° бОльшСм ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ со 100К строк. Π‘ΡƒΠ΄Π΅ΠΌ Π²Ρ‹Ρ‚Π°ΡΠΊΠΈΠ²Π°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π²ΡƒΡŽ Π±ΡƒΠΊΠ²Ρƒ ΠΈΠ· слов, входящих Π² Π²Π΅ΠΊΡ‚ΠΎΡ€-ΠΊΠΎΠ»ΠΎΠ½ΠΊΡƒ w.

Updated

Код

library(magrittr)
library(microbenchmark)

## Bigger example ----

rown <- 100000

dt <- 
	data.table(
		w = sapply(seq_len(rown), function(x) paste(sample(letters, 3, replace = T), collapse = ' '))
		, a = sample(letters, rown, replace = T)
		, b = runif(rown, -3, 3)
		, c = runif(rown, -3, 3)
		, e = rnorm(rown)
	) %>%
	.[, d := 1 + b + c + rnorm(nrow(.))]

# vectorization

microbenchmark({
	dt[
		, first_l := unlist(strsplit(w, split = ' ', fixed = T))[1]
		, by = 1:nrow(dt)
	   ]
})

# second

first_l_f <- function(sd)
{
	strsplit(sd, split = ' ', fixed = T) %>%
		do.call(rbind, .) %>%
		`[`(,1)
}

dt[, first_l := NULL]

microbenchmark({
	dt[
		, first_l := .(first_l_f(w))
		]
})

# third

first_l_f2 <- function(sd)
{
	strsplit(sd, split = ' ', fixed = T) %>%
		unlist %>%
		matrix(nrow = 3) %>%
		`[`(1,)
}

dt[, first_l := NULL]

microbenchmark({
	dt[
		, first_l := .(first_l_f2(w))
		]
})

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΡ€ΠΎΠ³ΠΎΠ½ с ΠΈΡ‚Π΅Ρ€Π°Ρ†ΠΈΠ΅ΠΉ ΠΏΠΎ строкам:

Unit: milliseconds
expr min
{ dt[, `:=`(first_l, unlist(strsplit(w, split = " ", fixed = T))[1]), by = 1:nrow(dt)] } 439.6217
lq mean median uq max neval
451.9998 460.1593 456.2505 460.9147 621.4042 100

Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΠΏΡ€ΠΎΠ³ΠΎΠ½, Π³Π΄Π΅ вСкторизация ΠΈΠ΄Π΅Ρ‚ Ρ‡Π΅Ρ€Π΅Π· ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ списка Π² ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρƒ ΠΈ взятиС элСмСнтов Π½Π° срСзС с индСксом 1 (послСднСС ΠΈ Π΅ΡΡ‚ΡŒ собствСнно вСкторизация). ΠŸΠΎΠΏΡ€Π°Π²Π»ΡŽΡΡŒ: вСкторизация Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ strsplit, которая ΡƒΠΌΠ΅Π΅Ρ‚ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π²Π΅ΠΊΡ‚ΠΎΡ€ Π½Π° Π²Ρ…ΠΎΠ΄. ΠžΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ΡΡ, ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Π° прСвращСния списка Π² ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρƒ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ тяТСлСС самой Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, Π½ΠΎ ΠΈ Π² этом случаС Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ быстрСС Π½Π΅Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°.

Unit: milliseconds
expr min lq mean median uq max neval
{ dt[, `:=`(first_l, .(first_l_f(w)))] } 93.07916 112.1381 161.9267 149.6863 185.9893 442.5199 100

УскорСниС ΠΏΠΎ ΠΌΠ΅Π΄ΠΈΠ°Π½Π΅ Π² 3 Ρ€Π°Π·.

Π’Ρ€Π΅Ρ‚ΠΈΠΉ ΠΏΡ€ΠΎΠ³ΠΎΠ½, Π³Π΄Π΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Π° схСма прСвращСния Π² ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρƒ.

Unit: milliseconds
expr min lq mean median uq max neval
{ dt[, `:=`(first_l, .(first_l_f2(w)))] } 32.60481 34.13679 40.4544 35.57115 42.11975 222.972 100

УскорСниС ΠΏΠΎ ΠΌΠ΅Π΄ΠΈΠ°Π½Π΅ Π² 13 Ρ€Π°Π·.

Π‘ этим Π΄Π΅Π»ΠΎΠΌ Π½Π°Π΄ΠΎ ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, Ρ‡Π΅ΠΌ большС β€” Ρ‚Π΅ΠΌ Π»ΡƒΡ‡ΡˆΠ΅ Π±ΡƒΠ΄Π΅Ρ‚.

Π•Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ с Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ, Π³Π΄Π΅ Ρ‚Π°ΠΊΠΆΠ΅ тСкст, Π½ΠΎ ΠΎΠ½ ΠΏΡ€ΠΈΠ±Π»ΠΈΠΆΠ΅Π½ ΠΊ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌ условиям: разная Π΄Π»ΠΈΠ½Π° слов, Ρ€Π°Π·Π½ΠΎΠ΅ количСство слов. ВрСбуСтся Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π²Ρ‹Π΅ 3 слова. Π’ΠΎΡ‚ Ρ‚Π°ΠΊ:

Π’ΠΎΠΊΡ€ΡƒΠ³ data.table

Π—Π΄Π΅ΡΡŒ ΡƒΠΆΠ΅ прСдыдущая функция Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ Π²Π΅ΠΊΡ‚ΠΎΡ€Ρ‹ Ρ€Π°Π·Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹, Π° ΠΌΡ‹ Π·Π°Π΄Π°Π²Π°Π»ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹. ΠŸΠ΅Ρ€Π΅Π΄Π΅Π»Π°Π΅ΠΌ это, покопавшись Π² ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π°Ρ….

Код

# fourth

rown <- 100000

words <-
	sapply(
		seq_len(rown)
		, function(x){
			nwords <- rbinom(1, 10, 0.5)
			paste(
				sapply(
					seq_len(nwords)
					, function(x){
						paste(sample(letters, rbinom(1, 10, 0.5), replace = T), collapse = '')
					}
				)
				, collapse = ' '
			)
		}
	)

dt <- 
	data.table(
		w = words
		, a = sample(letters, rown, replace = T)
		, b = runif(rown, -3, 3)
		, c = runif(rown, -3, 3)
		, e = rnorm(rown)
	) %>%
	.[, d := 1 + b + c + rnorm(nrow(.))]

first_l_f3 <- function(sd, n)
{
	l <- strsplit(sd, split = ' ', fixed = T)
	
	maxl <- max(lengths(l))
	
	sapply(l, "length<-", maxl) %>%
		`[`(n,) %>%
		as.character
}

microbenchmark({
	dt[
		, (paste0('w_', 1:3)) := lapply(1:3, function(x) first_l_f3(w, x))
		]
})

dt[
	, (paste0('w_', 1:3)) := lapply(1:3, function(x) first_l_f3(w, x))
	]

Unit: milliseconds
expr min lq mean median

{ dt[, `:=`((paste0(Β«w_Β», 1:3)), strsplit(w, split = " ", fixed = T))] } 851.7623 916.071 1054.5 1035.199
uq max neval
1178.738 1356.816 100

Π‘ΠΊΡ€ΠΈΠΏΡ‚ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π» со срСднСй ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒΡŽ 1 сСкунда. НСплохо.

БвязанныС ΠΎΠ΄Π½ΠΎΠΉ Ρ†Π΅ΠΏΡŒΡŽ…

Π‘ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ Π”Π’ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ chaining. Выглядит это ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½ΠΈΠ΅ синтаксиса скобок справа, ΠΏΠΎ сути, сахарок.

Код

# chaining

res1 <- dt[a == 'a'][sample(.N, 100)]

res2 <- dt[, .N, a][, N]

res3 <- dt[, coefficients(lm(e ~ d))[1], a][, .(letter = a, coef = V1)]

Π’Π΅Ρ‡Π΅Ρ‚ ΠΏΠΎ Ρ‚Ρ€ΡƒΠ±Π°ΠΌ…

Π’Π°ΠΊΠΈΠ΅ ΠΆΠ΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· piping, выглядит ΠΏΠΎΡ…ΠΎΠΆΠ΅, Π½ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ Π±ΠΎΠ³Π°Ρ‡Π΅, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π»ΡŽΠ±Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, Π° Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π”Π’. Π’Ρ‹Π²Π΅Π΄Π΅ΠΌ коээфициСнты логистичСской рСгрСссии для Π½Π°ΡˆΠΈΡ… синтСтичСских Π΄Π°Π½Π½Ρ‹Ρ… с рядом Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ² Π½Π° Π”Π’.

Код

# piping

samplpe_b <- dt[a %in% head(letters), sample(b, 1)]

res4 <- 
	dt %>%
	.[a %in% head(letters)] %>%
	.[, 
	  {
	  	dt0 <- .SD[1:100]
	  	
	  	quants <- 
	  		dt0[, c] %>%
	  		quantile(seq(0.1, 1, 0.1), na.rm = T)
	  	
	  	.(q = quants)
	  }
	  , .(cond = b > samplpe_b)
	  ] %>%
	glm(
		cond ~ q -1
		, family = binomial(link = "logit")
		, data = .
	) %>%
	summary %>%
	.[[12]]

Бтатистика, машинноС ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΈ ΠΏΡ€ΠΎΡ‡Π΅Π΅ Π²Π½ΡƒΡ‚Ρ€ΠΈ Π”Π’

МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ лямбда-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π½ΠΎ ΠΈΠ½ΠΎΠ³Π΄Π° Π»ΡƒΡ‡ΡˆΠ΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈΡ… ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ, ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ вСсь ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ Π°Π½Π°Π»ΠΈΠ·Π° Π΄Π°Π½Π½Ρ‹Ρ…, ΠΈ Π²ΠΏΠ΅Ρ€Π΅Π΄ β€” ΠΎΠ½ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π²Π½ΡƒΡ‚Ρ€ΠΈ Π”Π’. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠ±ΠΎΠ³Π°Ρ‰Π΅Π½ всСми Π²Ρ‹ΡˆΠ΅ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»Π΅Π½Π½Ρ‹ΠΌΠΈ Ρ„ΠΈΡ‡Π°ΠΌΠΈ, плюс нСсколько ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… Π²Π΅Ρ‰Π΅ΠΉ ΠΈΠ· арсСнала Π”Π’ (Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ самому Π”Π’ Π²Π½ΡƒΡ‚Ρ€ΠΈ Π”Π’ ΠΏΠΎ ссылкС, вставлСнных ΠΈΠ½ΠΎΠ³Π΄Π° Π½Π΅ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Π½ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ‹Π»ΠΎ).

Код

# function

rm(lm_preds)

lm_preds <- function(
	sd, by, n
)
{
	
	if(
		n < 100 | 
		!by[['a']] %in% head(letters, 4)
	   )
	{
		
		res <-
			list(
				low = NA
				, mean = NA
				, high = NA
				, coefs = NA
			)
		
	} else {

		lmm <- 
			lm(
				d ~ c + b
				, data = sd
			)
		
		preds <- 
			stats::predict.lm(
				lmm
				, sd
				, interval = "prediction"
				)
		
		res <-
			list(
				low = preds[, 2]
				, mean = preds[, 1]
				, high = preds[, 3]
				, coefs = coefficients(lmm)
			)
	}

	res
	
}

res5 <- 
	dt %>%
	.[e < 0] %>%
	.[.[, .I[b > 0]]] %>%
	.[, `:=` (
		low = as.numeric(lm_preds(.SD, .BY, .N)[[1]])
		, mean = as.numeric(lm_preds(.SD, .BY, .N)[[2]])
		, high = as.numeric(lm_preds(.SD, .BY, .N)[[3]])
		, coef_c = as.numeric(lm_preds(.SD, .BY, .N)[[4]][1])
		, coef_b = as.numeric(lm_preds(.SD, .BY, .N)[[4]][2])
		, coef_int = as.numeric(lm_preds(.SD, .BY, .N)[[4]][3])
	)
	, a
	] %>%
	.[!is.na(mean), -'e', with = F]


# plot

plo <- 
	res5 %>%
	ggplot +
	facet_wrap(~ a) +
	geom_ribbon(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, ymin = low
			, ymax = high
			, fill = a
		)
		, size = 0.1
		, alpha = 0.1
	) +
	geom_point(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, y = mean
			, color = a
		)
		, size = 1
	) +
	geom_point(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, y = d
		)
		, size = 1
		, color = 'black'
	) +
	theme_minimal()

print(plo)

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Π― надСюсь, Ρ‡Ρ‚ΠΎ смог ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ†Π΅Π»ΡŒΠ½ΡƒΡŽ, Π½ΠΎ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½Π΅ ΠΏΠΎΠ»Π½ΡƒΡŽ, ΠΊΠ°Ρ€Ρ‚ΠΈΠ½Ρƒ Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΊΠ°ΠΊ data.table, начиная ΠΎΡ‚ Π΅Π³ΠΎ свойств связанных с наслСдованиСм ΠΎΡ‚ классов R ΠΈ заканчивая Π΅Π³ΠΎ собствСнными Ρ„ΠΈΡˆΠΊΠ°ΠΌΠΈ ΠΈ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ΠΌ ΠΈΠ· элСмСнтов tidyverse. НадСюсь, это ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Π²Π°ΠΌ Π»ΡƒΡ‡ΡˆΠ΅ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ эту Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ развлСчСния.

Π’ΠΎΠΊΡ€ΡƒΠ³ data.table

Бпасибо!

ΠŸΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄

Код

## load libs ----------------

library(data.table)
library(ggplot2)
library(magrittr)
library(microbenchmark)


## arrays ---------

arrmatr <- array(1:20, c(4,5))

class(arrmatr)

typeof(arrmatr)

is.array(arrmatr)

is.matrix(arrmatr)


## lists ------------------

mylist <- as.list(arrmatr)

is.vector(mylist)

is.list(mylist)


## data.frames ------------

df <- as.data.frame(arrmatr)

is.list(df)

df$V6 <- df$V1 + df$V2


## data.tables -----------------------

data.table::setDT(df)

is.list(df)

is.data.frame(df)

is.data.table(df)

df2 <- df

df[V1 == 1, V2 := 999]

data.table::fsetdiff(df, df2)

df2 <- data.table::copy(df)

df[V1 == 2, V2 := 999]

data.table::fsetdiff(df, df2)


## operations on data.tables ------------

#using list properties

df$'V1'[1]

df[['V1']]

df[[1]][1]

sapply(df, class)

sapply(df, function(x) sum(is.na(x)))


## Bigger example ----

rown <- 100000

dt <- 
	data.table(
		w = sapply(seq_len(rown), function(x) paste(sample(letters, 3, replace = T), collapse = ' '))
		, a = sample(letters, rown, replace = T)
		, b = runif(rown, -3, 3)
		, c = runif(rown, -3, 3)
		, e = rnorm(rown)
	) %>%
	.[, d := 1 + b + c + rnorm(nrow(.))]

# vectorization

# zero - for loop

microbenchmark({
	for(i in 1:nrow(dt))
		{
		dt[
			i
			, first_l := unlist(strsplit(w, split = ' ', fixed = T))[1]
		]
	}
})

# first

microbenchmark({
	dt[
		, first_l := unlist(strsplit(w, split = ' ', fixed = T))[1]
		, by = 1:nrow(dt)
	   ]
})

# second

first_l_f <- function(sd)
{
	strsplit(sd, split = ' ', fixed = T) %>%
		do.call(rbind, .) %>%
		`[`(,1)
}

dt[, first_l := NULL]

microbenchmark({
	dt[
		, first_l := .(first_l_f(w))
		]
})

# third

first_l_f2 <- function(sd)
{
	strsplit(sd, split = ' ', fixed = T) %>%
		unlist %>%
		matrix(nrow = 3) %>%
		`[`(1,)
}

dt[, first_l := NULL]

microbenchmark({
	dt[
		, first_l := .(first_l_f2(w))
		]
})

# fourth

rown <- 100000

words <-
	sapply(
		seq_len(rown)
		, function(x){
			nwords <- rbinom(1, 10, 0.5)
			paste(
				sapply(
					seq_len(nwords)
					, function(x){
						paste(sample(letters, rbinom(1, 10, 0.5), replace = T), collapse = '')
					}
				)
				, collapse = ' '
			)
		}
	)

dt <- 
	data.table(
		w = words
		, a = sample(letters, rown, replace = T)
		, b = runif(rown, -3, 3)
		, c = runif(rown, -3, 3)
		, e = rnorm(rown)
	) %>%
	.[, d := 1 + b + c + rnorm(nrow(.))]

first_l_f3 <- function(sd, n)
{
	l <- strsplit(sd, split = ' ', fixed = T)
	
	maxl <- max(lengths(l))
	
	sapply(l, "length<-", maxl) %>%
		`[`(n,) %>%
		as.character
}

microbenchmark({
	dt[
		, (paste0('w_', 1:3)) := lapply(1:3, function(x) first_l_f3(w, x))
		]
})

dt[
	, (paste0('w_', 1:3)) := lapply(1:3, function(x) first_l_f3(w, x))
	]


# chaining

res1 <- dt[a == 'a'][sample(.N, 100)]

res2 <- dt[, .N, a][, N]

res3 <- dt[, coefficients(lm(e ~ d))[1], a][, .(letter = a, coef = V1)]

# piping

samplpe_b <- dt[a %in% head(letters), sample(b, 1)]

res4 <- 
	dt %>%
	.[a %in% head(letters)] %>%
	.[, 
	  {
	  	dt0 <- .SD[1:100]
	  	
	  	quants <- 
	  		dt0[, c] %>%
	  		quantile(seq(0.1, 1, 0.1), na.rm = T)
	  	
	  	.(q = quants)
	  }
	  , .(cond = b > samplpe_b)
	  ] %>%
	glm(
		cond ~ q -1
		, family = binomial(link = "logit")
		, data = .
	) %>%
	summary %>%
	.[[12]]


# function

rm(lm_preds)

lm_preds <- function(
	sd, by, n
)
{
	
	if(
		n < 100 | 
		!by[['a']] %in% head(letters, 4)
	   )
	{
		
		res <-
			list(
				low = NA
				, mean = NA
				, high = NA
				, coefs = NA
			)
		
	} else {

		lmm <- 
			lm(
				d ~ c + b
				, data = sd
			)
		
		preds <- 
			stats::predict.lm(
				lmm
				, sd
				, interval = "prediction"
				)
		
		res <-
			list(
				low = preds[, 2]
				, mean = preds[, 1]
				, high = preds[, 3]
				, coefs = coefficients(lmm)
			)
	}

	res
	
}

res5 <- 
	dt %>%
	.[e < 0] %>%
	.[.[, .I[b > 0]]] %>%
	.[, `:=` (
		low = as.numeric(lm_preds(.SD, .BY, .N)[[1]])
		, mean = as.numeric(lm_preds(.SD, .BY, .N)[[2]])
		, high = as.numeric(lm_preds(.SD, .BY, .N)[[3]])
		, coef_c = as.numeric(lm_preds(.SD, .BY, .N)[[4]][1])
		, coef_b = as.numeric(lm_preds(.SD, .BY, .N)[[4]][2])
		, coef_int = as.numeric(lm_preds(.SD, .BY, .N)[[4]][3])
	)
	, a
	] %>%
	.[!is.na(mean), -'e', with = F]


# plot

plo <- 
	res5 %>%
	ggplot +
	facet_wrap(~ a) +
	geom_ribbon(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, ymin = low
			, ymax = high
			, fill = a
		)
		, size = 0.1
		, alpha = 0.1
	) +
	geom_point(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, y = mean
			, color = a
		)
		, size = 1
	) +
	geom_point(
		aes(
			x = c * coef_c + b * coef_b + coef_int
			, y = d
		)
		, size = 1
		, color = 'black'
	) +
	theme_minimal()

print(plo)

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com