Python Pandas / Numpy的match()函数在Python中有什么等效的函数?

7

我是一个R语言用户,我无法找到pandas中match()函数的等效函数。我需要使用此函数遍历一堆文件,获取关键信息,并将其合并回“url”上的当前数据结构中。在R中,我会这样做:

logActions <- read.csv("data/logactions.csv")
logActions$class <- NA

files = dir("data/textContentClassified/")
for( i in 1:length(files)){
    tmp <- read.csv(files[i])
    logActions$class[match(logActions$url, tmp$url)] <- 
            tmp$class[match(tmp$url, logActions$url)]
}

我认为我不能使用merge()或join(),因为每次都会覆盖logActions$class。我也不能使用update()或combine_first(),因为它们都没有必要的索引功能。我还尝试了基于this SO post的match()函数,但无法弄清楚如何将其与DataFrame对象配合使用。如果我忽略了一些明显的东西,请原谅。
这里是一些Python代码,总结了我在pandas中无效尝试的一些操作:
from pandas import *
left = DataFrame({'url': ['foo.com', 'foo.com', 'bar.com'], 'action': [0, 1, 0]})
left["class"] = NaN
right1 = DataFrame({'url': ['foo.com'], 'class': [0]})
right2 = DataFrame({'url': ['bar.com'], 'class': [ 1]})

# Doesn't work:
left.join(right1, on='url')
merge(left, right, on='url')

# Also doesn't work the way I need it to:
left = left.combine_first(right1)
left = left.combine_first(right2)
left 

# Also does something funky and doesn't really work the way match() does:
left = left.set_index('url', drop=False)
right1 = right1.set_index('url', drop=False)
right2 = right2.set_index('url', drop=False)

left = left.combine_first(right1)
left = left.combine_first(right2)
left

所需输出为:
    url  action  class
0   foo.com  0   0
1   foo.com  1   0
2   bar.com  0   1

但是,我需要能够反复调用它,以便可以迭代每个文件。


这个主题可能是最相关的,链接如下:https://pandas.pydata.org/pandas-docs/stable/getting_started/comparison/comparison_with_r.html#match - Roman Luštrik
3个回答

10
请注意存在 pandas.match,它正是 R 的 match 所做的事情。

嘿Wes,你能帮我找一下pandas.match的文档吗?我在这里http://pandas.pydata.org/pandas-docs/stable/api.html和http://pandas.pydata.org/pandas-docs/stable/genindex.html#M都没看到。谢谢! - Solomon
输入:pd.match([1,2,3],[1,2]) 输出:array([0, 1, -1], dtype=int64)。它似乎对于匹配第二个数组中的第一个值给出0,对于匹配第二个值给出1,以此类推,并在未匹配时给出-1。 - seumas
请注意这个解决方案。pd.match([1,2,3,5,8,2],[1,2,4,5,9,2]) 会产生 array([ 0, 5, -1, 3, -1, 5]) 的结果。它只会返回单个匹配项,而不是像你希望的那样返回1和5。 - mike
请注意,pandas.match 已经被弃用了几年,但是如果您的数据是唯一的,Index.get_indexer非常有效,否则可以参考这个答案 - Jthorpe

1

编辑:

如果所有正确数据框中的url都是唯一的,您可以将正确的数据框作为由url索引的class系列,然后通过索引左侧中每个url来获取其类别。

from pandas import *
left = DataFrame({'url': ['foo.com', 'bar.com', 'foo.com', 'tmp', 'foo.com'], 'action': [0, 1, 0, 2, 4]})
left["klass"] = NaN
right1 = DataFrame({'url': ['foo.com', 'tmp'], 'klass': [10, 20]})
right2 = DataFrame({'url': ['bar.com'], 'klass': [30]})

left["klass"] = left.klass.combine_first(right1.set_index('url').klass[left.url].reset_index(drop=True))
left["klass"] = left.klass.combine_first(right2.set_index('url').klass[left.url].reset_index(drop=True))

print left

这是你想要的吗?
import pandas as pd
left = pd.DataFrame({'url': ['foo.com', 'foo.com', 'bar.com'], 'action': [0, 1, 0]})
left["class"] = NaN
right1 = pd.DataFrame({'url': ['foo.com'], 'class': [0]})
right2 = pd.DataFrame({'url': ['bar.com'], 'class': [ 1]})

pd.merge(left.drop("class", axis=1), pd.concat([right1, right2]), on="url")

输出:

   action      url  class
0       0  foo.com      0
1       1  foo.com      0
2       0  bar.com      1

如果左侧的类别列不全为NaN,您可以将其与结果合并。

谢谢,但我需要为每个文件调用一次match()等效函数,所以这种方法行不通 :( - Solomon
在每个正确的数据框中是唯一的(但可以在数据框之间重复)。理想情况下,解决方案应该对这个问题不加区分。但我认为按URL索引的类是正确的方法。 - Solomon

0

这是我最终采用的完整代码:

#read in df containing actions in chunks:
tp = read_csv('/data/logactions.csv', 
  quoting=csv.QUOTE_NONNUMERIC,
  iterator=True, chunksize=1000, 
  encoding='utf-8', skipinitialspace=True,
  error_bad_lines=False)
df = concat([chunk for chunk in tp], ignore_index=True)

# set classes to NaN
df["klass"] = NaN
df = df[notnull(df['url'])]
df = df.reset_index(drop=True)

# iterate over text files, match, grab klass
startdate = date(2013, 1, 1)
enddate = date(2013, 1, 26) 
d = startdate

while d <= enddate:
    dstring = d.isoformat()
    print dstring

    # Read in each file w/ classifications in chunks
    tp = read_csv('/data/textContentClassified/content{dstring}classfied.tsv'.format(**locals()), 
        sep = ',', quoting=csv.QUOTE_NONNUMERIC,
        iterator=True, chunksize=1000, 
        encoding='utf-8', skipinitialspace=True,
        error_bad_lines=False)
    thisdatedf = concat([chunk for chunk in tp], ignore_index=True)
    thisdatedf=thisdatedf.drop_duplicates(['url'])
    thisdatedf=thisdatedf.reset_index(drop=True)

    thisdatedf = thisdatedf[notnull(thisdatedf['url'])]
    df["klass"] = df.klass.combine_first(thisdatedf.set_index('url').klass[df.url].reset_index(drop=True))

    # Now iterate
    d = d + timedelta(days=1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接