2014-10-06 3 views
6

У меня есть набор данных, который выглядит следующим образом.Mutate несколько столбцов в dataframe

bankname bankid year totass cash bond loans 
Bank A  1  1881 244789 7250 20218 29513 
Bank B  2  1881 195755 10243 185151 2800 
Bank C  3  1881 107736 13357 177612 NA 
Bank D  4  1881 170600 35000 20000 5000 
Bank E  5  1881 3200000 351266 314012 NA 

и я хочу вычислить некоторые коэффициенты на основе балансовых балансов. и я хочу, чтобы набор данных, чтобы посмотреть, как этот

bankname bankid year totass cash bond loans CashtoAsset BondtoAsset LoanstoAsset 
Bank A  1  1881 2447890 7250 202100 951300 0.002 0.082 0.388 
Bank B  2  1881 195755 10243 185151 2800 0.052 0.945 0.014 
Bank C  3  1881 107736 13357 177612 NA 0.123 1.648585431 NA 
Bank D  4  1881 170600 35000 20000 5000 0.205 0.117 0.029 
Bank E  5  1881 32000000 351266 314012 NA 0.0109 0.009 NA 

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

bankname <- c("Bank A","Bank B","Bank C","Bank D","Bank E") 
bankid <- c(1, 2, 3, 4, 5) 
year<- c(1881, 1881, 1881, 1881, 1881) 
totass <- c(244789, 195755, 107736, 170600, 32000000) 
cash<-c(7250,10243,13357,35000,351266) 
bond<-c(20218,185151,177612,20000,314012) 
loans<-c(29513,2800,NA,5000,NA) 
bankdata<-data.frame(bankname, bankid,year,totass, cash, bond, loans) 

Во-первых, я избавилась от ВПЛ в балансах.

cols <- c("totass", "cash", "bond", "loans") 
bankdata[cols][is.na(bankdata[cols])] <- 0 

Тогда я вычислить коэффициенты

library(dplyr) 
bankdata<-mutate(bankdata,CashtoAsset = cash/totass) 
bankdata<-mutate(bankdata,BondtoAsset = bond/totass) 
bankdata<-mutate(bankdata,loanstoAsset =loans/totass) 

Но вместо вычисления все эти соотношения построчно, я хочу, чтобы создать внешний вид, чтобы сделать это все сразу. В Stata, я бы сделал

foreach x of varlist cash bond loans { 
by bankid: gen `x'toAsset = `x'/ totass 
} 

Как бы это сделать?

+1

Мета-комментарий: При переводе с одного языка на другой, вам не нужно быть слишком буквальным. Циклы в Stata часто работают лучше, чем массивные вычисления в R. (Даже обратное может быть правдой: новички в Stata с других языков часто пытаются использовать петли над наблюдениями, которые редко бывают нужны.) –

+0

Я упрощаю свои переменные здесь, но в моем dataset, у меня есть более 20 категорий активов, поэтому использование цикла полезно. –

+0

У меня нет ничего против петель; аналогично, типичный пользователь R, несомненно, доволен 20 столбцами .... –

ответ

0

Возможно, вы делаете это немного сложнее, чем необходимо. Просто попробуйте это и посмотрите, дает ли он то, что вам нужно.

bankdata$CashtoAsset <- bankdata$cash/bankdata$totass 
bankdata$BondtoAsset <- bankdata$bond/bankdata$totass 
bankdata$loantoAsset <- bankdata$loans/bankdata$totass 
bankdata 

Урожайность это:

bankname bankid year totass cash bond loans CashtoAsset BondtoAsset loantoAsset 
1 Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
2 Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
3 Bank C  3 1881 107736 13357 177612  0 0.12397899 1.648585431 0.00000 
4 Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
5 Bank E  5 1881 32000000 351266 314012  0 0.01097706 0.009812875 0.00000000 

Это должно вам начать работу в правильном направлении.

0

