【问题标题】:Comparing two csv files using given columns and build a third one using specific columns from the matching lines使用给定列比较两个 csv 文件,并使用匹配行中的特定列构建第三个文件
【发布时间】:2013-06-22 14:09:52
【问题描述】:

一个.csv:

12.23496740, -11.95760385, 3, 5, 11.1, 4
12.58295928, -11.39857395, 4, 7, 12.3, 6
12.42572572, -11.09478502, 2, 5, 12.3, 8
12.58300286, -11.95762569, 5, 11, 3.4, 7

两个.csv:

12.5830, -11.3986, .2, 4
12.4257, -11.0948, .7, 3

我想通过第 0 列和第 1 列匹配两个 csv 文件,并最终输出一个 csv 文件,其中包括 one.csv 中第 4 列和 two.csv 中第 2 列的相应值,如下所示:

三个.csv

12.5830, -11.3986, 12.3, .2
12.4257, -11.0948, 12.3, .7

【问题讨论】:

  • 您已经解释了您要解决的问题,但没有向我们展示您的代码以及它是如何不起作用的。请编辑您的问题以包含相关代码以及您获得的意外输出或错误(包括堆栈跟踪)。
  • 如果您知道one.csvtwo.csv 中的相关数字将相同到N 个小数位,那么round(value, N) 可能会对您有所帮助。

标签: python csv python-2.7 compare match


【解决方案1】:

我会将这两个 csv 文件读入列表列表,以便您拥有 csv1 和 csv2。然后循环遍历所有这些,你会这样做:

for e1 in csv1:
    for e2 in csv2:
         distance = d(e1[0],e1[1], e2[0], e2[1]) #using a function call to your distance formula

要保存结果,您可以使用字典,以便以后以简单的方式输出。所以在保存新条目时:

output_dict[(e1[0], e1[1])] = [e1[3], e2[3]]

