你好!进行玉米的 **NCII(North Carolina Design II,北卡罗来纳II设计...
Créé le : 23 janvier 2026
Répondu en utilisant GPT-5.2 Thinking par Chat01
Créé le : 23 janvier 2026
Répondu en utilisant GPT-5.2 Thinking par Chat01
你好!进行玉米的 NCII(North Carolina Design II,北卡罗来纳II设计) 分析是一个非常经典的数量遗传学操作。这种设计本质上是一个 析因设计(Factorial Design),即每一个选定的父本都要与每一个选定的母本进行杂交。
NCII 分析的核心目的是为了评估 配合力(Combining Ability) 和 遗传方差分量(加性方差和显性方差)。
你目前只有“样本名、母本、父本”这三列名单是不够的,你还需要表型数据(如产量、株高、穗位等)和**重复(Replication)**信息。
以下是完整的操作指南,从数据整理到分析方法的落地:
NCII 分析要求数据结构非常严谨。请检查你的 Excel 数据是否满足以下条件,并按建议格式整理:
1. 数据完整性检查
NCII 设计通常是将父本(Male)和母本(Female)分组。假设你有 个父本和 个母本,你应该有 个杂交组合。
2. 补充必要列
你需要将 Excel 整理成“长数据(Long Format)”格式。除了家系信息,必须加上田间试验的重复(Rep)和性状数值。
推荐的 Excel 格式:
| 样本名 (Cross ID) | 母本 (Female) | 父本 (Male) | 重复 (Rep) | 产量 (Yield) | 株高 (Plant Height) | ...其他性状 |
|---|---|---|---|---|---|---|
| Hybrid_1 | F1 | M1 | 1 | 650.5 | 210 | ... |
| Hybrid_1 | F1 | M1 | 2 | 640.2 | 212 | ... |
| Hybrid_2 | F1 | M2 | 1 | 680.0 | 205 | ... |
| ... | ... | ... | ... | ... | ... | ... |
注意: 如果你的试验是在多个地点(Environments)进行的,还需要增加一列“地点(Env)”。
在操作软件之前,你需要理解 NCII 的统计模型,这样看结果才不会晕。
对于单环境下的 NCII 设计,其线性模型通常表示为:
其中:
有了整理好的 Excel,你可以选择以下几种方式进行分析。对于玉米育种,强烈推荐使用 R语言,因为它免费且专业包最全。
你需要安装 R 和 RStudio。我们将使用 agricolae 包或者基础的 aov 函数。
操作代码模板:
r# 1. 加载数据 (假设你的文件名为 corn_data.csv) library(readxl) data <- read_excel("你的文件路径.xlsx") # 2. 确保分类变量是因子 (Factor) 格式 data$Male <- as.factor(data$Male) data$Female <- as.factor(data$Female) data$Rep <- as.factor(data$Rep) # 3. 运行方差分析 (ANOVA) # 这是一个标准的析因设计模型 model <- aov(Yield ~ Rep + Male + Female + Male:Female, data = data) # 4. 查看结果 summary(model) # 5. 计算配合力 (GCA 和 SCA) # 如果你需要具体的效应值,可以使用 model.tables effects <- model.tables(model, type = "effects", se = TRUE) print(effects)
如何解读 R 的结果:
如果你有 AGD-R (Analysis of Genetic Designs with R),这是一个基于 R 但有图形界面的工具,专门由 CIMMYT(国际玉米小麦改良中心)开发,非常适合做 NCII 分析。它能直接输出 GCA/SCA 和遗传力。
做完分析后,你要从结果中提取玉米育种关注的核心信息:
目前你需要做的第一件事是:
除了名单,你需要把田间的测产数据填入 Excel,并确认是否每个父本都和每个母本杂交了(构成矩阵)。
我可以为你做什么:
如果你已经有了带数据的 Excel 文件,你可以描述一下你的数据表头(具体的列名),我可以为你写一段不需要修改直接能用的 R 语言代码,帮你算出 GCA 和 SCA。你需要我这样做吗?
是的,我需要。列名:"hybrid" "mom" "dad" "ph_1" "ear_1" "mu_1" "ph_2" "ear_2" "mu_2".
其中hybrid是样本名,mom dad 是母本父本,_1 _2 是第1/2次重复。
下面这段 R 脚本可以直接吃你现在这张“宽表”(ph_1 / ph_2 …),自动转成长表,然后对每个性状(ph / ear / mu)分别做:
你不用改列名;读文件用
file.choose(),会弹窗让你选 Excel。
r## ========================= ## NCII (North Carolina Design II) analysis for your wide-format Excel ## Columns: hybrid, mom, dad, ph_1, ear_1, mu_1, ph_2, ear_2, mu_2 ## ========================= ## 0) Packages pkgs <- c("readxl", "dplyr", "tidyr", "stringr", "lme4", "broom", "writexl") to_install <- pkgs[!pkgs %in% rownames(installed.packages())] if (length(to_install) > 0) install.packages(to_install, dependencies = TRUE) invisible(lapply(pkgs, require, character.only = TRUE)) ## 1) Read Excel (interactive file picker) dat0 <- readxl::read_excel(path = file.choose()) ## 2) Basic checks required_cols <- c("hybrid", "mom", "dad") missing_required <- setdiff(required_cols, names(dat0)) if (length(missing_required) > 0) { stop("Missing required columns: ", paste(missing_required, collapse = ", ")) } ## 3) Pivot from wide -> long ## Any column ending with _<number> will be treated as trait_rep ## e.g., ph_1, ear_2, mu_2 ... dat_long <- dat0 %>% dplyr::mutate( hybrid = as.character(hybrid), mom = as.factor(mom), dad = as.factor(dad) ) %>% tidyr::pivot_longer( cols = dplyr::matches("_.+\\d+$|_\\d+$"), # tolerant names_to = c("trait", "Rep"), names_pattern = "^(.+)_([0-9]+)$", values_to = "y" ) %>% dplyr::mutate( trait = as.factor(trait), Rep = as.factor(Rep), y = suppressWarnings(as.numeric(y)) ) %>% dplyr::filter(!is.na(y)) if (nrow(dat_long) == 0) stop("No numeric phenotype values found after pivot_longer().") ## Optional: Use sum-to-zero contrasts to make 'effects' more interpretable options(contrasts = c("contr.sum", "contr.poly")) ## 4) Helper functions fit_one_trait <- function(df_trait) { # Fixed-effects ANOVA (classic factorial) aov_fit <- aov(y ~ Rep + mom + dad + mom:dad, data = df_trait) aov_tab <- broom::tidy(aov_fit) # Random-effects model for variance components # Rep kept as fixed (common in field trials with reps) lmer_fit <- lme4::lmer(y ~ Rep + (1|mom) + (1|dad) + (1|mom:dad), data = df_trait, REML = TRUE) vc <- as.data.frame(lme4::VarCorr(lmer_fit)) # vc columns: grp, var1, var2, vcov, sdcor get_v <- function(grp_name) { out <- vc$vcov[vc$grp == grp_name] if (length(out) == 0) return(0) out[1] } v_mom <- get_v("mom") v_dad <- get_v("dad") v_momdad <- get_v("mom:dad") v_resid <- get_v("Residual") r <- dplyr::n_distinct(df_trait$Rep) # Common NCII mapping (diploid, no epistasis assumptions): # Var(mom GCA) ~ 1/4 σA ; Var(dad GCA) ~ 1/4 σA => σA ≈ 2*(v_mom + v_dad) # Var(SCA) ~ 1/4 σD => σD ≈ 4*v_momdad sigma_A <- 2 * (v_mom + v_dad) sigma_D <- 4 * v_momdad # Narrow-sense heritability on hybrid MEAN (approx): # h2 ≈ σA / (σA + σD + σe/r) h2_mean <- ifelse((sigma_A + sigma_D + v_resid / r) > 0, sigma_A / (sigma_A + sigma_D + v_resid / r), NA_real_) varcomp <- dplyr::tibble( component = c("V_mom(GCA)", "V_dad(GCA)", "V_mom:dad(SCA)", "V_residual", "sigma_A(≈2*(V_mom+V_dad))", "sigma_D(≈4*V_SCA)", "h2_mean(≈sigmaA/(sigmaA+sigmaD+Ve/r))", "nRep"), value = c(v_mom, v_dad, v_momdad, v_resid, sigma_A, sigma_D, h2_mean, r) ) # BLUPs for GCA/SCA (random effects) re <- lme4::ranef(lmer_fit) gca_mom <- re$mom %>% tibble::rownames_to_column("mom") %>% dplyr::rename(GCA_mom = `(Intercept)`) %>% dplyr::arrange(dplyr::desc(GCA_mom)) gca_dad <- re$dad %>% tibble::rownames_to_column("dad") %>% dplyr::rename(GCA_dad = `(Intercept)`) %>% dplyr::arrange(dplyr::desc(GCA_dad)) sca <- re[["mom:dad"]] %>% tibble::rownames_to_column("mom_dad") %>% dplyr::rename(SCA = `(Intercept)`) %>% tidyr::separate(mom_dad, into = c("mom", "dad"), sep = ":", remove = TRUE) %>% dplyr::arrange(dplyr::desc(SCA)) # Hybrid means (useful for ranking) means <- df_trait %>% dplyr::group_by(hybrid, mom, dad) %>% dplyr::summarise(mean_y = mean(y, na.rm = TRUE), .groups = "drop") %>% dplyr::arrange(dplyr::desc(mean_y)) list( aov_table = aov_tab, varcomp = varcomp, gca_mom = gca_mom, gca_dad = gca_dad, sca = sca, means = means ) } ## 5) Run by trait and collect outputs traits <- levels(dat_long$trait) if (is.null(traits) || length(traits) == 0) traits <- unique(as.character(dat_long$trait)) out_sheets <- list() for (tr in traits) { df_tr <- dat_long %>% dplyr::filter(trait == tr) # skip if too small if (nrow(df_tr) < 5) next res <- fit_one_trait(df_tr) # Put into separate sheets (Excel sheet name limit ~31 chars) tr_safe <- stringr::str_replace_all(as.character(tr), "[\$$\$$\\*\\?/\\\\:]", "_") tr_safe <- substr(tr_safe, 1, 20) out_sheets[[paste0(tr_safe, "_ANOVA")]] <- res$aov_table out_sheets[[paste0(tr_safe, "_VarComp")]] <- res$varcomp out_sheets[[paste0(tr_safe, "_GCA_mom")]] <- res$gca_mom out_sheets[[paste0(tr_safe, "_GCA_dad")]] <- res$gca_dad out_sheets[[paste0(tr_safe, "_SCA")]] <- res$sca out_sheets[[paste0(tr_safe, "_Means")]] <- res$means } if (length(out_sheets) == 0) stop("No trait results generated. Check your trait columns like ph_1, ph_2 ...") ## 6) Write results to Excel writexl::write_xlsx(out_sheets, path = "NCII_results.xlsx") message("Done! Results saved to: NCII_results.xlsx")
你跑完以后,重点看:
*_ANOVA:mom / dad / mom:dad 的显著性(对应 GCA / GCA / SCA)*_VarComp:sigma_A、sigma_D、h2_mean*_GCA_mom、*_GCA_dad:每个亲本的 GCA(正值通常表示对性状贡献高,取决于性状方向)*_SCA:具体组合的 SCA(杂种优势/特配)如果你希望我帮你把 “ph/ear/mu”重命名成更直观的性状名,或者你有 多地点 Env(需要加 Env 和交互项),把你的表头/示例两三行贴出来,我可以把模型扩展成多环境的 NCII(含 GCA×Env、SCA×Env)。