Это один из недостатков dplyr: насколько я знаю, нет простого способа использовать его программно, а не интерактивно, без какого-либо «взлома», как прискорбная идиома eval(parse(text=foo)).

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

for (x in c("cash", "bond", "loans")) { 
    bankdata[sprintf("%stoAsset", x)] <- bankdata[x]/bankdata$totass # or, equivalently, bankdata["totass"] for a consistent "look" 
    ## can also replace `sprintf("%stoAsset", x)` with `paste0(c(x, "toAsset"))` or even `paste(x, "toAsset", collapse="") depending on what makes more sense to you. 
} 

Чтобы сделать все эту более Stata, как вы можете обернуть все это в within так:

bankdata <- within(bankdata, for (x in c("cash", "bond", "loans")) { 
    assign(x, get(x)/totass) 
}) 

, но это влечет за собой некоторые взлом с get и assign функциями, которые не являются как безопасно использовать в целом, хотя в вашем случае это, вероятно, не имеет большого значения. Например, я бы не рекомендовал попробовать подобные трюки с dplyr, потому что dplyr злоупотребляет нестандартными оценочными функциями R, и это, вероятно, больше проблем, чем того стоит. Для более быстрого и, вероятно, превосходного решения, проверьте пакет data.table, который (я думаю) позволит вам использовать синтаксис цикла Stata, как например, с частотой dplyr. Проверьте виньетку пакета на CRAN.

Также, вы действительно уверены, что хотите переписать NA записей на 0?

14

Update (по состоянию на 2 декабря 2017 года)

Так как я ответил на этот вопрос, я понял, что некоторые пользователи SO проверяли этот ответ.С тех пор пакет dplyr изменился. Поэтому я оставляю следующее обновление. Надеюсь, это поможет некоторым пользователям R узнать, как использовать mutate_at().

mutate_each() в настоящее время не рекомендуется. Вместо этого вы хотите использовать mutate_at(). Вы можете указать, в каких столбцах вы хотите применить свою функцию в .vars. Один из способов - использовать vars(). Другим является использование символьного вектора, содержащего имена столбцов, которые вы хотите применить к своей пользовательской функции в .fun. Другой - указать столбцы с номерами (например, 5: 7 в этом случае). Обратите внимание: если вы используете столбец для group_by(), вам нужно изменить количество позиций столбцов. Посмотрите this question.

bankdata %>% 
mutate_at(.funs = funs(toAsset = ./totass), .vars = vars(cash:loans)) 

bankdata %>% 
mutate_at(.funs = funs(toAsset = ./totass), .vars = c("cash", "bond", "loans")) 

bankdata %>% 
mutate_at(.funs = funs(toAsset = ./totass), .vars = 5:7) 

# bankname bankid year totass cash bond loans cash_toAsset bond_toAsset loans_toAsset 
#1 Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
#2 Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
#3 Bank C  3 1881 107736 13357 177612 NA 0.12397899 1.648585431   NA 
#4 Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
#5 Bank E  5 1881 32000000 351266 314012 NA 0.01097706 0.009812875   NA 

Я намеренно дал toAsset в пользовательскую функцию в .fun, так как это поможет мне организовать новые имена столбцов. Раньше я использовал rename(). Но я думаю, что в настоящем подходе гораздо проще очистить имена столбцов с помощью gsub(). Если приведенный выше результат сохраняется как out, вы хотите запустить следующий код, чтобы удалить _ в именах столбцов.

names(out) <- gsub(names(out), pattern = "_", replacement = "") 

Оригинальный ответ

Я думаю, что вы можете сэкономить набрав, таким образом, с dplyr. Недостатком является то, что вы переписываете деньги, облигации и кредиты.

bankdata %>% 
    group_by(bankname) %>% 
    mutate_each(funs(whatever = ./totass), cash:loans) 