【讨论】:

    【解决方案2】:

    我不确定您的问题究竟出在哪里。如果您想使用一种算法来根据坐标集计算距离,请随意使用以下代码:

    from math import radians, cos, sin, asin, sqrt
    
    def haversine(lat1, lng1, lat2, lng2, metric=False):
        """
        Calculate the great circle distance between two points 
        on the earth (specified in decimal degrees)
        """
        earths_radius_km = 6378.1
        # convert decimal degrees to radians 
        lat1, lng1, lat2, lng2 = map(radians, [lat1, lng1, lat2, lng2])
        # haversine formula 
        dlat = lat2 - lat1
        dlng = lng2 - lng1
        a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlng/2)**2
        c = 2 * asin(sqrt(a)) 
        km = earths_radius_km * c
        if not metric:
            km_to_miles = 0.621371192
            dist = km * km_to_miles
            units = 'miles'
        else:
            dist = km
            units = 'km'
        return dist, units
    
    if __name__ == '__main__':
        print 'Please call from within another script'
        # example...
        lat1, lng1, lat2, lng2 = 51.0820266, 1.1834209, 52.4931226, -2.1786751
        print 'e.g. distance in km is:', haversine(lat1, lng1, lat2, lng2, True)
        print 'e.g. distance in miles is:', haversine(lat1, lng1, lat2, lng2)
    

    如果我理解正确,您想遍历一个文件中的坐标并在另一个文件中找到最接近的匹配项吗?如果是这种情况,只需将 min_distance 初始化为任意高的值,例如1000000 对于第一组中的每个值,然后循环通过第二组坐标调用上面的公式(或您要使用的任何距离函数),如果结果小于当前 min_distance 并将 min_distance 重置为结果(并存储额外的您需要从临时变量中的第二个列表中获取的值,每次找到较低距离时都将被覆盖)。一旦你完成了内循环中的所有迭代,你就可以在开始外循环的下一次迭代之前将你需要的数据存储在一个列表中。

    【讨论】:

      【解决方案3】:

      我认为这不是很好的答案,但是您的问题的解决方案如下:

      import sys
      import math
      
      def dist(point1, point2):
        return math.sqrt((point1[0]-point2[0])**2 + (point1[1]-point2[1])**2)
      
      one = []
      two = []
      
      with open('one.csv', 'r') as f:
          for line in f.readlines():
              x, y, _, _, _4, _ = line.split(',')
              one.append((float(x), float(y), float(_4)))
      
      with open('two.csv', 'r') as f:
          for line in f.readlines():
              x, y, _2, _ = line.split(',')
              two.append((float(x), float(y), float(_2)))
      
      with open('three.csv', 'w') as f:
          for point in two:
              nearest = None
              distance = sys.float_info.max
              for point2 in one:
                  d = dist(point2, point)
                  if d < distance:
                      distance = d
                      nearest = point2
              f.write("%f, %f, %f, %f\n" % (point[0], point[1], nearest[2], point[2]))
      

      将产生输出到三个.csv:

      12.583000, -11.398600, 12.300000, 0.200000
      12.425700, -11.094800, 12.300000, 0.700000
      

      如果需要格式化,在sn-p的最后一行就行了。

      【讨论】:

      • 不,是的,如果您的点实际上是地理点,您应该使用@ChrisProsser 提到的Haversine 距离——替换我对dist() 函数的实现
      • 谢谢!但是,输出 csv 第三列应为 12.3, 12.3,因为这些是 one.csv(第 4 列)中这些坐标的对应值。
      • 已修复!最后一个字符串的错字,应该是 nearest[2] 而不是 point2[2]
      • 这在我的测试文件上效果很好,但是当我尝试在我的真实 csv 文件(其中 one.csv 是 24 列长,而 two.csv 是 46 列长)上运行它时,我得到了错误ValueError:解包的值太多。我只是更改了行分割线以包括每个 csv 有多少列。
      【解决方案4】:

      使用numpy 有一个优雅的解决方案:

      def compare_files( f1name, f2name, f3name, ctc1, ctc2, columns, TOL=0.001 ):
          f1 = np.loadtxt( f1name, delimiter=',' )
          f2 = np.loadtxt( f2name, delimiter=',' )
          check = np.logical_and( *[np.absolute(s.outer(f1[:,i], f2[:,j])) < TOL for i,j in zip(ctc1,ctc2)] )
          chosen1 = f1[np.any( check, axis=1 )]
          chosen2 = f2[np.any( check, axis=0 )]
          newshape = (2,f1.shape[0],f2.shape[0])
          ind = np.indices(check.shape)[np.vstack((check,check)).reshape(newshape)]
          ind1 = ind[:len(ind)/2]
          ind2 = ind[len(ind)/2:]
      
          new = np.concatenate( [eval(f)[ind1, c][:,None] if f=='f1' else\
                                 eval(f)[ind2, c][:,None] \
                                 for f,c in columns], axis=1 )
          np.savetxt(f3name, new, delimiter=',', fmt='%f')
      

      该功能是通用的,可以应用于您问题中描述的情况如下:

      f1name = 'one.csv'
      f2name = 'two.csv'
      f3name = 'three.csv'
      ctc1 = [0,1] # columns to compare from file 1
      #       ^ ^
      #       | | # this arrows are just to emphisize who is compared with who...
      #       v v
      ctc2 = [0,1] # columns to compare from file 2
      columns = [['f2',0], # file 2 column 0
                 ['f2',1], # file 2 column 1
                 ['f1',4], # file 1 column 4
                 ['f1',2]] # file 1 column 2
      TOL = 0.001
      compare_files( f1name, f2name, f3name, ctc1, ctc2, columns, TOL )
      

      ctc1ctc2 将告诉函数要比较哪些列 (ctc)。 columns 将告诉如何构建新文件。在此示例中,它使用来自 f2 的第 0 列,然后是第 1 列,然后是第 4 列形成 f1,然后是第 2 列。

      使用one.csv进行测试:

      12.23496740, -11.95760385, 3, 5, 11.1, 4
      12.58295928, -11.39857395, 4, 7, 12.3, 6
      12.42572572, -11.09478502, 2, 5, 12.3, 8
      12.58300286, -11.95762569, 5, 11, 3.4, 7
      

      还有two.csv:

      12.43, -11.0948, .7, 3
      12.43, -11.0948, .7, 3
      12.4257, -11.0948, .7, 3
      12.43, -11.0948, .7, 3
      12.5830, -11.3986, .2, 4
      

      three.csv

      12.583000,-11.398600,12.300000,0.200000
      12.425700,-11.094800,12.300000,0.700000
      

      【讨论】:

      • 谢谢!因此,我尝试将其应用于我的实际 csv 文件,这些文件的长度为 24 列和 46 列,但在第 9 行出现错误“ValueError:新数组的总大小必须保持不变”。我不确定要更改什么形状数组到,因为这样做的一部分是查看我得到了多少匹配项。有没有办法修改此代码以考虑到这一点?谢谢!
      • 是的,当然...重塑是硬编码的,现在我更新了答案...如果您要获取值的列是其他列,则必须更改 logical_and()还有concatenate 命令...
      • logical_and()和concatenate命令应该改成什么?
      • @user2520932 现在答案变得更笼统了,您只需将正确的参数传递给函数,以便以您想要的方式比较和构建新的csv...跨度>
      • 结合 numpy 数学和 pandas 来处理 csv 数据,应该就是这样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多