Closest value to a specific column in R












14















I would like to find the closest value to column x3 below.



data=data.frame(x1=c(24,12,76),x2=c(15,30,20),x3=c(45,27,15))
data
x1 x2 x3
1 24 15 45
2 12 30 27
3 76 20 15


So desired output will be



Closest_Value_to_x3
24
30
20


Please help. Thank you










share|improve this question





























    14















    I would like to find the closest value to column x3 below.



    data=data.frame(x1=c(24,12,76),x2=c(15,30,20),x3=c(45,27,15))
    data
    x1 x2 x3
    1 24 15 45
    2 12 30 27
    3 76 20 15


    So desired output will be



    Closest_Value_to_x3
    24
    30
    20


    Please help. Thank you










    share|improve this question



























      14












      14








      14


      2






      I would like to find the closest value to column x3 below.



      data=data.frame(x1=c(24,12,76),x2=c(15,30,20),x3=c(45,27,15))
      data
      x1 x2 x3
      1 24 15 45
      2 12 30 27
      3 76 20 15


      So desired output will be



      Closest_Value_to_x3
      24
      30
      20


      Please help. Thank you










      share|improve this question
















      I would like to find the closest value to column x3 below.



      data=data.frame(x1=c(24,12,76),x2=c(15,30,20),x3=c(45,27,15))
      data
      x1 x2 x3
      1 24 15 45
      2 12 30 27
      3 76 20 15


      So desired output will be



      Closest_Value_to_x3
      24
      30
      20


      Please help. Thank you







      r dataframe closest






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 23 at 13:36









      markus

      14.3k11236




      14.3k11236










      asked Jan 23 at 13:24









      melikmelik

      17012




      17012
























          4 Answers
          4






          active

          oldest

          votes


















          13














          Use max.col(-abs(data[, 3] - data[, -3])) to find the column positions of the closest values and use this result as part of a matrix to extract desired values from your data. The matrix is returned by cbind



          col <- 3
          data[, -col][cbind(1:nrow(data),
          max.col(-abs(data[, col] - data[, -col])))]
          #[1] 24 30 20





          share|improve this answer


























          • Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

            – Rich Scriven
            Jan 23 at 20:25













          • @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

            – markus
            Jan 23 at 20:32



















          4














          Here is another approach using matrixStats



          x <- as.matrix(data[,-3L])
          y <- abs(x - .subset2(data, 3L))
          x[matrixStats::rowMins(y) == y]
          # [1] 24 30 20




          Or in base using vapply



          x <- as.matrix(data[,-3L])
          y <- abs(x - .subset2(data, 3L))
          vapply(1:nrow(data),
          function(k) x[k,][which.min(y[k,])],
          numeric(1))
          # [1] 24 30 20





          share|improve this answer

































            3














            A tidyverse solution:



            data %>%
            rowid_to_column() %>%
            gather(var, val, -c(x3, rowid)) %>%
            mutate(temp = x3 - val) %>%
            group_by(rowid) %>%
            filter(abs(temp) == min(abs(temp))) %>%
            ungroup() %>%
            select(val)

            val
            <dbl>
            1 24
            2 30
            3 20


            First, it adds a row ID. Second, it transforms the data from wide to long. Third, it calculates the difference between "x3" and the other variables. Finally, it groups by the row ID and keeps the rows where the absolute difference is the smallest.



            Or:



            data %>%
            rowid_to_column() %>%
            gather(var, val, -c(x3, rowid)) %>%
            mutate(temp = x3 - val) %>%
            group_by(rowid) %>%
            filter(abs(temp) == min(abs(temp))) %>%
            ungroup() %>%
            pull(val)

            [1] 24 30 20


            Or using an approach originally proposed by @markus (it assumes that your columns are named "x"):



            data %>%
            mutate(temp = paste0("x", max.col(-abs(.[, -3] - .[, 3])))) %>%
            rowwise() %>%
            summarise(val = eval(as.symbol(temp)))

            val
            <dbl>
            1 24.
            2 30.
            3 20.


            First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest and combines it with "x". Then, it evaluates the combination of x and column index as a variable and returns the appropriate value.



            Also borrowing the idea from @markus (not assuming that your columns are named "x"):



            data %>%
            mutate(temp = max.col(-abs(.[, -3] - .[, 3]))) %>%
            rowwise %>%
            mutate(temp = names(.)[[temp]]) %>%
            summarise(val = eval(as.symbol(temp)))


            First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest. Second, it returns the column name based on the column index. Finally, it evaluates it as a variable and returns the appropriate value.



            Or a variant where you can reference the "x3" variable by its name and not by column index (the basic idea still from @markus):



            data %>%
            mutate(temp = max.col(-abs(.[, !grepl("x3", colnames(.))] - .[, grepl("x3", colnames(.))]))) %>%
            rowwise %>%
            mutate(temp = names(.)[[temp]]) %>%
            summarise(val = eval(as.symbol(temp)))





            share|improve this answer


























            • I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

              – NelsonGon
              Jan 23 at 14:19








            • 1





              @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

              – tmfmnk
              Jan 23 at 14:30








            • 1





              This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

              – Konrad Rudolph
              Jan 23 at 17:19






            • 1





              @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

              – Konrad Rudolph
              Jan 24 at 9:57








            • 1





              "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

              – RLave
              Jan 24 at 10:56



















            2














            Define a function closest_to_3 that operates on a vector and returns the value in the vector that's closest to the third member:



            closest_to_3 <- function(v) v[-3][which.min(abs( v[-3]-v[3] ))]


            (The idiom v[-3] deletes the 3rd member from v.) Then apply this function to each row of your data frame:



            apply(data, 1, closest_to_3)
            #[1] 24 30 20





            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54328301%2fclosest-value-to-a-specific-column-in-r%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              13














              Use max.col(-abs(data[, 3] - data[, -3])) to find the column positions of the closest values and use this result as part of a matrix to extract desired values from your data. The matrix is returned by cbind



              col <- 3
              data[, -col][cbind(1:nrow(data),
              max.col(-abs(data[, col] - data[, -col])))]
              #[1] 24 30 20





              share|improve this answer


























              • Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

                – Rich Scriven
                Jan 23 at 20:25













              • @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

                – markus
                Jan 23 at 20:32
















              13














              Use max.col(-abs(data[, 3] - data[, -3])) to find the column positions of the closest values and use this result as part of a matrix to extract desired values from your data. The matrix is returned by cbind



              col <- 3
              data[, -col][cbind(1:nrow(data),
              max.col(-abs(data[, col] - data[, -col])))]
              #[1] 24 30 20





              share|improve this answer


























              • Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

                – Rich Scriven
                Jan 23 at 20:25













              • @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

                – markus
                Jan 23 at 20:32














              13












              13








              13







              Use max.col(-abs(data[, 3] - data[, -3])) to find the column positions of the closest values and use this result as part of a matrix to extract desired values from your data. The matrix is returned by cbind



              col <- 3
              data[, -col][cbind(1:nrow(data),
              max.col(-abs(data[, col] - data[, -col])))]
              #[1] 24 30 20





              share|improve this answer















              Use max.col(-abs(data[, 3] - data[, -3])) to find the column positions of the closest values and use this result as part of a matrix to extract desired values from your data. The matrix is returned by cbind



              col <- 3
              data[, -col][cbind(1:nrow(data),
              max.col(-abs(data[, col] - data[, -col])))]
              #[1] 24 30 20






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Feb 18 at 8:23

























              answered Jan 23 at 13:30









              markusmarkus

              14.3k11236




              14.3k11236













              • Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

                – Rich Scriven
                Jan 23 at 20:25













              • @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

                – markus
                Jan 23 at 20:32



















              • Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

                – Rich Scriven
                Jan 23 at 20:25













              • @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

                – markus
                Jan 23 at 20:32

















              Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

              – Rich Scriven
              Jan 23 at 20:25







              Nice answer. Although I don't think the outside [, 1:2] subset is necessary since you've already done that subset inside the abs() call.

              – Rich Scriven
              Jan 23 at 20:25















              @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

              – markus
              Jan 23 at 20:32





              @RichScriven Thanks for your comment. I guess I included it in case OP changes their mind and want's to find the closest values to, say, column 1, in which case we'd need the [, 2:3] subset.

              – markus
              Jan 23 at 20:32













              4














              Here is another approach using matrixStats



              x <- as.matrix(data[,-3L])
              y <- abs(x - .subset2(data, 3L))
              x[matrixStats::rowMins(y) == y]
              # [1] 24 30 20




              Or in base using vapply



              x <- as.matrix(data[,-3L])
              y <- abs(x - .subset2(data, 3L))
              vapply(1:nrow(data),
              function(k) x[k,][which.min(y[k,])],
              numeric(1))
              # [1] 24 30 20





              share|improve this answer






























                4














                Here is another approach using matrixStats



                x <- as.matrix(data[,-3L])
                y <- abs(x - .subset2(data, 3L))
                x[matrixStats::rowMins(y) == y]
                # [1] 24 30 20




                Or in base using vapply



                x <- as.matrix(data[,-3L])
                y <- abs(x - .subset2(data, 3L))
                vapply(1:nrow(data),
                function(k) x[k,][which.min(y[k,])],
                numeric(1))
                # [1] 24 30 20





                share|improve this answer




























                  4












                  4








                  4







                  Here is another approach using matrixStats



                  x <- as.matrix(data[,-3L])
                  y <- abs(x - .subset2(data, 3L))
                  x[matrixStats::rowMins(y) == y]
                  # [1] 24 30 20




                  Or in base using vapply



                  x <- as.matrix(data[,-3L])
                  y <- abs(x - .subset2(data, 3L))
                  vapply(1:nrow(data),
                  function(k) x[k,][which.min(y[k,])],
                  numeric(1))
                  # [1] 24 30 20





                  share|improve this answer















                  Here is another approach using matrixStats



                  x <- as.matrix(data[,-3L])
                  y <- abs(x - .subset2(data, 3L))
                  x[matrixStats::rowMins(y) == y]
                  # [1] 24 30 20




                  Or in base using vapply



                  x <- as.matrix(data[,-3L])
                  y <- abs(x - .subset2(data, 3L))
                  vapply(1:nrow(data),
                  function(k) x[k,][which.min(y[k,])],
                  numeric(1))
                  # [1] 24 30 20






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 23 at 14:12

























                  answered Jan 23 at 13:47









                  natenate

                  3,1411321




                  3,1411321























                      3














                      A tidyverse solution:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      select(val)

                      val
                      <dbl>
                      1 24
                      2 30
                      3 20


                      First, it adds a row ID. Second, it transforms the data from wide to long. Third, it calculates the difference between "x3" and the other variables. Finally, it groups by the row ID and keeps the rows where the absolute difference is the smallest.



                      Or:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      pull(val)

                      [1] 24 30 20


                      Or using an approach originally proposed by @markus (it assumes that your columns are named "x"):



                      data %>%
                      mutate(temp = paste0("x", max.col(-abs(.[, -3] - .[, 3])))) %>%
                      rowwise() %>%
                      summarise(val = eval(as.symbol(temp)))

                      val
                      <dbl>
                      1 24.
                      2 30.
                      3 20.


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest and combines it with "x". Then, it evaluates the combination of x and column index as a variable and returns the appropriate value.



                      Also borrowing the idea from @markus (not assuming that your columns are named "x"):



                      data %>%
                      mutate(temp = max.col(-abs(.[, -3] - .[, 3]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest. Second, it returns the column name based on the column index. Finally, it evaluates it as a variable and returns the appropriate value.



                      Or a variant where you can reference the "x3" variable by its name and not by column index (the basic idea still from @markus):



                      data %>%
                      mutate(temp = max.col(-abs(.[, !grepl("x3", colnames(.))] - .[, grepl("x3", colnames(.))]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))





                      share|improve this answer


























                      • I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                        – NelsonGon
                        Jan 23 at 14:19








                      • 1





                        @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                        – tmfmnk
                        Jan 23 at 14:30








                      • 1





                        This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                        – Konrad Rudolph
                        Jan 23 at 17:19






                      • 1





                        @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                        – Konrad Rudolph
                        Jan 24 at 9:57








                      • 1





                        "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                        – RLave
                        Jan 24 at 10:56
















                      3














                      A tidyverse solution:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      select(val)

                      val
                      <dbl>
                      1 24
                      2 30
                      3 20


                      First, it adds a row ID. Second, it transforms the data from wide to long. Third, it calculates the difference between "x3" and the other variables. Finally, it groups by the row ID and keeps the rows where the absolute difference is the smallest.



                      Or:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      pull(val)

                      [1] 24 30 20


                      Or using an approach originally proposed by @markus (it assumes that your columns are named "x"):



                      data %>%
                      mutate(temp = paste0("x", max.col(-abs(.[, -3] - .[, 3])))) %>%
                      rowwise() %>%
                      summarise(val = eval(as.symbol(temp)))

                      val
                      <dbl>
                      1 24.
                      2 30.
                      3 20.


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest and combines it with "x". Then, it evaluates the combination of x and column index as a variable and returns the appropriate value.



                      Also borrowing the idea from @markus (not assuming that your columns are named "x"):



                      data %>%
                      mutate(temp = max.col(-abs(.[, -3] - .[, 3]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest. Second, it returns the column name based on the column index. Finally, it evaluates it as a variable and returns the appropriate value.



                      Or a variant where you can reference the "x3" variable by its name and not by column index (the basic idea still from @markus):



                      data %>%
                      mutate(temp = max.col(-abs(.[, !grepl("x3", colnames(.))] - .[, grepl("x3", colnames(.))]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))





                      share|improve this answer


























                      • I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                        – NelsonGon
                        Jan 23 at 14:19








                      • 1





                        @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                        – tmfmnk
                        Jan 23 at 14:30








                      • 1





                        This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                        – Konrad Rudolph
                        Jan 23 at 17:19






                      • 1





                        @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                        – Konrad Rudolph
                        Jan 24 at 9:57








                      • 1





                        "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                        – RLave
                        Jan 24 at 10:56














                      3












                      3








                      3







                      A tidyverse solution:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      select(val)

                      val
                      <dbl>
                      1 24
                      2 30
                      3 20


                      First, it adds a row ID. Second, it transforms the data from wide to long. Third, it calculates the difference between "x3" and the other variables. Finally, it groups by the row ID and keeps the rows where the absolute difference is the smallest.



                      Or:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      pull(val)

                      [1] 24 30 20


                      Or using an approach originally proposed by @markus (it assumes that your columns are named "x"):



                      data %>%
                      mutate(temp = paste0("x", max.col(-abs(.[, -3] - .[, 3])))) %>%
                      rowwise() %>%
                      summarise(val = eval(as.symbol(temp)))

                      val
                      <dbl>
                      1 24.
                      2 30.
                      3 20.


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest and combines it with "x". Then, it evaluates the combination of x and column index as a variable and returns the appropriate value.



                      Also borrowing the idea from @markus (not assuming that your columns are named "x"):



                      data %>%
                      mutate(temp = max.col(-abs(.[, -3] - .[, 3]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest. Second, it returns the column name based on the column index. Finally, it evaluates it as a variable and returns the appropriate value.



                      Or a variant where you can reference the "x3" variable by its name and not by column index (the basic idea still from @markus):



                      data %>%
                      mutate(temp = max.col(-abs(.[, !grepl("x3", colnames(.))] - .[, grepl("x3", colnames(.))]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))





                      share|improve this answer















                      A tidyverse solution:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      select(val)

                      val
                      <dbl>
                      1 24
                      2 30
                      3 20


                      First, it adds a row ID. Second, it transforms the data from wide to long. Third, it calculates the difference between "x3" and the other variables. Finally, it groups by the row ID and keeps the rows where the absolute difference is the smallest.



                      Or:



                      data %>%
                      rowid_to_column() %>%
                      gather(var, val, -c(x3, rowid)) %>%
                      mutate(temp = x3 - val) %>%
                      group_by(rowid) %>%
                      filter(abs(temp) == min(abs(temp))) %>%
                      ungroup() %>%
                      pull(val)

                      [1] 24 30 20


                      Or using an approach originally proposed by @markus (it assumes that your columns are named "x"):



                      data %>%
                      mutate(temp = paste0("x", max.col(-abs(.[, -3] - .[, 3])))) %>%
                      rowwise() %>%
                      summarise(val = eval(as.symbol(temp)))

                      val
                      <dbl>
                      1 24.
                      2 30.
                      3 20.


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest and combines it with "x". Then, it evaluates the combination of x and column index as a variable and returns the appropriate value.



                      Also borrowing the idea from @markus (not assuming that your columns are named "x"):



                      data %>%
                      mutate(temp = max.col(-abs(.[, -3] - .[, 3]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))


                      First, it is assessing the column index of the variable where the absolute difference in regard to "x3" is the smallest. Second, it returns the column name based on the column index. Finally, it evaluates it as a variable and returns the appropriate value.



                      Or a variant where you can reference the "x3" variable by its name and not by column index (the basic idea still from @markus):



                      data %>%
                      mutate(temp = max.col(-abs(.[, !grepl("x3", colnames(.))] - .[, grepl("x3", colnames(.))]))) %>%
                      rowwise %>%
                      mutate(temp = names(.)[[temp]]) %>%
                      summarise(val = eval(as.symbol(temp)))






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Jan 24 at 6:23

























                      answered Jan 23 at 14:00









                      tmfmnktmfmnk

                      3,0371514




                      3,0371514













                      • I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                        – NelsonGon
                        Jan 23 at 14:19








                      • 1





                        @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                        – tmfmnk
                        Jan 23 at 14:30








                      • 1





                        This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                        – Konrad Rudolph
                        Jan 23 at 17:19






                      • 1





                        @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                        – Konrad Rudolph
                        Jan 24 at 9:57








                      • 1





                        "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                        – RLave
                        Jan 24 at 10:56



















                      • I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                        – NelsonGon
                        Jan 23 at 14:19








                      • 1





                        @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                        – tmfmnk
                        Jan 23 at 14:30








                      • 1





                        This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                        – Konrad Rudolph
                        Jan 23 at 17:19






                      • 1





                        @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                        – Konrad Rudolph
                        Jan 24 at 9:57








                      • 1





                        "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                        – RLave
                        Jan 24 at 10:56

















                      I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                      – NelsonGon
                      Jan 23 at 14:19







                      I like that I can always count on you for a tidyverse approach but sometimes they look so complex and intimidating. Great all the same!

                      – NelsonGon
                      Jan 23 at 14:19






                      1




                      1





                      @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                      – tmfmnk
                      Jan 23 at 14:30







                      @NelsonGon sometimes it gets really verbose, that is true. But that is also true that the tidyverse aprroaches in general are not the ones with the shortest code. Anyway, thank you for your compliment :)

                      – tmfmnk
                      Jan 23 at 14:30






                      1




                      1





                      This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                      – Konrad Rudolph
                      Jan 23 at 17:19





                      This is a tidyverse solution, not the only one, and not one I'd write. You can make the code a lot less verbose by following the natural logic of the other answer, no need to reshape the data.

                      – Konrad Rudolph
                      Jan 23 at 17:19




                      1




                      1





                      @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                      – Konrad Rudolph
                      Jan 24 at 9:57







                      @tmfmnk You’re completely right but just to clarify, I think in this case you’re torturing dplyr, and it confesses to anything. You could do a simpler single mutate: data %>% mutate(d = .[, -3][cbind(row_number(), max.col(- abs(.[, 3] - .[, -3])))]) — I’d be tempted to introduce a temporary column to hold the result of max.col but otherwise that’s it.

                      – Konrad Rudolph
                      Jan 24 at 9:57






                      1




                      1





                      "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                      – RLave
                      Jan 24 at 10:56





                      "I think in this case you’re torturing dplyr, and it confesses to anything", this could be on fortunes.

                      – RLave
                      Jan 24 at 10:56











                      2














                      Define a function closest_to_3 that operates on a vector and returns the value in the vector that's closest to the third member:



                      closest_to_3 <- function(v) v[-3][which.min(abs( v[-3]-v[3] ))]


                      (The idiom v[-3] deletes the 3rd member from v.) Then apply this function to each row of your data frame:



                      apply(data, 1, closest_to_3)
                      #[1] 24 30 20





                      share|improve this answer




























                        2














                        Define a function closest_to_3 that operates on a vector and returns the value in the vector that's closest to the third member:



                        closest_to_3 <- function(v) v[-3][which.min(abs( v[-3]-v[3] ))]


                        (The idiom v[-3] deletes the 3rd member from v.) Then apply this function to each row of your data frame:



                        apply(data, 1, closest_to_3)
                        #[1] 24 30 20





                        share|improve this answer


























                          2












                          2








                          2







                          Define a function closest_to_3 that operates on a vector and returns the value in the vector that's closest to the third member:



                          closest_to_3 <- function(v) v[-3][which.min(abs( v[-3]-v[3] ))]


                          (The idiom v[-3] deletes the 3rd member from v.) Then apply this function to each row of your data frame:



                          apply(data, 1, closest_to_3)
                          #[1] 24 30 20





                          share|improve this answer













                          Define a function closest_to_3 that operates on a vector and returns the value in the vector that's closest to the third member:



                          closest_to_3 <- function(v) v[-3][which.min(abs( v[-3]-v[3] ))]


                          (The idiom v[-3] deletes the 3rd member from v.) Then apply this function to each row of your data frame:



                          apply(data, 1, closest_to_3)
                          #[1] 24 30 20






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 23 at 20:06









                          grand_chatgrand_chat

                          24111




                          24111






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54328301%2fclosest-value-to-a-specific-column-in-r%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

                              Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

                              A Topological Invariant for $pi_3(U(n))$