1

This is my first post so I hope it is not too elementary. I am trying to match observations which have a negative Amount to counterparts that have a positive Amount and an equal abs(Amount). Furthermore, I want to check that the Amounts are both from the same Account. To do this, I am trying to use a for loop, but am getting the following error: "Operations are possibly only for numeric, logical or complex types." This is my code so far:

for(i in 1:nrow(data)){
  for(j in 1:nrow(data)){
    if ((data$Amount[i]=abs(data$Amount[j]))&(data$Amount[i]!=data$Amount[j])&(data$Account[i]=data$Account[j]))
    {data$debit[i]<-1}}}

Does anyone have any idea why this is happening, or know of a better way using the Apply function family? Thank you in advance!

EDIT: Below is a toy data set: to illustrate this example. For instance, on this data set, I want to create an indicator variable which would be 0 except for ID=3 because for the observation, 4.7=abs(-4.7) and "abc1"="abc1" .

Data <- "   ID        Amount      Account 
            1          5.0         abc1          
            2         -5.0         abc9          
            3          4.7         abc1        
            4          4.6         abc7          
            5          5.0         abc8          
            6         -4.7         abc1    "
pestopasta
  • 51
  • 6
  • 1
    Please include a sample of your dataframe to make it easier for others to help you by letting them run the code, you can refer to this for your question format: https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example – Amanda Jun 12 '18 at 23:04
  • Updated per your suggestion - please let me know if the provided data is sufficient. – pestopasta Jun 13 '18 at 00:49

2 Answers2

1

You need to use the == operator (= is an assignment operator) and the && rather than the & operator for your logical condition:

## Assignment (incorrect in this case!)
1 = 1
# Error in 1 = 1 : invalid (do_set) left-hand side to assignment
a <- 1
a = a

Note that with a = a there is no logical checked (just the equivalent of a <- a; see more here).

## Checking equivalence (returns a logical)
1 == 1
# [1] TRUE
a == a
# [1] TRUE

For the difference between & and &&, the second evaluates the full condition and the first each element (see here).

Also it might be more elegant to check whether the sum of data$Amount[i] and data$Amount[j] is null rather than to check if they have the first absolute value but not the same signed value.

## Your example
for(i in 1:nrow(data)){
  for(j in 1:nrow(data)){
    if ( (sum(c(data$Amount[i], data$Amount[j])) == 0) && (data$Account[i] == data$Account[j]) ) {
            data$debit[i]<-1
        }
    }
}
Thomas Guillerme
  • 1,747
  • 4
  • 16
  • 23
1

Here's an alternative method of achieving the same result with a lot less code (and I think it's easier to read too)

library(dplyr)
Data <- Data %>%
  group_by(Account) %>%
  mutate(
    debit = (Amount > 0 & -Amount %in% unique(Amount)) * 1
  ) %>%
  ungroup()

If you aren't familiar with the pipe operator (%>%), it allows us to avoid nesting a lot of functions inside one another. It works by taking the output of the previous function, and entering it as the first argument of the next function. So this code takes the data set (Data), groups it by the Account, adds a new column with the indicator variable with the desired criterion, and then ungroups the data so it's back to its normal format.

The looping is done within these function calls, which allows them to be implemented in compiled languages (usually C++) - which can be a lot faster than R.

Melissa Key
  • 4,476
  • 12
  • 21
  • Thank you for your response! When I do the above, where does debit save in memory? Why is it that I can't append Data[4]<-debit – pestopasta Jun 13 '18 at 19:47
  • You perform assignment exactly as you did before - using `<-`. See my updated answer where I update `Data` to add debit. In my original answer, `debit` was added to a version of the data set that was posted to the screen, but nothing actually was saved (similar to the result you get if you just write `mean(Data$Account)` - the calculated result is posted to the screen, but not saved unless you assign it to something. – Melissa Key Jun 13 '18 at 19:57