python - 熊猫中两个列表的逐行差异
问题描述
我正在使用pandas
增量查找新元素,即对于每一行,我会查看列表中的值是否以前见过。如果是,我们将忽略它们。如果没有,我们将选择它们。
我可以使用 来做到这一点row.iterrows()
,但我有 >1M 行,所以我相信矢量化apply
可能会更好。
这是示例数据和代码。运行此代码后,您将获得预期的输出:
from numpy import nan as NA
import collections
df = pd.DataFrame({'ID':['A','B','C','A','B','A','A','A','D','E','E','E'],
'Value': [1,2,3,4,3,5,2,3,7,2,3,9]})
#wrap all elements by group in a list
Changed_df=df.groupby('ID')['Value'].apply(list).reset_index()
Changed_df=Changed_df.rename(columns={'Value' : 'Elements'})
Changed_df=Changed_df.reset_index(drop=True)
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
Changed_df["Elements_s"]=Changed_df['Elements'].shift()
#attempt 1: For loop
Changed_df["Diff"]=NA
Changed_df["count"]=0
Elements_so_far = []
#replace NA with empty list in columns that will go through list operations
for col in ["Elements","Elements_s","Diff"]:
Changed_df[col] = Changed_df[col].apply(lambda d: d if isinstance(d, list) else [])
for idx,row in Changed_df.iterrows():
diff = list(set(row['Elements']) - set(Elements_so_far))
Changed_df.at[idx, "Diff"] = diff
Elements_so_far.append(row['Elements'])
Elements_so_far = flatten(Elements_so_far)
Elements_so_far = list(set(Elements_so_far)) #keep unique elements
Changed_df.loc[idx,"count"]=diff.__len__()
关于代码的注释:
- 我不喜欢这段代码,因为它笨重且效率低下。
- 我说的是效率低下,因为我创建
Elements_s
了持有转移值的东西。效率低下的另一个原因是for
循环遍历行。
- 我说的是效率低下,因为我创建
Elements_so_far
跟踪我们为每一行发现的所有元素。如果出现了新元素,我们将其计入Diff
列中。- 我们还跟踪在
count
列中发现的新元素的长度。
如果专家可以帮助我提供代码的矢量化版本,我将不胜感激。
我确实尝试了矢量化版本,但我不能走得太远。
#attempt 2:
Changed_df.apply(lambda x: [i for i in x['Elements'] if i in x['Elements_s']], axis=1)
我的灵感来自如何将两列都与字符串列表进行比较并创建一个具有唯一项的新列?做上面,但我做不到。链接的 SO 线程在列之间进行逐行差异。
我正在使用 Anaconda 的 Python 3.6.7。熊猫版本是 0.23.4
解决方案
您可以使用sort
然后使用 numpy 来获取unique
索引,然后构建您的分组,例如:
In []:
df = df.sort_values(by='ID').reset_index(drop=True)
_, i = np.unique(df.Value.values, return_index=True)
df.iloc[i].groupby(df.ID).Value.apply(list)
Out[]:
ID
A [1, 2, 3, 4, 5]
D [7]
E [9]
Name: Value, dtype: object
或者接近你当前的输出:
In []:
df = df.sort_values(by='ID').reset_index(drop=True)
_, i = np.unique(df.Value.values, return_index=True)
s1 = df.groupby(df.ID).Value.apply(list).rename('Elements')
s2 = df.iloc[i].groupby(df.ID).Value.apply(list).rename('Diff').reindex(s1.index, fill_value=[])
pd.concat([s1, s2, s2.apply(len).rename('Count')], axis=1)
Out[]:
Elements Diff Count
ID
A [1, 4, 5, 2, 3] [1, 2, 3, 4, 5] 5
B [2, 3] [] 0
C [3] [] 0
D [7] [7] 1
E [2, 3, 9] [9] 1
推荐阅读
- sql - SQL:复合主键作为外键
- python-3.x - 如果任何任务引发异常,Python asyncio.gather() 不会返回结果
- java - 如何向此代码添加用户代理,以便不再收到错误 403 异常?我正在尝试为股票筛选器抓取数据
- python - 安装打开的datacube,无法启动postgressql
- css - 图像的 Flexbox 纵横比?
- apache-kafka - 如果自动提交为假,当同一组中的 2 个消费者想要从同一主题中读取时会发生什么
- reactjs - 在 Windows Server 2008 R2 上的 IIS 上发布的 React 应用程序显示空白页
- mysql - 尝试执行更新查询,其中行是来自 TEdit 的变量
- r - 对导入的 .xlsx 数据集运行线性回归,将列的每一行作为系数返回,而不仅仅是列名
- swift - AVPlayer 字幕选择屏幕的完成按钮始终为白色