Вопрос был:
Как вернуть ответ от асинхронного вызова?
, который может быть интерпретирован как:
Как сделать синхронный асинхронный код синхронным?
Решение будет состоять в том, чтобы избежать обратных вызовов и использовать комбинацию Promises и async / await.
Я хотел бы привести пример для запроса Ajax.
(Хотя он может быть записан в Javascript, я предпочитаю писать его на Python и компилировать его в Javascript, используя Transcrypt . Это будет достаточно ясно.)
Позволяет сначала включить использование JQuery, чтобы
$
был доступен какS
:__pragma__ ('alias', 'S', '$')
Определить функцию, которая возвращает Promise, в этом случае вызов Ajax:
def read(url: str): deferred = S.Deferred() S.ajax({'type': "POST", 'url': url, 'data': { }, 'success': lambda d: deferred.resolve(d), 'error': lambda e: deferred.reject(e) }) return deferred.promise()
Использовать асинхронный код, как если бы он был синхронным:
async def readALot(): try: result1 = await read("url_1") result2 = await read("url_2") except Exception: console.warn("Reading a lot failed")
Все, что вам нужно сделать, это снова применить множитель () к вашей переменной после подмножества:
> subdf$letters
[1] a b c
Levels: a b c d e
subdf$letters <- factor(subdf$letters)
> subdf$letters
[1] a b c
Levels: a b c
ИЗМЕНИТЬ
Пример примера с параметрами:
factor(ff) # drops the levels that do not occur
Для удаления уровней из всех столбцов факторов в кадре данных вы можете использовать:
subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)
Вот еще один способ, который, я считаю, эквивалентен подходу factor(..)
:
> df <- data.frame(let=letters[1:5], num=1:5)
> subdf <- df[df$num <= 3, ]
> subdf$let <- subdf$let[ , drop=TRUE]
> levels(subdf$let)
[1] "a" "b" "c"
Для полноты, теперь есть fct_drop
в пакете forcats
http://forcats.tidyverse.org/reference/fct_drop.html .
Он отличается от droplevels
тем, как он имеет дело с NA
:
f <- factor(c("a", "b", NA), exclude = NULL)
droplevels(f)
# [1] a b <NA>
# Levels: a b <NA>
forcats::fct_drop(f)
# [1] a b <NA>
# Levels: a b
Я написал служебные функции для этого. Теперь, когда я знаю о drop.levels gdata, он выглядит довольно похожим. Здесь они (из здесь ):
present_levels <- function(x) intersect(levels(x), x)
trim_levels <- function(...) UseMethod("trim_levels")
trim_levels.factor <- function(x) factor(x, levels=present_levels(x))
trim_levels.data.frame <- function(x) {
for (n in names(x))
if (is.factor(x[,n]))
x[,n] = trim_levels(x[,n])
x
}
Другой способ сделать то же самое, но с dplyr
library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)
Изменить:
Также работает! Благодаря agenis
subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)
здесь есть способ сделать это
varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]
Очень интересная нить, мне особенно понравилась идея просто подставить подзаголовок снова. Раньше у меня была аналогичная проблема, и я просто перешел к символу, а затем вернулся к коэффициенту.
df <- data.frame(letters=letters[1:5],numbers=seq(1:5))
levels(df$letters)
## [1] "a" "b" "c" "d" "e"
subdf <- df[df$numbers <= 3]
subdf$letters<-factor(as.character(subdf$letters))
Это известная проблема, и одно возможное решение предоставляется drop.levels()
в пакете gdata , где ваш пример становится
> drop.levels(subdf)
letters numbers
1 a 1
2 b 2
3 c 3
> levels(drop.levels(subdf)$letters)
[1] "a" "b" "c"
Существует также dropUnusedLevels
в пакете Hmisc . Однако он работает только путем изменения оператора подмножества [
и здесь неприменим.
В качестве следствия прямой подход на основе столбца является простым as.factor(as.character(data))
:
> levels(subdf$letters)
[1] "a" "b" "c" "d" "e"
> subdf$letters <- as.factor(as.character(subdf$letters))
> levels(subdf$letters)
[1] "a" "b" "c"
Если вы не хотите этого поведения, не используйте факторы, используйте вместо него векторы символов. Я думаю, что это имеет больше смысла, чем исправление. Попробуйте выполнить следующие действия перед загрузкой данных с помощью read.table
или read.csv
:
options(stringsAsFactors = FALSE)
Недостатком является то, что вы ограничены алфавитным порядком. (переупорядочить ваш друг для сюжетов)
Глядя на код droplevels
методов в источнике R, вы можете видеть , он обтекает функцию factor
. Это означает, что вы можете в основном воссоздать столбец с функцией factor
. Ниже data.table способ сбросить уровни из всех столбцов факторов.
library(data.table)
dt = data.table(letters=factor(letters[1:5]), numbers=seq(1:5))
levels(dt$letters)
#[1] "a" "b" "c" "d" "e"
subdt = dt[numbers <= 3]
levels(subdt$letters)
#[1] "a" "b" "c" "d" "e"
upd.cols = sapply(subdt, is.factor)
subdt[, names(subdt)[upd.cols] := lapply(.SD, factor), .SDcols = upd.cols]
levels(subdt$letters)
#[1] "a" "b" "c"
Это неприятно. Так я обычно делаю это, чтобы не загружать другие пакеты:
levels(subdf$letters)<-c("a","b","c",NA,NA)
, который получает вас:
> subdf$letters
[1] a b c
Levels: a b c
Обратите внимание, что новые уровни заменят все, что занимает их индекс в старые значения (subdf $ letters), поэтому что-то вроде:
levels(subdf$letters)<-c(NA,"a","c",NA,"b")
не будет работать.
Это, очевидно, не идеально, когда у вас много уровней, но для Несколько, это быстро и легко.
Поскольку R версии 2.12, есть функция droplevels()
.
levels(droplevels(subdf$letters))