簡體   English   中英

通過在 R 中添加其他單元格和行的值來擴展 Dataframe 中的值

[英]Extend Value in Dataframe by add Value of an other Cell and Row in R

我嘗試使用 dplyr 和 ggplot2 在 R 中分析 XML 數據。 我的代碼能夠將 XML 數據轉換為數據框。 不幸的是,結構丟失了。

我的 XML 文檔具有以下示例結構:

<?xml version="1.0" encoding="UTF-8"?>
<Budget price="1234" items="1234" year="1990">
<Account name="a" value="123" step="0">
<Account name="1" value="12" step="1"/>
<Account name="1.1" value="12" step="2"/>
<Account name="2" value="12" step="1"/>
<Account name="2.1" value="9" step="2"/>
<Account name="2.2" value="3" step="2"/>
<Account name="3" value="99" step="1"/>
<Account name="3.1" value="78" step="2"/>
<Account name="3.1.1" value="70" step="3"/>
<Account name="3.1.2" value="8" step="3"/>
<Account name="3.2" value="21" step)="2"/>
</Account>
<Account name="b" value="234" step="0">
<Account name="1" value="200" step="1"/>

等等

起初我保存所有值:

budget_values = xml_find_all(doc,"//Budget",flatten=FALSE)

然后我選擇一些值:

step_ids = purrr::map_chr(budget_values, ~xml_attr(.,"step"))
name_values = purrr::map_chr(budget_values, ~xml_attr(.,"name"))
values = purrr::map_chr(budget_values, ~xml_attr(.,"value"))

將屬性保存在組合列表中:

values_list <- list((step_ids),(name_values),(values))

並將其轉換為數據框:

budget_df <- data.frame(sapply(values_list, c))

效果很好。 我有一個這樣的 DF:

步驟ID 姓名
0 一種 1234
1個 1個 12
2個 1.1 12
1個 2個 12
2個 2.1 9
2個 2.2 3個
1個 3個 99
0 b 234
1個 1個 200

等等

正如您從示例中看到的,一些名稱是重復的——通常是第 1 步和第 2 步; 第 3 步通常非常獨特。

我的目標是跟隨數據框來分析更有條理的數據。

步驟ID 姓名
0 一種 1234
1個 a1 12
2個 a1.1 12
1個 a2 12
2個 a2.1 9
2個 a2.2 3個
1個 a3 99
0 b 234
1個 b1 200

等等

例如:我想要所有 step1 的值。 現在我不知道它來自哪個預算。 通過新名稱,我可以看到:這個值來自預算 a,這個來自預算 b,依此類推。

我嘗試使用 for-loop 並將結果存儲在一個新的數據框中

df<-for (rows in budget_df) {
  if (rows$`Step-ID` == "0") {
    saved_name <- rows$name
    print(saved_name)
  }
  else
    (rows$`Step-ID` == "1"){
      rows$Haushalt+saved_name
      saved_names<-saved_name+rows$name
      print(saved_names)
    }
  else(rows$`Step-ID`=="2"){
    rows$Haushalt+saved_name
  }
  else(rows$`Step-ID`=="3"){
    rows$name+saved_names
  }
}
View(df)

我得到以下錯誤:

