-1

假设我有一个关于小额贷款商店的数据集,我想了解其贷款被质押证券覆盖的情况。问题是,我为一笔贷款质押了多份证券,为多笔贷款质押了一份证券:

cAID cID cLoan sID sAmount
1   10  50   200 100    1100
2   11  50  1000 100    1100
3   12  60  1000 110     900
4   12  60  1000 120     300
5   14  80  1000 140    1200
6   15  90  1000 150     900

分配给贷款的担保金额不应超过贷款,如果担保高于贷款,并且有另一笔由该担保支持的贷款,则应将剩余部分分配给它。

理想情况下,我希望它最终是这样的:

cAIDa cIDa cLoanA sIDa sAmountA asignedSAmountA CoverageRatio
1    10   50    200  100     1100             200           1.0
2    11   50   1000  100     1100             900           0.9
3    12   60   1000  110      900            1000           1.0
4    12   60   1000  120      300            1000           1.0
5    14   80   1000  140     1200            1000           1.0
6    15   90   1000  150      900             900           0.9

如何在 R 或 Excel 中生成这两个其他列?基本上最后我想要唯一的客户账户 ID 和分配的证券总和,而不会超过证券。第一笔原始贷款是 200 (cLoanA),保证金 (sAmountA) 是 1100,因此分配的保证金是贷款的最大值 (asignedSAmountA),因此是 200,但下一笔贷款使用相同的保证金(注意相同的 sIDa),它是 1100,我们第一次贷款减去 200,剩下 900,因为第二行 cLoanA 为 1000,更高,因此我们使用全额保证金,比率为 0.9,这意味着部分是无抵押的。这就是我在 asignedSAmountA 和 Coverage ratio 中导出前几个数字的方法。

