Python 如何将.loc与groupby一起使用,以便基于分组数据创建新列;你不认为是副本吗?
我有一个包含多组数据的CSV文件,正在使用Python 如何将.loc与groupby一起使用,以便基于分组数据创建新列;你不认为是副本吗?,python,pandas,dataframe,pandas-groupby,Python,Pandas,Dataframe,Pandas Groupby,我有一个包含多组数据的CSV文件,正在使用groupby()方法将它们分离。每个组都经过一点简单的数学处理,包括对两列使用min()和max(),以及一点减法和乘法来创建新的数据列。然后,我绘制每组的图表。这基本上是可行的,但我对我的代码图有两个抱怨——它们是单独的,而不是我喜欢的组合;我在每个组中都会看到“SettingWithCopyWarning”。从我的搜索中,我相信解决方案要么是使用.loc,要么是使用更好的拆分应用(并可能结合)方法。 我可以在Excel中完成这项工作,但我正在尝试学
groupby()
方法将它们分离。每个组都经过一点简单的数学处理,包括对两列使用min()
和max()
,以及一点减法和乘法来创建新的数据列。然后,我绘制每组的图表。这基本上是可行的,但我对我的代码图有两个抱怨——它们是单独的,而不是我喜欢的组合;我在每个组中都会看到“SettingWithCopyWarning”。从我的搜索中,我相信解决方案要么是使用.loc
,要么是使用更好的拆分应用(并可能结合)方法。
我可以在Excel中完成这项工作,但我正在尝试学习Python,并且,在我的代码运行时,我希望改进它
import os.path
import sys
import pandas as pd
filename = "data/cal_data.csv"
df = pd.read_csv(filename, header=0) #one line of headers
df['Test']="Model "+df['Model No'] +", SN "+ df['Serial No'].values.astype(str) +", Test time "+ df['Test time'].values.astype(str) # combining several columns into a single column that makes grouping straight-forward, and simplifies titles of graphs. Not completely necessary.
df = df[df.index <= df.groupby('Test')['Test Point'].transform('idxmax')]#drop rows after each max test point
for title, group in df.groupby('Test'):
x1, x2 = min(group["Test Reading"]),max(group["Test Reading"])
x4, x3 = max(group["Test Point"]),min(group["Test Point"]) #min is usually zero
R=(x2-x1)/(x4-x3) #linearize
group['Test Point Error']=100*(group['Test Reading']- (group['Test Point']*R+x1))
ax=group.plot(x='Test Point', y='Test Point Error', title=title, grid=True)
ax.set_ylabel("% error (+/-"+str(Error_Limit)+"% limit)")
编辑-添加了来自df.head(20)
的输出,以及一对绘图的图像:
Test Point Test Reading Test
0 0 0.10453 Model LC-500, SN 937618, Test time 17:20:10
1 20 0.17271 Model LC-500, SN 937618, Test time 17:20:10
2 50 0.27838 Model LC-500, SN 937618, Test time 17:20:10
3 100 0.45596 Model LC-500, SN 937618, Test time 17:20:10
4 150 0.63435 Model LC-500, SN 937618, Test time 17:20:10
5 200 0.81323 Model LC-500, SN 937618, Test time 17:20:10
6 250 0.99252 Model LC-500, SN 937618, Test time 17:20:10
7 300 1.17222 Model LC-500, SN 937618, Test time 17:20:10
8 350 1.35219 Model LC-500, SN 937618, Test time 17:20:10
9 400 1.53260 Model LC-500, SN 937618, Test time 17:20:10
10 450 1.71312 Model LC-500, SN 937618, Test time 17:20:10
11 500 1.89382 Model LC-500, SN 937618, Test time 17:20:10
14 0 0.10468 Model LC-500, SN 937618, Test time 17:31:46
15 20 0.17284 Model LC-500, SN 937618, Test time 17:31:46
16 50 0.27856 Model LC-500, SN 937618, Test time 17:31:46
17 100 0.45609 Model LC-500, SN 937618, Test time 17:31:46
18 150 0.63457 Model LC-500, SN 937618, Test time 17:31:46
19 200 0.81341 Model LC-500, SN 937618, Test time 17:31:46
20 250 0.99277 Model LC-500, SN 937618, Test time 17:31:46
21 300 1.17237 Model LC-500, SN 937618, Test time 17:31:46
编辑/更新2020年7月23日:
我做了一些变通办法,使这项工作,但我仍然感谢任何帮助。下面是修改后的for循环代码,将每个组写入一个新的csv文件以供以后读取(这样我可以添加在此处创建的新列),如果临时文件已经存在,还可以删除它:
if os.path.exists("data/temp.csv"):
os.remove("data/temp.csv")
for title, group in df.groupby('Test'):
x1 = min(group["Test Reading"].head(1))
x2 = max(group["Test Reading"].tail(1))
x3 = min(group["Test Point"].head(1))
x4 = max(group["Test Point"].tail(1))
R=(x2-x1)/(x4-x3) #linearization scalar
group['Test Point Error'] =100*(group['Test Reading']- (group['Test Point']*R+x1))/(x2-x1)
file = open('data/temp.csv','a')
group.to_csv('data/temp.csv', mode="a", index=False, columns=columns, header=False)#, header=True, index=True, index_label=None, mode='w', encoding=None, compression='infer', quoting=None, quotechar='"', line_terminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal='.'))
file.close()
然后,读取临时csv,我使用seaborn(import seaborn as sns
和import matplotlib.pyplot as plt
将多个组绘制在一起,按序列号分组,每行4个子批
df = pd.read_csv('data/temp.csv', header=0)
df['Model/SN']=df['Model No']+" / "+df['Serial No'].values.astype(str)
g = sns.FacetGrid(df, col='Model/SN', hue='Test', col_wrap=4, sharey=False, sharex=False)
g.map(plt.axhline, y=Error_Limit, ls='--', c='red')
g.map(plt.axhline, y=-Error_Limit, ls='--', c='red')
g = g.map(sns.lineplot, 'Test Point', 'Test Point Error', ci=None)
总结-这些修复并不理想;它们是解决方案,我仍然收到“SettingWithCopyWarning”错误。因此您要求:
group['Test Point Error']=100*(group['Test Reading']- (group['Test Point']*R+x1))
与
这将为每个组添加一个序列,索引与df.index匹配。完成后,df中的每一行将有一行错误。因此,退出for循环后:
df.assign(test_point_error=pd.concat(error_list))
将完全匹配每一行,而不考虑df上的任何排序
---编辑结束---
子绘图问题与此类似,您在循环时分别绘制每个组。如果您在退出for loop后绘制,则
df.groupby().plot(subplots=True)
我会给你想要的
在另一个主题中,我将取消“Test”的字符串连接,并执行以下操作:
df.groupby(['Model No', 'Serial No', 'Test Time'])
如果有许多行,这可能会使您的代码更快。因此您要求:
group['Test Point Error']=100*(group['Test Reading']- (group['Test Point']*R+x1))
与
这将为每个组添加一个序列,索引与df.index匹配。完成后,df中的每一行将有一行错误。因此,退出for循环后:
df.assign(test_point_error=pd.concat(error_list))
将完全匹配每一行,而不考虑df上的任何排序
---编辑结束---
子绘图问题与此类似,您在循环时分别绘制每个组。如果您在退出for loop后绘制,则
df.groupby().plot(subplots=True)
我会给你想要的
在另一个主题中,我将取消“Test”的字符串连接,并执行以下操作:
df.groupby(['Model No', 'Serial No', 'Test Time'])
如果有许多行,这可能会使您的代码更快。谢谢您的建议。我不确定创建序列列表的过程是什么样子。我尝试了字符串串联替换-它确实运行得更快,但每个序列号除了一个组外,我失去了所有组。也许我需要获得您对子批次工作的建议首先是ing(使用系列列表,我不确定如何将每个新系列正确地附加到该列表中…)谢谢你的建议。我不确定创建序列列表是什么样子。我尝试了字符串串联替换-它确实运行得更快,但每个序列号除了一个组外,我丢失了所有组。也许我需要先得到你关于子批次的建议(带有系列列表,我不知道如何正确地将每个新系列附加到此列表中…)