Error: unexpected '{' in:
"  else
    (rows$`Step-ID` == "1"){"

我的問題是:是否有更好的方法來分析數據或重命名名稱中的值?

非常感謝您的幫助!

更新:

再次感謝@jpsmith。 我嘗試了以下關於他的推薦的代碼:

df-budget_df

    budget <- ""
    df <- for (row in df) {
      mutate(
        case_when (
          df$`Step-ID` == "0" ~ budget <- df$Haushalt,
          df$`Step-ID` == "2" ~ mutate(df, sturucture = paste(budget, df$Haushalt)),
          df$`Step-ID` == "2" ~ budget <- c(budget, df$Haushalt),
          df$`Step-ID` == "3" ~ mutate(df, sturucture = paste(values, df$Haushalt))
        )
      )
    }

從邏輯上解釋我想做什么,但不起作用。 我認為,這是因為試圖用<-存儲值? 我在?case_when找不到另一種方法來存儲值。 另一個代碼(我已經覆蓋)存儲了Step-ID的值並擴展了同一步驟的Haushalt的值,而不是: Step-ID 0 to Haushalt with Step-ID 1 under Step-ID 0 and Step-ID 1 to帶有Step-ID 2 Haushalt

好的,感謝所有幫助:我用 for-Loop 得到了它:

n <- 0
df<-mutate(df,Structure=NA)
for (i in 1:nrow(df)) {
  if (df[i, 1] == "0") {
    first_step <- df[i, 2]
    values<-first_step
    df$Structure[which(is.na(df$Structure))[1]]<-values
  }
  else if (df[i, 1] == "1") {
    second_step <- df[i, 2]
    values <- paste(first_step, second_step)
    df$Structure[which(is.na(df$Structure))[1]]<-values
  }
  else if (df[i, 1] == "2") {
    third_step <- df[i, 2]
    values <- paste(first_step, second_step, third_step)
    df$Structure[which(is.na(df$Structure))[1]]<-values
  }
  else if (df[i, 1] == "3") {
    fourth_step <- df[i, 2]
    values <- paste(first_step, second_step, third_step, fourth_step)
    df$Structure[which(is.na(df$Structure))[1]]<-values
  }
  n <- n + 1
}

考慮XSLT ,一種設計用於轉換 XML 文件的專用語言,以便將父@name屬性作為基礎子@name屬性的前綴。 使用 R 的xslt (對xml2的補充包),您可以運行 XSLT 1.0 腳本:

XSLT (另存為.xsl文件,一種特殊的.xml文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/Budget">
     <xsl:copy>
       <xsl:apply-templates select="Account"/>
     </xsl:copy>
    </xsl:template>
    
    <!-- MOVE ATTRIBUTES TO ELEMENTS -->
    <xsl:template match="Account">
     <xsl:copy>
       <stepid><xsl:value-of select="@step"/></stepid>
       <name><xsl:value-of select="@name"/></name>
       <value><xsl:value-of select="@value"/></value>
     </xsl:copy>
     <xsl:apply-templates select="*"/>
    </xsl:template>
    
    <!-- MOVE ATTRIBUTES TO ELEMENTS AND CONCATENATE PARENT @name ATTRIBUTE -->
    <xsl:template match="Account/*">
     <xsl:variable name="step">
       <xsl:value-of select="../@name"/>
     </xsl:variable>
     <xsl:copy>
       <stepid><xsl:value-of select="@step"/></stepid>
       <name><xsl:value-of select="concat($step, @name)"/></name>
       <value><xsl:value-of select="@value"/></value>
     </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

在線演示

R

library(xml2)
library(xslt)

# LOAD XML AND XSLT
doc <- read_xml("inputF.xml")
style <- read_xml("style.xsl", package = "xslt")

# RUN TRANSFORMATION AND SEE OUTPUT
new_xml <- xml_xslt(doc, style)

# RETRIEVE ALL NODES
recs <- xml2::xml_find_all(new_xml, "//Account")

# BIND EACH CHILD TEXT AND NAME
df_list <- lapply(recs, function(r) {
  vals <- xml2::xml_children(r)
  
  df <- setNames(
    c(xml2::xml_text(vals)), 
    c(xml2::xml_name(vals))
  ) |> rbind() |> data.frame()
})

# COMBINE ALL DFS
accounts_df <- do.call(rbind.data.frame, df_list)

輸出

accounts_df

#    stepid   name value
# 1       0      a   123
# 2       1     a1    12
# 3       2   a1.1    12
# 4       1     a2    12
# 5       2   a2.1     9
# 6       2   a2.2     3
# 7       1     a3    99
# 8       2   a3.1    78
# 9       3 a3.1.1    70
# 10      3 a3.1.2     8
# 11      2   a3.2    21
# 12      0      b   234
# 13      1     b1   200

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM