【问题标题】:Use R to extract data for an identifier in a row and put it in a new column使用 R 为一行中的标识符提取数据并将其放入新列中
【发布时间】:2014-12-04 04:39:58
【问题描述】:

我有一些使用 ArcGIS 获取的数据,我想通过流域标识符(例如 HUC_8=1404106)构建一个数据库。数据包含流域标识符 (HUC_8)、流域面积、土壤类型和土壤面积。流域标识符被列出的次数与土壤类型一样多。我想创建一个基于流域的数据库(标识符只在列中出现一次),并在不同列中按类型提取土壤面积。我附上了数据的一个子集,希望它是清楚的。我对 R 有点陌生,但我觉得这可以通过 for 循环来完成。知道如何做到这一点将非常有帮助,因为我经常使用 GIS,但想在 R 中执行更多分析。

HUC_8   WatershedArea   Soil    SoilArea    A_Area  B_Area  C_Area  D_Area  Null_Area
14040106    461104.4883 B       96590.33424                 
14040106    461104.4883 C       86282.93487                 
14040106    461104.4883 D       24945.9992                  
14050007    921494.3621 Null    2.861388                    
14050007    921494.3621 A       87214.28385                 
14050007    921494.3621 B       131417.8659                 
14050007    921494.3621 C       268324.5125                 
14050007    921494.3621 D       314131.5806                 
14060001    627348.8316 Null    8119.375083                 
14060001    627348.8316 A       5315.511117                 
14060001    627348.8316 B       286915.9001                 
14060001    627348.8316 C       114357.5251                 
14060001    627348.8316 D       163671.7545             

【问题讨论】:

    标签: r loops gis watershed


    【解决方案1】:

    从本质上讲,您似乎想将数据从长格式重塑为宽格式。 reshape2 库可以在这里派上用场

    #sample data
    dd<-read.table(text="HUC_8   WatershedArea   Soil    SoilArea
    14040106    461104.4883 B       96590.33424                 
    14040106    461104.4883 C       86282.93487                 
    14040106    461104.4883 D       24945.9992                  
    14050007    921494.3621 Null    2.861388                    
    14050007    921494.3621 A       87214.28385                 
    14050007    921494.3621 B       131417.8659                 
    14050007    921494.3621 C       268324.5125                 
    14050007    921494.3621 D       314131.5806                 
    14060001    627348.8316 Null    8119.375083                 
    14060001    627348.8316 A       5315.511117                 
    14060001    627348.8316 B       286915.9001                 
    14060001    627348.8316 C       114357.5251                 
    14060001    627348.8316 D       163671.7545", header=T)
    

    现在转换数据

    library(reshape2)
    
    wide <- dcast(dd, HUC_8+ WatershedArea ~ Soil)
    
    #change default column names
    soils <- levels(dd$Soil)
    names(wide)[match(soils, names(wide))] <- paste(soils,"Area",sep="_")
    

    这导致wide 数据框看起来像

         HUC_8 WatershedArea    A_Area    B_Area    C_Area   D_Area   Null_Area
    1 14040106      461104.5        NA  96590.33  86282.93  24946.0          NA
    2 14050007      921494.4 87214.284 131417.87 268324.51 314131.6    2.861388
    3 14060001      627348.8  5315.511 286915.90 114357.53 163671.8 8119.375083
    

    【讨论】:

    • 谢谢弗里克先生。我尝试了您的方法,但我收到错误消息“使用 SoilArea 作为值列:使用 value.var 覆盖。”。不知道这意味着什么
    • 这不是错误。这是一个警告。如果您愿意,可以在函数调用中显式设置 value.var= 参数。我建议您在学习新功能时阅读?dcast 帮助页面。
    • 我在较大的数据集上再次尝试,但出现错误(缺少聚合函数:默认为长度)。我的代码如下 > Huc8Soil wide2 #更改默认列名称 > 土壤 名称(wide2)[match(soils,names(wide2))]
    • > WIDE2 HUC_8 WatershedArea A_Area B_Area C_Area D_Area Null_Area 1 14010005 31458.13 0 0 1 0 0 2 14040106 461104.49 0 1 1 1 0 3 14040107 116521.39 0 0 0 1 0 4 14050007 921494.36 1 1 2 1 1 5 14060001 627348.83 1 1 1 1 1 6 14060002 412849.74 0 1 1 1 1 7 14060003 1693374.17 1 1 1 1 1 ......
    • 感谢您的所有帮助。我确定这是我在 CSV 文件中忽略的内容。
    【解决方案2】:

    你可以试试

    lst <- Map(function(x,y) ifelse(df$Soil==x,y, NA),
                         sort(unique(df$Soil)), list(df$SoilArea))
    names(lst) <- paste(names(lst), 'Area', sep="_")
    df[names(lst)]  <- lst
    
    head(df,3)
    #      HUC_8 WatershedArea Soil SoilArea A_Area   B_Area   C_Area D_Area
    #1 14040106      461104.5    B 96590.33     NA 96590.33       NA     NA
    #2 14040106      461104.5    C 86282.93     NA       NA 86282.93     NA
    #3 14040106      461104.5    D 24946.00     NA       NA       NA  24946
    #   Null_Area
    #1        NA
    #2        NA
    #3        NA
    

    更新

    如果你想将reshapelong变为wide,你也可以使用base Rreshape

    df1 <- reshape(df, idvar=c('HUC_8', 'WatershedArea'),
                              timevar='Soil', direction='wide')
    
    colnames(df1)[-(1:2)] <- paste0(gsub('.*\\.', '',
                               colnames(df1)[-(1:2)]), '_Area')
    df1[,c(1:2,7,3:6)]
    #     HUC_8 WatershedArea    A_Area    B_Area    C_Area   D_Area   Null_Area
    #1 14040106      461104.5        NA  96590.33  86282.93  24946.0          NA
    #4 14050007      921494.4 87214.284 131417.87 268324.51 314131.6    2.861388
    #9 14060001      627348.8  5315.511 286915.90 114357.53 163671.8 8119.375083
    

    数据

    df <- structure(list(HUC_8 = c(14040106L, 14040106L, 14040106L, 14050007L, 
    14050007L, 14050007L, 14050007L, 14050007L, 14060001L, 14060001L, 
    14060001L, 14060001L, 14060001L), WatershedArea = c(461104.4883, 
    461104.4883, 461104.4883, 921494.3621, 921494.3621, 921494.3621, 
    921494.3621, 921494.3621, 627348.8316, 627348.8316, 627348.8316, 
    627348.8316, 627348.8316), Soil = c("B", "C", "D", "Null", "A", 
    "B", "C", "D", "Null", "A", "B", "C", "D"), SoilArea = c(96590.33424, 
    86282.93487, 24945.9992, 2.861388, 87214.28385, 131417.8659, 
    268324.5125, 314131.5806, 8119.375083, 5315.511117, 286915.9001, 
    114357.5251, 163671.7545)), .Names = c("HUC_8", "WatershedArea", 
    "Soil", "SoilArea"), class = "data.frame", row.names = c(NA, 
    -13L))
    

    【讨论】:

    • 谢谢阿克伦,我很感激。这很有帮助,但对于每个 HUC_8 值,我仍然只需要一行。
    猜你喜欢
    • 2023-03-20
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多