# bankname bankid year totass  cash  bond  loans 
#1 Bank A  1 1881 244789 0.02961734 0.082593581 0.12056506 
#2 Bank B  2 1881 195755 0.05232561 0.945830247 0.01430359 
#3 Bank C  3 1881 107736 0.12397899 1.648585431   NA 
#4 Bank D  4 1881 170600 0.20515826 0.117233294 0.02930832 
#5 Bank E  5 1881 32000000 0.01097706 0.009812875   NA 

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

bankdata %>% 
    group_by(bankname) %>% 
    summarise_each(funs(whatever = ./totass), cash:loans) %>% 
    rename(cashtoAsset = cash, bondtoAsset = bond, loanstoAsset = loans) -> ana; 
    ana %>% 
    merge(bankdata,., by = "bankname") 

# bankname bankid year totass cash bond loans cashtoAsset bondtoAsset loanstoAsset 
#1 Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
#2 Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
#3 Bank C  3 1881 107736 13357 177612 NA 0.12397899 1.648585431   NA 
#4 Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
#5 Bank E  5 1881 32000000 351266 314012 NA 0.01097706 0.009812875   NA 
+0

Привет, Я пробую все разные варианты, размещенные здесь. Когда я попробовал свои коды, я понял. 'Ошибка: объект 'ana' не найден. Не могли бы вы объяснить мне, что происходит? Благодарю. –

+0

@HPark Я назначаю вывод объекту, ana в процессе трубопровода. Если этот подход не работает для вас, вы можете сделать это: ana <- bankdata%>% group_by (имя банка)%>% summaryise_each (funs (whatever = ./totass), cash: loans)%>% rename (cashtoAsset = денежные средства, облигации, связанные с облигациями, облигации, ссуды и займы); ana%>% merge (bankdata,., by = "имя банка") ' – jazzurro

0

Try:

for(i in 5:7){ 
    bankdata[,(i+3)] = bankdata[,i]/bankdata[,4] 
} 
names(bankdata)[(5:7)+3] = paste0(names(bankdata)[5:7], 'toAssest') 

Выход:

bankdata 
    bankname bankid year totass cash bond loans cashtoAssest bondtoAssest loanstoAssest 
1 Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
2 Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
3 Bank C  3 1881 107736 13357 177612  0 0.12397899 1.648585431 0.00000000 
4 Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
5 Bank E  5 1881 32000000 351266 314012  0 0.01097706 0.009812875 0.00000000 
2

Вот data.table решение.

library(data.table) 
setDT(bankdata) 
bankdata[, paste0(names(bankdata)[5:7], "toAsset") := 
      lapply(.SD, function(x) x/totass), .SDcols=5:7] 
bankdata 
# bankname bankid year totass cash bond loans cashtoAsset bondtoAsset loanstoAsset 
# 1: Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
# 2: Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
# 3: Bank C  3 1881 107736 13357 177612  0 0.12397899 1.648585431 0.00000000 
# 4: Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
# 5: Bank E  5 1881 32000000 351266 314012  0 0.01097706 0.009812875 0.00000000 
2

Apply и cbind

cbind(bankdata,apply(bankdata[,5:7],2, function(x) x/bankdata$totass)) 
names(bankdata)[8:10] <- paste0(names(bankdata)[5:7], 'toAssest’) 

> bankdata 
    bankname bankid year totass cash bond loans cashtoAssest bondtoAssest loanstoAssest 
1 Bank A  1 1881 244789 7250 20218 29513 0.02961734 0.082593581 0.12056506 
2 Bank B  2 1881 195755 10243 185151 2800 0.05232561 0.945830247 0.01430359 
3 Bank C  3 1881 107736 13357 177612 NA 0.12397899 1.648585431   NA 
4 Bank D  4 1881 170600 35000 20000 5000 0.20515826 0.117233294 0.02930832 
5 Bank E  5 1881 32000000 351266 314012 NA 0.01097706 0.009812875   NA 
Смежные вопросы