Find column name at change of value










1















I have a dataset like this (reproducible)



X1 <- c(0,0,1,3)
X2 <- c(0,0,4,5)
X3 <- c(0,2,2,6)
X4 <- c(0,0,0,1)

df <- data.frame(rbind(X1, X2, X3, X4))
rownames(df) <- NULL
df

X1 X2 X3 X4
1 0 0 1 3
2 0 0 4 5
3 0 2 2 6
4 0 0 0 1


I want to add a column, which will take the value of the column name where, per row wise, value changed from 0 to any value greater than 0



Hence expected output is



 X1 X2 X3 X4 Value
1 0 0 1 3 X3
2 0 0 4 5 X3
3 0 2 2 6 X2
4 0 0 1 1 X4


How can I achieve this for each row?










share|improve this question



















  • 2





    Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

    – Henrik
    Nov 13 '18 at 9:28
















1















I have a dataset like this (reproducible)



X1 <- c(0,0,1,3)
X2 <- c(0,0,4,5)
X3 <- c(0,2,2,6)
X4 <- c(0,0,0,1)

df <- data.frame(rbind(X1, X2, X3, X4))
rownames(df) <- NULL
df

X1 X2 X3 X4
1 0 0 1 3
2 0 0 4 5
3 0 2 2 6
4 0 0 0 1


I want to add a column, which will take the value of the column name where, per row wise, value changed from 0 to any value greater than 0



Hence expected output is



 X1 X2 X3 X4 Value
1 0 0 1 3 X3
2 0 0 4 5 X3
3 0 2 2 6 X2
4 0 0 1 1 X4


How can I achieve this for each row?










share|improve this question



















  • 2





    Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

    – Henrik
    Nov 13 '18 at 9:28














1












1








1








I have a dataset like this (reproducible)



X1 <- c(0,0,1,3)
X2 <- c(0,0,4,5)
X3 <- c(0,2,2,6)
X4 <- c(0,0,0,1)

df <- data.frame(rbind(X1, X2, X3, X4))
rownames(df) <- NULL
df

X1 X2 X3 X4
1 0 0 1 3
2 0 0 4 5
3 0 2 2 6
4 0 0 0 1


I want to add a column, which will take the value of the column name where, per row wise, value changed from 0 to any value greater than 0



Hence expected output is



 X1 X2 X3 X4 Value
1 0 0 1 3 X3
2 0 0 4 5 X3
3 0 2 2 6 X2
4 0 0 1 1 X4


How can I achieve this for each row?










share|improve this question
















I have a dataset like this (reproducible)



X1 <- c(0,0,1,3)
X2 <- c(0,0,4,5)
X3 <- c(0,2,2,6)
X4 <- c(0,0,0,1)

df <- data.frame(rbind(X1, X2, X3, X4))
rownames(df) <- NULL
df

X1 X2 X3 X4
1 0 0 1 3
2 0 0 4 5
3 0 2 2 6
4 0 0 0 1


I want to add a column, which will take the value of the column name where, per row wise, value changed from 0 to any value greater than 0



Hence expected output is



 X1 X2 X3 X4 Value
1 0 0 1 3 X3
2 0 0 4 5 X3
3 0 2 2 6 X2
4 0 0 1 1 X4


How can I achieve this for each row?







r datatable






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 '18 at 9:18









Sotos

28.7k51640




28.7k51640










asked Nov 13 '18 at 9:13









Hardik guptaHardik gupta

1,95231136




1,95231136







  • 2





    Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

    – Henrik
    Nov 13 '18 at 9:28













  • 2





    Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

    – Henrik
    Nov 13 '18 at 9:28








2




2





Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

– Henrik
Nov 13 '18 at 9:28






Related: For each row return the column name of the largest value, where e.g. the max.col method is described.

– Henrik
Nov 13 '18 at 9:28













3 Answers
3






active

oldest

votes


















2














The Vectorized way to do it would be,



names(df)[max.col(df != 0, ties.method = 'first')]
#[1] "X3" "X3" "X2" "X4"


In addition, you can use apply with margin 1 (to do row operations), and find the first index where the diff is not 0, i.e.



names(df)[apply(df, 1, function(i) which(diff(i) != 0)[1]) + 1]
#[1] "X3" "X3" "X2" "X4"





share|improve this answer


















  • 2





    The vectorized way is a nice catch.

    – RLave
    Nov 13 '18 at 9:25


















1














Another option using apply again:



