Python 根据条件拆分为不同的行
我有一个如下所示的数据框:Python 根据条件拆分为不同的行,python,pandas,grouping,Python,Pandas,Grouping,我有一个如下所示的数据框: data = [ [101, '1987-09-01', 1, 1, '1987-09-01', 2, 2], [102, '1987-09-01', 1, 1, '1999-09-01', 2, 2], [103, 'nan', 0, 0, '1999-09-01', 2, 2] ] df = pd.DataFrame(data, columns=['ID', 'Date1', 'x1', 'y1', 'Date2', 'x2', 'y2']
data = [
[101, '1987-09-01', 1, 1, '1987-09-01', 2, 2],
[102, '1987-09-01', 1, 1, '1999-09-01', 2, 2],
[103, 'nan', 0, 0, '1999-09-01', 2, 2]
]
df = pd.DataFrame(data, columns=['ID', 'Date1', 'x1', 'y1', 'Date2', 'x2', 'y2'])
df['Date1'] = pd.to_datetime(df['Date1'])
df['Date2'] = pd.to_datetime(df['Date2'])
我的目标
如果日期列的值在一行中相同,则添加聚合x和y值。
如果它们不相同,请将行拆分为两行,并保持值不变
用(伪)代码解释:
另一个挑战是,包含日期的列可以少于或多于2列。但列名将始终包含字符串“Date”。例如,如果有三个具有三个不同值的不同日期列,则目标是创建三行。如果只有一个日期列,则无需进行任何修改
预期结果
用于先重塑形状,然后聚合sum
:
df1 = pd.wide_to_long(df.reset_index(),
stubnames=['Date','x','y'],
i=['index','ID'],
j='tmp')
df1 = df1.groupby(['index','ID','Date']).sum().reset_index(level=0, drop=True).reset_index()
print (df1)
ID Date x y
0 101 1987-09-01 3 3
1 102 1987-09-01 1 1
2 102 1999-09-01 2 2
3 103 1999-09-01 2 2
4 103 nan 0 0
如果ID
值是唯一的,则应简化解决方案:
df1 = pd.wide_to_long(df,
stubnames=['Date','x','y'],
i='ID',
j='tmp')
df1 = df1.groupby(['ID','Date']).sum().reset_index()
print (df1)
ID Date x y
0 101 1987-09-01 3 3
1 102 1987-09-01 1 1
2 102 1999-09-01 2 2
3 103 1999-09-01 2 2
4 103 nan 0 0
编辑:
如果列名称不以1,2
结尾,则与日期列类似,您可以通过前两个字母对其进行规范化,然后应用上述解决方案(更改存根名称):
编辑2:我尝试创建更通用的解决方案:
data = [
[101, '1987-09-01', 1, 1, '1987-09-01', 2, 2, 3],
[102, '1987-09-01', 1, 1, '1999-09-01', 2, 2, 3],
[103, 'nan', 0, 0, '1999-09-01', 2, 2, 3]
]
df = pd.DataFrame(data, columns=['ID', 'Date1', 'OPxx', 'NPxy', 'Date2',
'OPyy', 'NPyx', 'WZ'])
df['Date1'] = pd.to_datetime(df['Date1'])
df['Date2'] = pd.to_datetime(df['Date2'])
s = df.columns.to_series()
#get first 2 characters
s1 = s.str[:2]
#create groups starting by ID and Da (first 2 letters of Date)
s2 = s1.isin(['ID','Da']).cumsum().astype(str)
s = s1 + s2
print (s)
ID ID1
Date1 Da2
OPxx OP2
NPxy NP2
Date2 Da3
OPyy OP3
NPyx NP3
WZ WZ3
dtype: object
然后使用exclude
ID
和index
创建子名称dynames-s1的所有唯一值:
print(np.setdiff1d(s1.unique(), ['ID', 'index']))
['Da' 'NP' 'OP' 'WZ']
df1 = pd.wide_to_long(df.reset_index(),
stubnames=np.setdiff1d(s1.unique(), ['ID', 'index']),
i=['index','ID1'],
j='tmp')
合计金额:
df2 = (df1.groupby(['index','ID1','Da'])
.sum()
.reset_index(level=0, drop=True)
.reset_index())
print (df2)
ID1 Da NP OP WZ
0 101 1987-09-01 3 3 3.0
1 102 1987-09-01 1 1 0.0
2 102 1999-09-01 2 2 3.0
3 103 1999-09-01 2 2 3.0
谢谢这确实满足了我的要求。然而,我的列名比我最初在示例中指出的要复杂一些。是否可以根据列字符串的前两个字符对列进行分组?请参阅编辑后的问题。@bjornvandijkman-不太容易,解决方案最好是将每个
OP
,NP
标准化为OP1,NP1
,OP2,NP2
,就像第一个解决方案一样。您好,jaezrael。这个现在很好用。但是,每当引入一个以前从未见过的新列时,它就会中断(请参见我的编辑)。问题是,现在每当进行拆分时,该值都会添加到第一行,因为我猜分组是基于“stubnames”完成的。因此,我认为在找到带有日期的新列之前,为“Date”旁边的列指定相同的stubname是可行的。但是,我不知道如何实施这一点。有什么想法吗?提前非常感谢。我将为此创建一个新问题,并链接回此问题。
data = [
[101, '1987-09-01', 1, 1, '1987-09-01', 2, 2, 3],
[102, '1987-09-01', 1, 1, '1999-09-01', 2, 2, 3],
[103, 'nan', 0, 0, '1999-09-01', 2, 2, 3]
]
df = pd.DataFrame(data, columns=['ID', 'Date1', 'OPxx', 'NPxy', 'Date2',
'OPyy', 'NPyx', 'WZ'])
df['Date1'] = pd.to_datetime(df['Date1'])
df['Date2'] = pd.to_datetime(df['Date2'])
s = df.columns.to_series()
#get first 2 characters
s1 = s.str[:2]
#create groups starting by ID and Da (first 2 letters of Date)
s2 = s1.isin(['ID','Da']).cumsum().astype(str)
s = s1 + s2
print (s)
ID ID1
Date1 Da2
OPxx OP2
NPxy NP2
Date2 Da3
OPyy OP3
NPyx NP3
WZ WZ3
dtype: object
df = df.rename(columns=s)
print (df)
ID1 Da2 OP2 NP2 Da3 OP3 NP3 WZ3
0 101 1987-09-01 1 1 1987-09-01 2 2 3
1 102 1987-09-01 1 1 1999-09-01 2 2 3
2 103 NaT 0 0 1999-09-01 2 2 3
print(np.setdiff1d(s1.unique(), ['ID', 'index']))
['Da' 'NP' 'OP' 'WZ']
df1 = pd.wide_to_long(df.reset_index(),
stubnames=np.setdiff1d(s1.unique(), ['ID', 'index']),
i=['index','ID1'],
j='tmp')
df2 = (df1.groupby(['index','ID1','Da'])
.sum()
.reset_index(level=0, drop=True)
.reset_index())
print (df2)
ID1 Da NP OP WZ
0 101 1987-09-01 3 3 3.0
1 102 1987-09-01 1 1 0.0
2 102 1999-09-01 2 2 3.0
3 103 1999-09-01 2 2 3.0