EV/EBITDA

简介

编辑
EV/EBITDA 又称企业价值倍数,是一种被广泛使用的 公司估值指标,公式为,EV÷EBITDA 投资应用:EV/EBITDA和 市盈率(PE)等相对估值法指标的用法一样,其倍数相对于行业平均水平或历史水平较高通常说明高估,较低说明低估,不同行业或板块有不同的估值(倍数)水平。EV/EBITDA法估值公司价值: 公司价值EV=市值+(总负债-总现金) =市值+净负债
EBITDA(Earings before interest,tax,depreciation and amortization)(利息、所得税、折旧、摊销前盈余) =营业利润+折旧费用+摊销费用 其中,营业利润=毛利-销售费用-管理费用

估值方法

EV/EBITDA倍数和P/E同属于可比法,在使用的方法和原则上大同小异,只是选取的指标口径有所不同。 从指标的计算上来看,EV/EBITDA倍数使用企业价值(EV),即投入企业的所有资本的市场价值代替PE中的 股价,使用息税折旧前盈利(EBITDA)代替PE中的 每股净利润。企业所有投资人的资本投入既包括 股东权益也包括债权人的投入,而EBITDA则反映了上述所有投资人所获得的税前 收益水平。相对于PE是 股票市值和预测净利润的比值,EV/EBITDA则反映了 投资资本的市场价值和未来一年企业收益间的比例关系。因此,总体来讲,PE和EV/EBITDA反映的都是市场价值和收益指标间的比例关系,只不过PE是从股东的角度出发,而EV/EBITDA则是从全体投资人的角度出发。在EV/EBITDA方法下,要最终得到对股票市值的估计,还必须减去债权的价值。在缺乏债权市场的情况下,可以使用债务的账面价值来近似估计。 在具体运用中,EV/EBITDA倍数法和PE法的使用前提一样,都要求企业预测的未来 收益水平必须能够体现企业未来的收益流量和风险状况的主要特征。这体现于可比公司选择的各项假设和具体要求上,缺失了这些前提,该方法同样也就失去了合理估值的功能。

优势

EV/EBITDA较P/E有明显优势。概括而言,由于不受所得税率不同的影响,使得不同国家和市场的上市 公司估值更具可比性;其次不受 资本结构不同的影响,公司对资本结构的改变都不会影响估值,同样有利于比较不同公司估值水平;最后,排除了折旧摊销这些非 现金成本的影响(现金比账面利润重要),可以更准确的反映公司价值。但EV/EBITDA更适用于单一业务或子公司较少的公司估值,如果业务或合并子公司数量众多,需要做复杂调整,有可能会降低其准确性。
相比而言,由于指标选取角度的不同,EV/EBITDA倍数弥补了PE倍数的一些不足,使用的范围也更为广泛。首先,以收益为基础的可比法的一个使用前提是收益必须为正。如果一个企业的预测净利润为负值,则P/E就失效了。相比而言,由于 EBITDA指标中扣除的费用项目较少,因此其相对于净利润而言成为负数的可能性也更小,因而具有比PE更广泛的使用范围。
EBITDA不受 企业融资政策的影响,不同 资本结构的企业在这一指标下更具有可比性。同样,由于EBITDA为扣除折旧摊销费用之前的收益指标,企业间不同的 折旧政策也不会对上述指标产生影响,这也避免了折旧政策差异以及折旧反常等现象对估值合理性的影响。
最后,EBITDA指标中不包括投资收益、营业外收支等其他收益项目,仅代表了企业主营业务的运营绩效,这也使企业间的比较更加纯粹,真正体现了企业主业运营的经营效果以及由此而应该具有的价值。当然,这也要求单独评估长期投资的价值,并在最终的计算结果中加回到 股东价值之中。
总体而言,相比于将所有因素都综合在一起的净利润指标,EBITDA剔除了诸如 财务杠杆使用状况、折旧政策变化、长期投资水平等非营运因素的影响,更为纯粹,因而也更为清晰地展现了企业真正的运营绩效。这有利于投资者排除各种干扰,更为准确地把握 企业核心业务的经营状况。同时,从指标对企业价值的反映程度上来说,由于剔除了上述因素的影响,企业单一年度的EBITDA指标与企业未来收益和风险的相关性更高,换句话说,影响企业单一年度EBITDA水平的因素和影响企业未来所有年度EBITDA水平的因素更为一致,而影响企业单一年度净利润的因素则相对复杂和多变。也正因为如此,作为一种以可比为基础的估值方法,EV/EBITDA倍数法的合理性相对于PE也就更强。

缺陷

当然,和其他任何方法一样,EV/EBITDA也有一些固有的缺陷。首先,和P/E比较起来,EV/EBITDA方法要稍微复杂一些,至少还要对债权的价值以及长期投资的价值进行单独估计。其次,EBITDA中没有考虑到税收因素,因此,如果两个公司之间的 税收政策差异很大,这个指标的估值结果就会失真。

适用条件

