【问题标题】:How do I match multiple columns in two separate files and only output the rows where all three column values match?如何匹配两个单独文件中的多个列,并且只输出所有三个列值都匹配的行?
【发布时间】:2021-03-01 06:24:36
【问题描述】:

我有两个大文件。第一个看起来像这样:

PLATEID MJD FIBERID LGM_TOT_P50 OH_P50  SFR_TOT_P50 SPECSFR_TOT_P50 Index
------- --- ------- ----------- ------  ----------- --------------- -----
266 51602   1   10.294701   -9999.0 -0.5206503  -10.87437   1
266 51602   2   11.162018   -9999.0 -0.34972167 -11.567741  2
266 51602   3   -9999.0 -9999.0 -9999.0 -9999.0 3

第二个看起来像这样:

col1    col2_1  col7_1  col3_2  col4_1  col5_2  col7_2  col4_2  col3    col4    col5    Index
----    ------  ------  ------  ------  ------  ------  ------  ----    ----    ----    -----
114 2244    14.2824 42.796721558    0.941932669 0.1921383   -11.9826088 -0.233108   51871   409 601 1
325 3669    14.0476 56.956485129    1.027377082 0.1799167   -10.5876274 0.6275974   52901   1242    375 2
351 3806    14.3661 58.387142242    1.042578256 0.0762465   -11.5828028 -0.6205882  52901   1242    610 3

我知道这些非常混乱,但本质上我想将这两个组合成一个文件。我想匹配以下列:

MJD(文件 1)和 col3(文件 2)
PLATEID(文件 1)和 col4(文件 2)
FIBERID(文件 1)和第 5 列(文件 2)

新文件应包含满足上述所有三个条件的行:

col1    col2_1  col7_1  col3_2  col4_1  col5_2  col7_2  col4_2  col3    col4    col5    Index PLATEID MJD FIBERID LGM_TOT_P50 OH_P50  SFR_TOT_P50 SPECSFR_TOT_P50 Index
721 37102   14.1816 167.791828441   0.625389832 0.0250531   -10.6558456 -0.4704049  -1  -1  -1  7 -1    -1  -1  0.0 0.0 0.0 0.0 7

到目前为止,我已经尝试过这个 awk 命令:

awk -F'|' '
FNR==NR{
    a[$9,$10,$11]=(a[$9,$10,$11]?a[$9,$10,$11] ORS:"")$0
    next
}
(($2,$1,$3) in a){
    print a[$2,$1,$3]
}' file2 file1 > catalog.txt

但是这个输出文件最终是完全空白的。我也尝试了 Pandas DataFrame,但出现了 TypeError。我的代码是

f = pd.DataFrame(data=file2[1:,1:],
                index=file2[1:,0:],
                columns=file2[0:,1:])

(我对文件 1 做了同样的事情)。错误是:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-f7663abb5cdb> in <module>
      5 sdss = pd.read_csv("/Users/emmalovett/research/galSpecExtra-dr8", header = 2)
      6 
----> 7 f = pd.DataFrame(data=IDcat[1:,1:],
      8                 index=IDcat[1:,0:],
      9                 columns=IDcat[0:,1:])

~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/frame.py in __getitem__(self, key)
   2798             if self.columns.nlevels > 1:
   2799                 return self._getitem_multilevel(key)
-> 2800             indexer = self.columns.get_loc(key)
   2801             if is_integer(indexer):
   2802                 indexer = [indexer]

~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
   2644                 )
   2645             try:
-> 2646                 return self._engine.get_loc(key)
   2647             except KeyError:
   2648                 return self._engine.get_loc(self._maybe_cast_indexer(key))

pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()

pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()

TypeError: '(slice(1, None, None), slice(1, None, None))' is an invalid key

感谢任何帮助——我没有使用 awk 或 Pandas 的经验。蒂亚!!

【问题讨论】:

  • 您的 awk 脚本以 awk -F'|' 开头,这意味着它需要以 | 分隔的数据,但在您发布的示例输入中没有 |s。如果您的真实数据是|-separated,则发布|-separated 示例数据,这样您就不会最终解决您没有的问题。还要根据您发布的示例输入添加预期的输出。
  • @EdMorton 啊,好吧,我拿出了 -F ' | '这似乎奏效了。我在我的问题中添加了预期的输出,但恐怕它看起来没有多大意义。我希望输出具有 all both 文件的列;现在,awk 命令只给我文件 2 中两个文件之间的列匹配的行。有没有办法让我将文件 1 中的列包含到输出中?我还注意到输出比文件 1 或 2 大得多,这没有多大意义。
  • 您发布的预期输出必须是您发布的输入的预期输出,而不仅仅是可能从某些不同输入输出的随机文本行。我们需要一些可以测试潜在解决方案的东西。

标签: python pandas dataframe awk


【解决方案1】:

这可能是你想要的:

$ cat tst.awk
NR==FNR {
    a[$9 FS $10 FS $11] = $0
    next
}
{ key = $2 FS $1 FS $3 }
key in a {
    print a[key], $0
}

$ awk -f tst.awk file2 file1

考虑到你发布的输入,它不会产生任何输出,所以如果这真的是你所期望的,那么我知道。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 2018-07-12
    • 2018-10-25
    相关资源
    最近更新 更多