names(df)[apply(df, 1, function(x) which(x > 0)[1])]
# [1] "X3" "X3" "X2" "X4"





share|improve this answer






























    1














    A tidyverse solution:



    df %>%
    rowid_to_column() %>% #Creating an ID
    gather(var, val, -rowid) %>% #Transforming the data from wide to long
    arrange(rowid) %>% #Arranging according ID
    group_by(rowid) %>% #Grouping by ID
    mutate(res = ifelse(cumsum(val) > 0, paste0(var), NA)) %>% #Applying the condition
    filter(res == first(res[!is.na(res)])) %>% #Selecting the relevant value
    left_join(df %>% rowid_to_column(), by = c("rowid" = "rowid")) %>% #Joining with the original df
    ungroup() %>%
    select(-rowid, -var, -val) #Deleting the redundant variables

    res X1 X2 X3 X4
    <chr> <dbl> <dbl> <dbl> <dbl>
    1 X3 0. 0. 1. 3.
    2 X3 0. 0. 4. 5.
    3 X2 0. 2. 2. 6.
    4 X4 0. 0. 0. 1.





    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%2f53277485%2ffind-column-name-at-change-of-value%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      The Vectorized way to do it would be,



      names(df)[max.col(df != 0, ties.method = 'first')]
      #[1] "X3" "X3" "X2" "X4"


      In addition, you can use apply with margin 1 (to do row operations), and find the first index where the diff is not 0, i.e.



      names(df)[apply(df, 1, function(i) which(diff(i) != 0)[1]) + 1]
      #[1] "X3" "X3" "X2" "X4"





      share|improve this answer


















      • 2





        The vectorized way is a nice catch.

        – RLave
        Nov 13 '18 at 9:25















      2














      The Vectorized way to do it would be,



      names(df)[max.col(df != 0, ties.method = 'first')]
      #[1] "X3" "X3" "X2" "X4"


      In addition, you can use apply with margin 1 (to do row operations), and find the first index where the diff is not 0, i.e.



      names(df)[apply(df, 1, function(i) which(diff(i) != 0)[1]) + 1]
      #[1] "X3" "X3" "X2" "X4"





      share|improve this answer


















      • 2





        The vectorized way is a nice catch.

        – RLave
        Nov 13 '18 at 9:25













      2












      2








      2







      The Vectorized way to do it would be,



      names(df)[max.col(df != 0, ties.method = 'first')]
      #[1] "X3" "X3" "X2" "X4"


      In addition, you can use apply with margin 1 (to do row operations), and find the first index where the diff is not 0, i.e.



      names(df)[apply(df, 1, function(i) which(diff(i) != 0)[1]) + 1]
      #[1] "X3" "X3" "X2" "X4"





      share|improve this answer













      The Vectorized way to do it would be,



      names(df)[max.col(df != 0, ties.method = 'first')]
      #[1] "X3" "X3" "X2" "X4"


      In addition, you can use apply with margin 1 (to do row operations), and find the first index where the diff is not 0, i.e.



      names(df)[apply(df, 1, function(i) which(diff(i) != 0)[1]) + 1]
      #[1] "X3" "X3" "X2" "X4"






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Nov 13 '18 at 9:18









      SotosSotos

      28.7k51640




      28.7k51640







      • 2





        The vectorized way is a nice catch.

        – RLave
        Nov 13 '18 at 9:25












      • 2





        The vectorized way is a nice catch.

        – RLave
        Nov 13 '18 at 9:25







      2




      2





      The vectorized way is a nice catch.

      – RLave
      Nov 13 '18 at 9:25





      The vectorized way is a nice catch.

      – RLave
      Nov 13 '18 at 9:25













      1














      Another option using apply again:



      names(df)[apply(df, 1, function(x) which(x > 0)[1])]
      # [1] "X3" "X3" "X2" "X4"





      share|improve this answer



























        1














        Another option using apply again:



        names(df)[apply(df, 1, function(x) which(x > 0)[1])]
        # [1] "X3" "X3" "X2" "X4"





        share|improve this answer

























          1












          1








          1







          Another option using apply again:



          names(df)[apply(df, 1, function(x) which(x > 0)[1])]
          # [1] "X3" "X3" "X2" "X4"





          share|improve this answer













          Another option using apply again:



          names(df)[apply(df, 1, function(x) which(x > 0)[1])]
          # [1] "X3" "X3" "X2" "X4"






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 13 '18 at 9:21









          ANGANG

          4,3412620




          4,3412620





















              1














              A tidyverse solution:



              df %>%
              rowid_to_column() %>% #Creating an ID
              gather(var, val, -rowid) %>% #Transforming the data from wide to long
              arrange(rowid) %>% #Arranging according ID
              group_by(rowid) %>% #Grouping by ID
              mutate(res = ifelse(cumsum(val) > 0, paste0(var), NA)) %>% #Applying the condition
              filter(res == first(res[!is.na(res)])) %>% #Selecting the relevant value
              left_join(df %>% rowid_to_column(), by = c("rowid" = "rowid")) %>% #Joining with the original df
              ungroup() %>%
              select(-rowid, -var, -val) #Deleting the redundant variables

              res X1 X2 X3 X4
              <chr> <dbl> <dbl> <dbl> <dbl>
              1 X3 0. 0. 1. 3.
              2 X3 0. 0. 4. 5.
              3 X2 0. 2. 2. 6.
              4 X4 0. 0. 0. 1.





              share|improve this answer



























                1














                A tidyverse solution:



                df %>%
                rowid_to_column() %>% #Creating an ID
                gather(var, val, -rowid) %>% #Transforming the data from wide to long
                arrange(rowid) %>% #Arranging according ID
                group_by(rowid) %>% #Grouping by ID
                mutate(res = ifelse(cumsum(val) > 0, paste0(var), NA)) %>% #Applying the condition
                filter(res == first(res[!is.na(res)])) %>% #Selecting the relevant value
                left_join(df %>% rowid_to_column(), by = c("rowid" = "rowid")) %>% #Joining with the original df
                ungroup() %>%
                select(-rowid, -var, -val) #Deleting the redundant variables

                res X1 X2 X3 X4
                <chr> <dbl> <dbl> <dbl> <dbl>
                1 X3 0. 0. 1. 3.
                2 X3 0. 0. 4. 5.
                3 X2 0. 2. 2. 6.
                4 X4 0. 0. 0. 1.





                share|improve this answer

























                  1












                  1








                  1







                  A tidyverse solution:



                  df %>%
                  rowid_to_column() %>% #Creating an ID
                  gather(var, val, -rowid) %>% #Transforming the data from wide to long
                  arrange(rowid) %>% #Arranging according ID
                  group_by(rowid) %>% #Grouping by ID
                  mutate(res = ifelse(cumsum(val) > 0, paste0(var), NA)) %>% #Applying the condition
                  filter(res == first(res[!is.na(res)])) %>% #Selecting the relevant value
                  left_join(df %>% rowid_to_column(), by = c("rowid" = "rowid")) %>% #Joining with the original df
                  ungroup() %>%
                  select(-rowid, -var, -val) #Deleting the redundant variables

                  res X1 X2 X3 X4
                  <chr> <dbl> <dbl> <dbl> <dbl>
                  1 X3 0. 0. 1. 3.
                  2 X3 0. 0. 4. 5.
                  3 X2 0. 2. 2. 6.
                  4 X4 0. 0. 0. 1.





                  share|improve this answer













                  A tidyverse solution:



                  df %>%
                  rowid_to_column() %>% #Creating an ID
                  gather(var, val, -rowid) %>% #Transforming the data from wide to long
                  arrange(rowid) %>% #Arranging according ID
                  group_by(rowid) %>% #Grouping by ID
                  mutate(res = ifelse(cumsum(val) > 0, paste0(var), NA)) %>% #Applying the condition
                  filter(res == first(res[!is.na(res)])) %>% #Selecting the relevant value
                  left_join(df %>% rowid_to_column(), by = c("rowid" = "rowid")) %>% #Joining with the original df
                  ungroup() %>%
                  select(-rowid, -var, -val) #Deleting the redundant variables

                  res X1 X2 X3 X4
                  <chr> <dbl> <dbl> <dbl> <dbl>
                  1 X3 0. 0. 1. 3.
                  2 X3 0. 0. 4. 5.
                  3 X2 0. 2. 2. 6.
                  4 X4 0. 0. 0. 1.






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 13 '18 at 9:29









                  tmfmnktmfmnk

                  2,0601412




                  2,0601412



























                      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%2f53277485%2ffind-column-name-at-change-of-value%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







                      這個網誌中的熱門文章

                      Barbados

                      How to read a connectionString WITH PROVIDER in .NET Core?

                      Node.js Script on GitHub Pages or Amazon S3