编辑
最后,和PE一样,EBITDA也是一个单一的年度指标,并没有考虑到企业未来 增长率这个对于企业价值判断至关重要的因素,因而也只有在两个企业具有近似增长前景的条件下才适用。 EV/EBITDA倍数法作为当前专业投资人员越来越普遍采用的一种估值方法,其主要优势就在于EBITDA指标对企业收益的更清晰度量,以及该指标和企业价值之间更强的相关性。然而在某些具体行业中,由于行业特性和会计处理规定可能会导致上述关系一定程度的扭曲,这时就需要使用者对EBITDA指标进行一定的调整,恢复其衡量企业主营业务税前绩效的合理性。以航空公司为例,公司运营的飞机有的是自筹资金购买的,这在财务报表上显示为企业的固定资产需要每年计提折旧。如上所述,这类费用并不在EBITDA指标中扣除。但航空公司中还有相当一部分飞机是租来的,每年付给飞机租赁公司一定的费用,而这部分费用在财务报表中显示为经营费用,在EBITDA指标中已经进行了扣除。显然,如果单纯的比较航空公司EBITDA水平就会有失公允。所以,此时应该将航空公司EBITDA指标中已经扣除的 租赁费用加回,变形为EBITDAR指标,从而实现公司之间的可比性,相应的估值方法也变形为EV/EBITDAR倍数法。在石油行业中,勘探活动可以界定为高风险 投资活动。要衡量石油公司的运营绩效,需要将勘探费用加回以进行比较,此时相应的估值方法演化为EV/EBITDAX。
import pandas as pd from decimal import Decimal, getcontext, setcontext, InvalidOperation from decimal import Context as DecimalContext import numpy as np from openpyxl import load_workbook from scipy import stats import math def read_excel_to_dict(file_path, sheet_name, cell_range, column_names): """ 读取Excel指定区域的多列数据,并返回命名数组,保留空单元格为NaN 参数: file_path: Excel文件路径 sheet_name: 工作表名称 cell_range: 单元格范围 (如'C3:D27') column_names: 列名称列表 (如['pettm', 'petf1']) 返回: 包含命名数组的字典 """ # 解析单元格范围 start_cell, end_cell = cell_range.split(':') start_col = start_cell[0] end_col = end_cell[0] start_row = int(start_cell[1:]) end_row = int(end_cell[1:]) # 计算列范围 all_columns = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' start_idx = all_columns.index(start_col) end_idx = all_columns.index(end_col) num_columns = end_idx - start_idx + 1 # 验证列名数量 if len(column_names) != num_columns: raise ValueError(f"列名数量({len(column_names)})与列数({num_columns})不匹配") # 读取数据为DataFrame,保留空值为NaN # 读取数据为字符串保留精度 df = pd.read_excel( file_path, sheet_name=sheet_name, header=None, usecols=f"{start_col}:{end_col}", skiprows=start_row - 1, nrows=end_row - start_row + 1, dtype=str ) # 转换为Decimal/Nan数组 result = {} for i, col_name in enumerate(column_names): mixed_list = [] for val in df.iloc[:, i]: # 处理空单元格(NaN或空字符串) if pd.isna(val) or str(val).strip() == '': mixed_list.append(np.nan) # 处理Excel中的特殊空值表示 elif str(val).lower() in ['nan', 'n/a', 'na', 'null', '#n/a', '', ' ']: mixed_list.append(np.nan) # 尝试转换为Decimal else: try: mixed_list.append(Decimal(str(val))) except: # 保留原始值作为后备 mixed_list.append(val) result[col_name] = np.array(mixed_list, dtype=object) return result def z_score_normalize(data_dict, fill_nan=None): """ 对数据字典中的每列进行Z-score标准化,保留NaN位置不变 参数: data_dict: 包含数据的字典 {列名: np.array},数组包含 Decimal 和 NaN 返回: 标准化后的数据字典,保留原始 NaN 位置,数值为 Decimal 类型 """ # 设置高精度计算环境 original_context = getcontext() high_precision_context = original_context.copy() high_precision_context.prec = 28 # 设置28位精度 setcontext(high_precision_context) normalized_data = {} for col_name, arr in data_dict.items(): # 步骤1: 提取有效 Decimal 值(排除 NaN) decimal_values = [] indices = [] # 记录有效值的索引位置 for i, val in enumerate(arr): # 保留 NaN 位置 if pd.isna(val): continue # 处理 Decimal 值 if isinstance(val, Decimal): decimal_values.append(val) indices.append(i) # 处理其他数值类型(转换为 Decimal) elif isinstance(val, (int, float)): try: decimal_values.append(Decimal(str(val))) indices.append(i) except (InvalidOperation, ValueError): # 转换失败,保留为 NaN pass # 步骤2: 计算均值和标准差(Decimal 计算) if len(decimal_values) > 0: # 计算总和 total = sum(decimal_values, Decimal(0)) # 计算均值 mean_val = total / Decimal(len(decimal_values)) # 计算方差 variance = Decimal(0) for val in decimal_values: diff = val - mean_val variance += diff * diff variance /= Decimal(len(decimal_values)) # 计算标准差 if variance > 0: std_dev = variance.sqrt() else: std_dev = Decimal(0) else: # 没有有效数据时使用默认值 mean_val = Decimal(0) std_dev = Decimal(1) # 步骤3: 创建结果数组(初始化全部为 NaN) normalized_arr = np.empty(len(arr), dtype=object) normalized_arr[:] = np.nan # 初始化为 NaN # 步骤4: 计算 Z-score 并对有效值进行标准化 for idx, val in zip(indices, decimal_values): # 处理标准差为零的情况 if std_dev == 0: normalized_val = Decimal(0) else: normalized_val = (val - mean_val) / std_dev normalized_arr[idx] = normalized_val normalized_data[col_name] = normalized_arr # 恢复原始计算精度环境 setcontext(original_context) return normalized_data def calculate_weighted_averages(normalized_data, group_config): """ 计算多组列的权平均值 参数: normalized_data: 标准化数据字典 {列名: 数组} group_config: 分组配置字典 返回: 包含X和Y数组的字典 """ # 确定数据行数 first_col = next(iter(normalized_data.values())) num_rows = len(first_col) results = {} for group_name, config in group_config.items(): columns = config['columns'] weights = config['weights'] # 验证配置 if len(columns) != len(weights): raise ValueError(f"组 '{group_name}' 的列数与权重数不匹配") # 验证权重和为1 if not np.isclose(sum(weights), 1.0, atol=1e-6): print(f"警告: 组 '{group_name}' 的权重和({sum(weights)})不为1,将自动归一化") weights = [w / sum(weights) for w in weights] # 初始化结果列表 weighted_avgs = [] nan_count = 0 # 逐行处理 for row_idx in range(num_rows): valid_values = [] # 存储有效值 valid_weights = [] # 存储有效权重 invalid_indices = [] # 记录无效值位置 # 收集当前行的有效值 for col_idx, col_name in enumerate(columns): if col_name not in normalized_data: raise KeyError(f"列名 '{col_name}' 在输入数据中不存在") value = normalized_data[col_name][row_idx] # 检查值是否为有效 Decimal if pd.isna(value) or value is None: invalid_indices.append(col_idx) else: try: # 确保值是 Decimal if not isinstance(value, Decimal): value = Decimal(str(value)) valid_values.append(value) valid_weights.append(weights[col_idx]) except (TypeError, InvalidOperation): invalid_indices.append(col_idx) # 处理全无效行 if not valid_values: weighted_avgs.append(np.nan) nan_count += 1 continue # 计算有效权重的总和 total_valid_weight = sum(valid_weights, Decimal(0)) # 重新调整权重(归一化) if total_valid_weight != Decimal(1): adjusted_weights = [w / total_valid_weight for w in valid_weights] else: adjusted_weights = valid_weights # 计算权平均值(Decimal 精确计算) weighted_sum = Decimal(0) for val, weight in zip(valid_values, adjusted_weights): weighted_sum += val * weight weighted_avgs.append(weighted_sum) # 存储结果 results[group_name] = weighted_avgs # 打印处理统计 print(f"组 '{group_name}' 处理完成: " f"总行数={num_rows}, " f"有效行={num_rows - nan_count}, " f"无效行={nan_count}") return results # 使用示例 if __name__ == "__main__": FILE_PATH = "shuzhi.xlsx" SHEET_NAME = "Sheet1" CELL_RANGE = "C3:I27" # 读取7列数据 COLUMN_NAMES = ["pettm", "petf1", "pblf", "pbfy1", "ev/ebitda","股息率","peg"] HANDLE_NON_NUMERIC = 'convert' # 处理非数值的策略 FILL_VALUE = np.nan # 填充值 # 1. 读取Excel数据 print(f"从 {FILE_PATH} 读取数据...") data_dict = read_excel_to_dict(FILE_PATH, SHEET_NAME, CELL_RANGE, COLUMN_NAMES) # 验证空值处理 print("\n空值验证:") for col_name, arr in data_dict.items(): nan_count = sum(1 for x in arr if pd.isna(x)) print(f"{col_name}: 共 {nan_count} 个NaN值") # 2. Z-score标准化处理 print("\n进行Z-score标准化...") normalized_data = z_score_normalize(data_dict) # 验证标准化结果 print("\n标准化结果空值验证:") for col_name, arr in normalized_data.items(): nan_count = sum(1 for x in arr if pd.isna(x)) print(f"{col_name}: 共 {nan_count} 个NaN值") print(normalized_data) #3.权平均1 # 分组配置 group_config = { 'X': { 'columns': ["pettm", "petf1", "revenue", "cost", "profit"], # BCD列的标准化数据 'weights': [0.2, 0.2, 0.2,0.2,0.2] # 权权重 }, 'Y': { 'columns': ["股息率","peg"], # EFG列的标准化数据 'weights': [0.5, 0.5] # 权权重 } } # 计算权平均值 print("计算权平均值...") results = calculate_weighted_averages(normalized_data, group_config) print(results) 里面有什么错误导致没有结果
最新发布
09-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值