【问题标题】:Cannot iterate through CSV columns无法遍历 CSV 列
【发布时间】:2019-02-26 23:47:00
【问题描述】:

我正在构建一个股票筛选器,它通过 csv 文件的每一列应用计算。但是,当我运行 for 循环时,我只能得到一个结果。

    String path = "C:/Users/0/Desktop/Git/Finance/Data/NQ100.csv";
    Reader buf = Files.newBufferedReader(Paths.get(path));
    CSVParser parsed = new CSVParser(buf, CSVFormat.DEFAULT.withFirstRecordAsHeader()
            .withIgnoreHeaderCase().withTrim());

    // Parse tickers
    Map<String, Integer> header = parsed.getHeaderMap();
    List<String> tickerList = new ArrayList<>(header.keySet());

    for (int x=1; x < tickerList.size(); x++) { <----------------------- PROBLEM

        // Accessing closing price by Header names
        List<Double> closeList = new ArrayList<>();
        for (CSVRecord record : parsed) {
            String stringClose = record.get(x);
            Double close = Double.valueOf(stringClose);
            closeList.add(close);
        }

        // Percentage Change
        List<Double> pctList = new ArrayList<>();
        for (int i=1; i < closeList.size(); i++) {
            Double pct = closeList.get(i) / closeList.get(i-1) - 1;
            pctList.add(pct);
        }

        // Statistics
        Double sum = 0.0, var = 0.0, mean, sd, rfr, sr;
        // Mean
        for (Double num : pctList) sum += num;
        mean = sum/pctList.size();
        // Standard Deviation
        for (Double num: pctList) var += Math.pow(num - mean, 2);
        sd = Math.sqrt(var/pctList.size());
        // Risk Free Rate
        rfr = Math.pow((1+0.03),(1/252.0))-1;
        // Sharpe Ratio
        sr = Math.sqrt(252) * ((mean-rfr)/sd);

        System.out.println(tickerList.get(x) + " " + sr);
    }

我的数据如下所示:

,AAL,AAPL,ADBE
2007-10-25,26.311651,23.141403,47.200001
2007-10-26,26.273216,23.384495,47.0
2007-10-29,26.004248,23.43387,47.0

所以我期待:

AAL XXX
AAPL XXX
ADBE XXX

但我得到了:

AAL 0.3604941921663456

如果你们能帮我找出问题,将不胜感激!

【问题讨论】:

    标签: java loops csv finance stock


    【解决方案1】:

    您只能在 Java 中遍历 Iterable 一次,在您的情况下,CSVParser parsed 实现了 Iterable&lt;CSVRecord&gt;

    因此,您仅在计算 AAL 的统计数据时才第一次遍历它,在分析 AAPLADBE 的数据期间,它会被当作​​空的处理。

    您可以通过 parsed 引入 helper list init 来处理此问题,在 for 之前添加下一个代码(它当然是单行解决方案,例如在 Java 8 中,但此选项也适用于早期版本)循环:

        List<CSVRecord> records = new ArrayList<>();
        for (CSVRecord record : parsed) {
            records.add(record);
        }
    

    然后更改下一行:

    for (CSVRecord record : records) {
    

    与:

    for (CSVRecord record : parsed) {
    

    对于您提供的 CSV,您将获得下一个输出:

    AAL -21.583101145880306
    AAPL 23.417753561072438
    ADBE -16.75343297000953
    

    【讨论】:

    • 哇,感谢marme1ad,它完美无瑕,解释也很好!所以看起来 records 是一个可迭代的 record (行)列表。这似乎具有为整个数据集创建另一个缓冲区的净效果。如果是这样,是否有更有效的方法来处理这些迭代器问题,或者这是标准解决方案?并且,创建 记录列表 仍然会使 Apache CSV 比手动解析 CSV(不创建 CSVRecord/Parse 对象)像 user3043452 建议的那样更有效吗?谢谢!!!
    • @JamesShen, CSVParser 很好用,因为它封装了 CSV 解析功能。假设 CSV 在内存中不太大且易于管理,我建议将您的逻辑分成两部分:首先将使用 CSVParser 并准备 Map&lt;String, List&lt;Double&gt;&gt;CSV标题作为键,收盘价列表作为值;第二个将根据这张地图计算统计数据。
    【解决方案2】:

    所以这是对我有用的代码块,如果我理解你的问题,你只想从 csv 文件中“读取”每一列和每一行,希望有所帮助。

            br = new BufferedReader(new InputStreamReader(new FileInputStream(archivo), "UTF8"));
            while ((line = br.readLine()) != null) {                
                if(a!=0){
                    String[] datos = line.split(cvsSplitBy);
                    System.out.println(datos[0] + " - " + datos[1] + " - " + datos[2]);
                }
                a++;
            }         
    

    【讨论】:

    • 您好,感谢您的意见。如果我无法让 Apache Commons 工作,我将像这样手动解析 CSV。 marme1ad 发现 CSVParser 只能迭代一次。但是,是的,像这样手动解析它们可以让循环更容易。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 2019-08-08
    • 1970-01-01
    • 2021-03-04
    • 2018-03-15
    • 2020-01-26
    • 2011-12-19
    相关资源
    最近更新 更多