Here are three ways to transform the price column of a data frame, treating rows with different values in the name column separately. I don't have the Winsorize() function, so I used scale(), which sets the mean of the values to zero and the standard deviation to one.
DF <- data.frame(name = rep(c("Model1", "Model2", "Model3"),4),
price = runif(n = 12,min = 25,max = 100))
DF
#> name price
#> 1 Model1 90.54648
#> 2 Model2 76.48961
#> 3 Model3 36.07650
#> 4 Model1 27.95938
#> 5 Model2 43.13003
#> 6 Model3 33.33270
#> 7 Model1 62.58777
#> 8 Model2 54.85340
#> 9 Model3 60.32941
#> 10 Model1 82.00785
#> 11 Model2 96.41996
#> 12 Model3 64.20060
#Method 1. Put all the results in three data frames with a for loop
for(Nm in unique(DF$name)) {
tmp <- DF[DF$name == Nm, ]
tmp$price <- scale(tmp$price)
assign(Nm, tmp)
}
Model1
#> name price
#> 1 Model1 0.8912794
#> 4 Model1 -1.3606422
#> 7 Model1 -0.1146918
#> 10 Model1 0.5840546
Model2
#> name price
#> 2 Model2 0.3714638
#> 5 Model2 -1.0421075
#> 8 Model2 -0.5453442
#> 11 Model2 1.2159878
Model3
#> name price
#> 3 Model3 -0.7740921
#> 6 Model3 -0.9452647
#> 9 Model3 0.7389261
#> 12 Model3 0.9804307
#method 2. Make data frames in a list and process them
DF_Split <- split(DF, DF$name)
DF_Split
#> $Model1
#> name price
#> 1 Model1 90.54648
#> 4 Model1 27.95938
#> 7 Model1 62.58777
#> 10 Model1 82.00785
#>
#> $Model2
#> name price
#> 2 Model2 76.48961
#> 5 Model2 43.13003
#> 8 Model2 54.85340
#> 11 Model2 96.41996
#>
#> $Model3
#> name price
#> 3 Model3 36.07650
#> 6 Model3 33.33270
#> 9 Model3 60.32941
#> 12 Model3 64.20060
DF_New2 <- lapply(DF_Split, function(DATA) DATA$price <- scale(DATA$price))
DF_New2
#> $Model1
#> [,1]
#> [1,] 0.8912794
#> [2,] -1.3606422
#> [3,] -0.1146918
#> [4,] 0.5840546
#> attr(,"scaled:center")
#> [1] 65.77537
#> attr(,"scaled:scale")
#> [1] 27.79275
#>
#> $Model2
#> [,1]
#> [1,] 0.3714638
#> [2,] -1.0421075
#> [3,] -0.5453442
#> [4,] 1.2159878
#> attr(,"scaled:center")
#> [1] 67.72325
#> attr(,"scaled:scale")
#> [1] 23.59951
#>
#> $Model3
#> [,1]
#> [1,] -0.7740921
#> [2,] -0.9452647
#> [3,] 0.7389261
#> [4,] 0.9804307
#> attr(,"scaled:center")
#> [1] 48.4848
#> attr(,"scaled:scale")
#> [1] 16.02949
#Method 3. Use dplyr functions and have the results in one data frame
#Notice the original row order is preserved
library(dplyr)
DF_New3 <- DF |> group_by(name) |> mutate(price = scale(price))
DF_New3
#> # A tibble: 12 × 2
#> # Groups: name [3]
#> name price[,1]
#> <chr> <dbl>
#> 1 Model1 0.891
#> 2 Model2 0.371
#> 3 Model3 -0.774
#> 4 Model1 -1.36
#> 5 Model2 -1.04
#> 6 Model3 -0.945
#> 7 Model1 -0.115
#> 8 Model2 -0.545
#> 9 Model3 0.739
#> 10 Model1 0.584
#> 11 Model2 1.22
#> 12 Model3 0.980
Created on 2024-02-24 with reprex v2.0.2
Your code didn't work because you are confusing the strings like "Model1" and the name of the data frame Model1 (with no quotes). In your for loop, the Nm variable takes the values "Model1", "Model", "Model3". Those are character values. The code Nm$price
will not work because Nm is a character variable, not a data frame. Model1$price
(where there are not quotes around Model1) does work because Model1 is the name of a data frame.