我在 R 中的代码:`

#example client AccountID
cAIDa <- c(10, 11, 12, 12, 14, 15)
#example client AccountID
cAIDa <- c(10, 11, 12, 12, 14, 15)
#example client ID
cIDa <- c(50, 50, 60, 60, 80, 90)
#example loan amount
cLoanA <- c(200, 1000, 1000, 1000, 1000, 1000)
#example security pledged ID
sIDa <- c(100, 100, 110, 120, 140, 150)
#example security pledged Amount
sAmountA <- c(1100,1100,900,300,1200, 900)

# generate initial data.frame 
portfolioOne <- data.frame(cAIDa,cIDa,cLoanA,sIDa,sAmountA)
portfolioOne

#assign security sum by unique account id
asignedSAmountA <- c(200, 900, 1200, 1200, 1000, 900)
portfolioTwo <- data.frame(cAIDa,cIDa,cLoanA,sIDa,sAmountA, asignedSAmountA)
ratio1 <- asignedSAmountA/portfolioOne$cLoanA
portfolioTwo$CoverageRatio <- ratio1
portfolioTwo
4

2 回答 2

4

好的,现在我明白你想要什么了。

以下是我从您的原始数据中得到的结果:

    cAIDa  cIDa cLoanA  sIDa sAmountA asignedSAmountA  CoverageRatio
    10      50    200   100    1100         200             1.0
    11      50   1000   100    1100         900             0.9
    12      60   1000   110     900        1000             1.0
    12      60   1000   120     300        1000             1.0
    14      80   1000   140    1200        1000             1.0
    15      90   1000   150     900         900             0.9

这是我运行的 VBA 宏:

Option Explicit
Sub AllocateSecurity()
    Dim colSec As Collection
    Dim dSec() As Double
    Dim dSecIndex() As Double
    Dim colLoan As Collection
    Dim dLoan() As Double
    Dim dLoanIndex() As Double
    Dim rSrc As Range, vSrc As Variant
    Dim vRes() As Variant
    Dim i As Long, j As Long, d As Double, v As Variant
    Dim rDest As Range

Set rDest = Range("J1")

'Get Original Data
Set rSrc = Range("A1", Cells(Rows.Count, "A").End(xlUp)) _
    .Resize(columnsize:=5)
vSrc = rSrc

'Securities
Set colSec = New Collection
On Error Resume Next
For i = 2 To UBound(vSrc)
    colSec.Add Item:=vSrc(i, 4), Key:=CStr(vSrc(i, 4))
Next i
On Error GoTo 0
ReDim dSec(1 To colSec.Count, 0 To 1)
ReDim dSecIndex(1 To colSec.Count)
For i = 1 To colSec.Count
    dSec(i, 0) = colSec(i)
    dSecIndex(i) = colSec(i)
    dSec(i, 1) = WorksheetFunction.VLookup(colSec(i), _
        Range(rSrc.Columns(4), rSrc.Columns(5)), 2, False)
Next i

'Loans
Set colLoan = New Collection
On Error Resume Next
For i = 2 To UBound(vSrc)
    colLoan.Add Item:=vSrc(i, 1), Key:=CStr(vSrc(i, 1))
Next i
On Error GoTo 0
ReDim dLoan(1 To colLoan.Count, 0 To 1)
ReDim dLoanIndex(1 To colLoan.Count)
For i = 1 To colLoan.Count
    dLoan(i, 0) = colLoan(i)
    dLoanIndex(i) = colLoan(i)
    'covered amt
    dLoan(i, 1) = WorksheetFunction.VLookup(colLoan(i), _
        rSrc, 3, False)
Next i


'Set up Results Array
ReDim vRes(1 To UBound(vSrc), 1 To UBound(vSrc, 2) + 2)

'Headers
v = Array("cAIDa", "cIDa", "cLoanA", "sIDa", "sAmountA", "asignedSAmountA", "CoverageRatio")
For i = 0 To UBound(v)
    vRes(1, i + 1) = v(i)
Next i

With WorksheetFunction
For i = 2 To UBound(vSrc)
    For j = 1 To UBound(vSrc, 2)
        vRes(i, j) = vSrc(i, j)
    Next j
    'LOAN = VSRC(I,1)
    'LOANAMT = DLOAN(.MATCH(LOAN,DLOANINDEX,0),1)
    'SEC = VSRC(I,4)
    'SECAMT = DSEC(.MATCH(SEC,DSECINDEX,0),1)
        'assSecamt
        vRes(i, 6) = .Min(dSec(.Match(vSrc(i, 4), dSecIndex, 0), 1), dLoan(.Match(vSrc(i, 1), dLoanIndex, 0), 1))
        'reduce loan and sec
        dLoan(.Match(vSrc(i, 1), dLoanIndex, 0), 1) = dLoan(.Match(vSrc(i, 1), dLoanIndex, 0), 1) - vRes(i, 6)
        dSec(.Match(vSrc(i, 4), dSecIndex, 0), 1) = dSec(.Match(vSrc(i, 4), dSecIndex, 0), 1) - vRes(i, 6)
Next i
End With

'coverage ratio:  1 - (uncovered amt/ orig amt)
'adjust assigned amt
With WorksheetFunction
For i = 2 To UBound(vRes)
    vRes(i, 7) = 1 - (dLoan(.Match(vRes(i, 1), dLoanIndex, 0), 1) / vRes(i, 3))
    vRes(i, 6) = vRes(i, 3) * vRes(i, 7)
Next i
End With

Set rDest = rDest.Resize(rowsize:=UBound(vRes), columnsize:=UBound(vRes, 2))

    Application.ScreenUpdating = False
rDest.EntireColumn.Clear
rDest = vRes
rDest.Columns(7).NumberFormat = "0.0"
rDest.EntireColumn.AutoFit
    Application.ScreenUpdating = True

End Sub
于 2013-10-12T20:48:39.147 回答
1

读取样本数据集:

portfolioOne <- read.table(text="
  cAID cID cLoan sID sAmount
1   10  50   200 100    1100
2   11  50  1000 100    1100
3   12  60  1000 110     900
4   12  60  1000 120     300
5   14  80  1000 140    1200
6   15  90  1000 150     900
")

从您的示例中可以看出,我们并不关心贷款是从哪个特定的保证金中支付的。因此,让我们创建一个列详细说明一个帐户的总保证金cID。然后我们可以通过贷款对它进行累积求和以获得运行余额,从而找到哪些贷款被覆盖/未被覆盖。

请注意,我通过使用该duplicated函数查找冗余行来避免重复计算金额。对于保证金,我按子集排除了它们。对于贷款,我将冗余条目设置为 0,以便累积总和达到正确的长度。

一个data.table解决方案:

library(data.table)
dat <- data.table(portfolioOne)
dat[, sTotal := sum(sAmount[!duplicated(sID)]), by = cID]
dat[, cLoanCum := cumsum({x <- cLoan; x[duplicated(cAID)] <- 0; x}), by = cID]
dat[, balance := sTotal - cLoanCum, by = cID]
dat[, assignedAmount := ifelse(balance >= 0, cLoan, pmax(0,cLoan + balance))]
dat[, CoverageRatio := assignedAmount / cLoan]

## delete intermediate columns if desired
dat[, c("sTotal","cLoanCum","balance") := NULL]
dat
   # cAID cID cLoan sID sAmount assignedAmount CoverageRatio
# 1:   10  50   200 100    1100            200           1.0
# 2:   11  50  1000 100    1100            900           0.9
# 3:   12  60  1000 110     900           1000           1.0
# 4:   12  60  1000 120     300           1000           1.0
# 5:   14  80  1000 140    1200           1000           1.0
# 6:   15  90  1000 150     900            900           0.9

一个plyr解决方案:

library(plyr)
dat <- portfolioOne
dat <- ddply(dat, .(cID), mutate, 
    sTotal = sum(sAmount[!duplicated(sID)]),
    cLoanCum = cumsum({x <- cLoan; x[duplicated(cAID)] <- 0; x}),
    balance = sTotal - cLoanCum,
    assignedAmount = ifelse(balance >= 0, cLoan, pmax(0,cLoan + balance)),
    CoverageRatio = assignedAmount / cLoan
)
dat <- dat[,!(names(dat) %in% c("sTotal","cLoanCum","balance"))]

使用基础 R 的解决方案:

dat <- split(portfolioOne, portfolioOne$cID)
dat <- lapply(dat, within, {
    sTotal = sum(sAmount[!duplicated(sID)])
    cLoanCum = cumsum({x <- cLoan; x[duplicated(cAID)] <- 0; x})
    balance = sTotal - cLoanCum
    assignedAmount = ifelse(balance >= 0, cLoan, pmax(0,cLoan + balance))
    CoverageRatio = assignedAmount / cLoan
})
dat <- do.call(rbind, dat)
dat <- dat[,c(names(portfolioOne),"assignedAmount","CoverageRatio")]
于 2013-10-13T09:17:14.120 回答