数据框的复杂过滤
我刚开始使用Pandas这个工具,想弄清楚它是否适合我的问题。
我有一个数据集:
date, sourceid, destid, h1..h12
我主要想要的是H1到H12这些列的总和,但我需要从数据集中排除一些特定的范围。
比如说,我想:
排除H4、H5、H6这些数据,当sourceid等于4944时;还有排除H8、H9到H12这些数据,当destination等于481981时,等等……
... 这样的过滤条件可能会有很多,因为我们不断地在去掉数据,以便接近我们的最终模型。
我记得看到过一个解决方案,里面提到可以先建立一个过滤条件的列表,然后创建一个函数来进行测试,但我还没找到一个好的例子来参考。
我最初的想法是先复制一份数据,然后把我们不想要的数据删掉,如果需要的话再从原始数据中复制回来,但这样做似乎不是个好主意。
2 个回答
你可以用 DataFrame.ix[]
来把数据设置为零。
首先,先创建一个空的 DataFrame:
N = 10000
df = pd.DataFrame(np.random.rand(N, 12), columns=["h%d" % i for i in range(1, 13)], index=["row%d" % i for i in range(1, N+1)])
df["sourceid"] = np.random.randint(0, 50, N)
df["destid"] = np.random.randint(0, 50, N)
然后,对于你的每个筛选条件,你可以调用:
df.ix[df.sourceid == 10, "h4":"h6"] = 0
因为你有60万行数据,使用 df.sourceid == 10
来创建一个筛选数组可能会比较慢。你可以创建一些 Series 对象,把值映射到 DataFrame 的索引上:
sourceid = pd.Series(df.index.values, index=df["sourceid"].values).sort_index()
destid = pd.Series(df.index.values, index=df["destid"].values).sort_index()
接着,可以通过以下方式排除掉 sourceid 为 10 的 h4、h5、h6:
df.ix[sourceid[10], "h4":"h6"] = 0
要找到 sourceid 为 10 且 destid 为 20 的行 ID,可以这样做:
np.intersect1d(sourceid[10].values, destid[20].values, assume_unique=True)
要找到 sourceid 在 10 到 12 之间,且 destid 在 3 到 5 之间的行 ID,可以这样做:
np.intersect1d(sourceid.ix[10:12].values, destid.ix[3:5].values, assume_unique=True)
sourceid 和 destid 是带有重复索引值的 Series,当索引值有序时,Pandas 会使用 searchsorted 来查找索引。这种方法的效率是 O(log N),比创建筛选数组的 O(N) 要快。
通过使用“掩码”,你不需要从数据框中删除数据。例如:
mask1 = df.sourceid == 4944
var1 = df[mask1]['H4','H5','H6'].sum()
或者你可以直接这样做:
var1 = df[df.sourceid == 4944]['H4','H5','H6'].sum()
如果有多个过滤条件,你可以用布尔运算符把这些布尔掩码结合起来:
totmask = mask1 & mask2