SAS杂乱数据导入问题:如何确保U字段仅为数值型且所有描述归入T字段
解决SAS导入CSV时U字段仅存数值、描述归入T字段的问题
看起来你在处理CSV导入时遇到了字段分类的难题——想让U字段只存储数值型数据,所有描述类信息都归入T字段,但当前的代码逻辑没达到预期。我先帮你拆解下现有代码的核心问题:你的do循环反复读取U并拼接T和U,但既没有区分数值和描述性内容,后续又重复读取U,这会导致数据读取错位,完全没实现你要的分类逻辑。下面给你几个可行的调整方案:
方案1:先读取所有字段,再通过条件判断分类
这种方法适合你能明确区分数值/描述的规则(比如描述是纯文本、U的数值是数字格式):
DATA data; infile '....csv' dlm=',' firstobs=2 dsd truncover; /* 先读取所有原始字段,包括可能的多个混合内容的U类字段 */ input A B C D E F G H I J K L M N O P Q R S T_raw U_raw1-U_raw24 V W X Y Z AA AB AC AD AE AF AG AH AI AJ AK AL AM AN AO AP AQ AR AS; /* 把T_raw和所有非数值的U_raw内容拼接成最终的T字段 */ T = T_raw; do i=1 to 24; /* 判断当前U_raw是否为非数值,是则加入T */ if not digit(strip(vvaluex(cats('U_raw',i)))) then do; T = catx(', ', T, vvaluex(cats('U_raw',i))); end; /* 如果是数值,存入U字段(这里假设你要保留第一个有效数值,或者可以改成数组存储多个U数值) */ else if missing(U) then U = input(vvaluex(cats('U_raw',i)), best32.); end; /* 不需要的临时变量可以删掉 */ drop T_raw U_raw1-U_raw24 i; format A$ B$ C$ D$ E$ F$ G$ H$ I$ J$ K$ L$ M$ N$ O$ P$ Q$ R$ S$ T$ U V W$ X$ Y$ Z$ AA$ AB$ AC$ AD$ AE$ AF$ AG$ AH$ AI$ AJ$ AK$ AL$ AM$ AN$ AO$ AP$ AQ$ AR$ AS; RUN;
这里用digit()函数判断是否为纯数字,vvaluex()动态引用变量名,把非数值的描述内容都合并到T,第一个有效数值存入U(如果需要多个U数值,可以改成数组U[24]来存储)。
方案2:在读取阶段直接区分数值和描述
如果CSV里的数值型U和描述内容是按位置或规则出现的,可以在input时直接判断:
DATA data; infile '....csv' dlm=',' firstobs=2 dsd truncover; length T $500; /* 给T足够长度存描述,避免内容截断 */ input A B C D E F G H I J K L M N O P Q R S T @; /* 循环读取接下来的24个字段,判断是否为数值 */ do _n_=1 to 24; input temp $ @; /* 尝试把temp转成数值,成功则存入U */ if not missing(input(temp, ?? best32.)) then do; /* 这里只存第一个有效数值,若要存多个可改用数组 */ if missing(U) then U = input(temp, best32.); end; else do; /* 非数值则追加到T字段 */ T = catx(', ', T, temp); end; end; input V W X Y Z AA AB AC AD AE AF AG AH AI AJ AK AL AM AN AO AP AQ AR AS; drop temp; format A$ B$ C$ D$ E$ F$ G$ H$ I$ J$ K$ L$ M$ N$ O$ P$ Q$ R$ S$ T$ U V W$ X$ Y$ Z$ AA$ AB$ AC$ AD$ AE$ AF$ AG$ AH$ AI$ AJ$ AK$ AL$ AM$ AN$ AO$ AP$ AQ$ AR$ AS; RUN;
这里用临时变量temp先读取为字符,再尝试转数值(??用来抑制转换错误),如果转成功就是U的数值,否则加入T。truncover参数可以避免因行尾字段不足导致的报错。
方案3:预处理整行(适合极度杂乱的CSV)
如果CSV本身的格式非常混乱(比如数值和描述混在同一列,没有固定规则),可以先把整行读成一个字符变量,再逐个拆分判断:
DATA data; infile '....csv' dlm=',' firstobs=2 dsd truncover; length full_line $2000 T $500; /* 先把整行读成一个变量,方便后续拆分 */ input full_line $; /* 拆分前19个字段(A-S),这里省略了中间的C-R,你可以补充完整 */ A = scan(full_line, 1, ','); B = scan(full_line, 2, ','); S = scan(full_line, 19, ','); /* 初始化T为第20个字段(原T) */ T = scan(full_line, 20, ','); /* 处理第21到44个字段(原U的24个) */ do i=21 to 44; temp = scan(full_line, i, ','); if not missing(input(temp, ?? best32.)) then do; if missing(U) then U = input(temp, best32.); end; else do; T = catx(', ', T, temp); end; end; /* 处理后面的V-AS字段,同样需要补充中间的字段 */ V = input(scan(full_line, 45, ','), best32.); W = scan(full_line, 46, ','); AS = scan(full_line, 69, ','); drop full_line temp i; format A$ B$ C$ D$ E$ F$ G$ H$ I$ J$ K$ L$ M$ N$ O$ P$ Q$ R$ S$ T$ U V W$ X$ Y$ Z$ AA$ AB$ AC$ AD$ AE$ AF$ AG$ AH$ AI$ AJ$ AK$ AL$ AM$ AN$ AO$ AP$ AQ$ AR$ AS; RUN;
这种方法适合CSV格式极度不规则的情况,通过整行读取再拆分,完全掌控每个字段的处理逻辑。
关键注意事项
- 一定要给
T字段设置足够的长度(比如length T $500;),避免描述内容被截断 - 使用
truncover或missover参数,防止因行尾字段数量不足导致数据读取错位 - 如果你的“数值”包含小数、负数等,
digit()函数可能不适用,改用input(temp, ?? best32.)判断是否能转成有效数值更准确
内容的提问来源于stack exchange,提问作者konsteinuser
相关产品推荐
相关产品推荐

