Написание функций на R с учетом объема работ

Вот родной подход Spark, который не затрудняет имена столбцов. Он основан на aggregateByKey и использует словарь для сбора столбцов, которые отображаются для каждого ключа. Затем мы собираем все имена столбцов, чтобы создать окончательный файл данных. [Предварительная версия использовала jsonRDD после испускания словаря для каждой записи, но это более эффективно.] Ограничение на конкретный список столбцов или исключение таких, как XX, было бы легкой модификацией.

Производительность кажется хорошим даже на довольно больших столах. Я использую вариацию, которая подсчитывает количество раз, каждое из которых имеет переменное число событий для каждого идентификатора, генерируя один столбец для каждого типа события. Код в основном тот же, за исключением того, что для подсчета вхождений используется коллекция.Counter вместо dict в seqFn.

from pyspark.sql.types import *

rdd = sc.parallelize([('X01',41,'US',3),
                       ('X01',41,'UK',1),
                       ('X01',41,'CA',2),
                       ('X02',72,'US',4),
                       ('X02',72,'UK',6),
                       ('X02',72,'CA',7),
                       ('X02',72,'XX',8)])

schema = StructType([StructField('ID', StringType(), True),
                     StructField('Age', IntegerType(), True),
                     StructField('Country', StringType(), True),
                     StructField('Score', IntegerType(), True)])

df = sqlCtx.createDataFrame(rdd, schema)

def seqPivot(u, v):
    if not u:
        u = {}
    u[v.Country] = v.Score
    return u

def cmbPivot(u1, u2):
    u1.update(u2)
    return u1

pivot = (
    df
    .rdd
    .keyBy(lambda row: row.ID)
    .aggregateByKey(None, seqPivot, cmbPivot)
)
columns = (
    pivot
    .values()
    .map(lambda u: set(u.keys()))
    .reduce(lambda s,t: s.union(t))
)
result = sqlCtx.createDataFrame(
    pivot
    .map(lambda (k, u): [k] + [u.get(c) for c in columns]),
    schema=StructType(
        [StructField('ID', StringType())] + 
        [StructField(c, IntegerType()) for c in columns]
    )
)
result.show()

Производит:

ID  CA UK US XX  
X02 7  6  4  8   
X01 2  1  3  null
30
задан AakashM 23 July 2009 в 08:59
поделиться

4 ответа

If I know that I'm going to need a function parametrized by some values and called repeatedly, I avoid globals by using a closure:

make.fn2 <- function(a, b) {
    fn2 <- function(x) {
        return( x + a + b )
    }
    return( fn2 )
}

a <- 2; b <- 3
fn2.1 <- make.fn2(a, b)
fn2.1(3)    # 8
fn2.1(4)    # 9

a <- 4
fn2.2 <- make.fn2(a, b)
fn2.2(3)    # 10
fn2.1(3)    # 8

This neatly avoids referencing global variables, instead using the enclosing environment of the function for a and b. Modification of globals a and b doesn't lead to unintended side effects when fn2 instances are called.

36
ответ дан 28 November 2019 в 00:02
поделиться

Есть причина, по которой некоторые языки не допускают использование глобальных переменных: они могут легко привести к поломке кода.

Правила области видимости в R позволяют писать код ленивым способом - позволяя функции, использующие переменные в других средах, могут сэкономить вам время на вводе текста и отлично подходят для экспериментов в простых случаях.

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

В приведенном выше примере:

Лучшая практика - использовать fn1.

В качестве альтернативы, попробуйте что-нибудь вроде

 fn3 <- function(x)
   {
      if(!exists("a", envir=.GlobalEnv))
      {
         warning("Variable 'a' does not exist in the global environment")
         a <- 1
      }

      if(!exists("b", envir=.GlobalEnv))
      {
         warning("Variable 'b' does not exist in the global environment")
         b <- 2
      }

      x + a + b
   }
8
ответ дан 28 November 2019 в 00:02
поделиться

Использование глобальных переменных в большинстве языков не рекомендуется, и R не является исключением. Очень часто короткие функции используют короткие и общие имена переменных, которые могут быть заполнены в глобальной среде. Безопаснее всего: а) включить все переменные в определение функции б) , а не , чтобы назначать значения по умолчанию. Например, напишите f = function (a, b), а не f = function (a = 0, b = NA).

0
ответ дан 28 November 2019 в 00:02
поделиться

Возникает ли проблема, когда вы просто используете глобальную переменную в функции или когда вы пытаетесь присвоить переменную? Если это последнее, я подозреваю, что это потому, что вы не используете << - в качестве присваивания внутри функции. И хотя использование << - кажется темной стороной 1 , это может очень хорошо работать для ваших целей. В первом случае функция, вероятно, маскирует глобальную переменную.

Может помочь присвоение глобальным переменным имен таким образом, чтобы их было сложно замаскировать локально. например: global.pimultiples <- 1: 4 * pi

3
ответ дан 28 November 2019 в 00:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: