第5章 合并

第5章 合并

import numpy as np
import pandas as pd
df = pd.read_csv('data/table.csv')
df.head()
SchoolClassIDGenderAddressHeightWeightMathPhysics
0S_1C_11101Mstreet_11736334.0A+
1S_1C_11102Fstreet_21927332.5B+
2S_1C_11103Mstreet_21868287.2B+
3S_1C_11104Fstreet_21678180.4B-
4S_1C_11105Fstreet_41596484.8B+

一、append与assign

1. append方法

(a)利用序列添加行(必须指定name)
df_append = df.loc[:3,['Gender','Height']].copy()
df_append
GenderHeight
0M173
1F192
2M186
3F167
s = pd.Series({'Gender':'F','Height':188},name='new_row')
df_append.append(s)
GenderHeight
0M173
1F192
2M186
3F167
new_rowF188
(b)用DataFrame添加表
df_temp = pd.DataFrame({'Gender':['F','M'],'Height':[188,176]},index=['new_1','new_2'])
df_append.append(df_temp)
GenderHeight
0M173
1F192
2M186
3F167
new_1F188
new_2M176

2. assign方法

该方法主要用于添加列,列名直接由参数指定:
s = pd.Series(list('abcd'),index=range(4))
df_append.assign(Letter=s)
GenderHeightLetter
0M173a
1F192b
2M186c
3F167d
可以一次添加多个列:
df_append.assign(col1=lambda x:x['Gender']*2,
                 col3=s)
GenderHeightcol1col3
0M173MMa
1F192FFb
2M186MMc
3F167FFd

二、combine与update

1. comine方法

comine和update都是用于表的填充函数,可以根据某种规则填充
(a)填充对象
可以看出combine方法是按照表的顺序轮流进行逐列循环的,而且自动索引对齐,缺失值为NaN,理解这一点很重要
df_combine_1 = df.loc[:1,['Gender','Height']].copy()
df_combine_2 = df.loc[10:11,['Gender','Height']].copy()
df_combine_1.combine(df_combine_2,lambda x,y:print(x,y))
0       M
1       F
10    NaN
11    NaN
Name: Gender, dtype: object 0     NaN
1     NaN
10      M
11      F
Name: Gender, dtype: object
0     173.0
1     192.0
10      NaN
11      NaN
Name: Height, dtype: float64 0       NaN
1       NaN
10    161.0
11    175.0
Name: Height, dtype: float64
GenderHeight
0NaNNaN
1NaNNaN
10NaNNaN
11NaNNaN
(b)一些例子
例①:根据列均值的大小填充
# 例子1
df1 = pd.DataFrame({'A': [1,10], 'B': [3,4]})
df2 = pd.DataFrame({'A': [8, 7], 'B': [6, 5]})

df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y)
AB
086
175
例②:索引对齐特性(默认状态下,后面的表没有的行列都会设置为NaN)
df2 = pd.DataFrame({'B': [8, 7], 'C': [6, 5]},index=[1,2])
df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y)
ABC
0NaNNaNNaN
1NaN8.06.0
2NaN7.05.0
例③:使得df1原来符合条件的值不会被覆盖
df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y,overwrite=False) 
ABC
01.0NaNNaN
12.08.06.0
2NaN7.05.0
例④:在新增匹配df2的元素位置填充-1
df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y,fill_value=-1)
ABC
01.0-1.0-1.0
12.08.06.0
2-1.07.05.0
(c)combine_first方法
这个方法作用是用df2填补df1的缺失值,功能比较简单,但很多时候会比combine更常用,下面举两个例子:
df1 = pd.DataFrame({'A': [None, 0], 'B': [None, 4]})
df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
df1.combine_first(df2)
AB
01.03.0
10.04.0
df1 = pd.DataFrame({'A': [None, 0], 'B': [4, None]})
df2 = pd.DataFrame({'B': [3, 3], 'C': [1, 1]}, index=[1, 2])
df1.combine_first(df2)
ABC
0NaN4.0NaN
10.03.01.0
2NaN3.01.0

2. update方法

(a)三个特点
①返回的框索引只会与被调用框的一致(默认使用左连接,下一节会介绍)
②第二个框中的nan元素不会起作用
③没有返回值,直接在df上操作
(b)例子
例①:索引完全对齐情况下的操作
df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
df2 = pd.DataFrame({'B': [4, 5, 6],
                    'C': [7, 8, 9]})
df1.update(df2)
df1
AB
014
125
236
例②:部分填充
df1 = pd.DataFrame({'A': ['a', 'b', 'c'],
                    'B': ['x', 'y', 'z']})
df2 = pd.DataFrame({'B': ['d', 'e']}, index=[1,2])
df1.update(df2)
df1
AB
0ax
1bd
2ce
例③:缺失值不会填充
df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
df2 = pd.DataFrame({'B': [4, np.nan, 6]})
df1.update(df2)
df1
AB
014.0
12500.0
236.0

三、concat方法

concat方法可以在两个维度上拼接,默认纵向凭借(axis=0),拼接方式默认外连接
所谓外连接,就是取拼接方向的并集,而’inner’时取拼接方向(若使用默认的纵向拼接,则为列的交集)的交集
下面举一些例子说明其参数:
df1 = pd.DataFrame({'A': ['A0', 'A1'],
                    'B': ['B0', 'B1']},
                    index = [0,1])
df2 = pd.DataFrame({'A': ['A2', 'A3'],
                    'B': ['B2', 'B3']},
                    index = [2,3])
df3 = pd.DataFrame({'A': ['A1', 'A3'],
                    'D': ['D1', 'D3'],
                    'E': ['E1', 'E3']},
                    index = [1,3])
默认状态拼接:
pd.concat([df1,df2])
AB
0A0B0
1A1B1
2A2B2
3A3B3
axis=1时沿列方向拼接:
pd.concat([df1,df2],axis=1)
ABAB
0A0B0NaNNaN
1A1B1NaNNaN
2NaNNaNA2B2
3NaNNaNA3B3
join设置为内连接(由于axis=0,因此列取交集):
pd.concat([df3,df1],join='inner')
A
1A1
3A3
0A0
1A1
join设置为外链接:
pd.concat([df3,df1],join='outer',sort=True) #sort设置列排序,默认为False
ABDE
1A1NaND1E1
3A3NaND3E3
0A0B0NaNNaN
1A1B1NaNNaN
verify_integrity检查列是否唯一:
#pd.concat([df3,df1],verify_integrity=True,sort=True) 报错
同样,可以添加Series:
s = pd.Series(['X0', 'X1'], name='X')
pd.concat([df1,s],axis=1)
ABX
0A0B0X0
1A1B1X1
key参数用于对不同的数据框增加一个标号,便于索引:
pd.concat([df1,df2], keys=['x', 'y'])
pd.concat([df1,df2], keys=['x', 'y']).index
MultiIndex([('x', 0),
            ('x', 1),
            ('y', 2),
            ('y', 3)],
           )

四、merge与join

1. merge函数

merge函数的作用是将两个pandas对象横向合并,遇到重复的索引项时会使用笛卡尔积,默认inner连接,可选left、outer、right连接
所谓左连接,就是指以第一个表索引为基准,右边的表中如果不再左边的则不加入,如果在左边的就以笛卡尔积的方式加入
merge/join与concat的不同之处在于on参数,可以指定某一个对象为key来进行连接
同样的,下面举一些例子:
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1'],
                      'A': ['A0', 'A1', 'A2', 'A3'],
                      'B': ['B0', 'B1', 'B2', 'B3']}) 
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']})
right2 = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3']})
以key1为准则连接,如果具有相同的列,则默认suffixes=(’_x’,’_y’):
pd.merge(left, right, on='key1')
key1key2_xABkey2_yCD
0K0K0A0B0K0C0D0
1K0K1A1B1K0C0D0
2K1K0A2B2K0C1D1
3K1K0A2B2K0C2D2
4K2K1A3B3K0C3D3
以多组键连接:
pd.merge(left, right, on=['key1','key2'])
key1key2ABCD
0K0K0A0B0C0D0
1K1K0A2B2C1D1
2K1K0A2B2C2D2
默认使用inner连接,因为merge只能横向拼接,所以取行向上keys的交集,下面看如果使用how=outer参数
注意:这里的how就是concat的join
pd.merge(left, right, how='outer', on=['key1','key2'])
key1key2ABCD
0K0K0A0B0C0D0
1K0K1A1B1NaNNaN
2K1K0A2B2C1D1
3K1K0A2B2C2D2
4K2K1A3B3NaNNaN
5K2K0NaNNaNC3D3
左连接:
pd.merge(left, right, how='left', on=['key1', 'key2'])
key1key2ABCD
0K0K0A0B0C0D0
1K0K1A1B1NaNNaN
2K1K0A2B2C1D1
3K1K0A2B2C2D2
4K2K1A3B3NaNNaN
右连接:
pd.merge(left, right, how='right', on=['key1', 'key2'])
key1key2ABCD
0K0K0A0B0C0D0
1K1K0A2B2C1D1
2K1K0A2B2C2D2
3K2K0NaNNaNC3D3
如果还是对笛卡尔积不太了解,请务必理解下面这个例子,由于B的所有元素为2,因此需要6行:
left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})
right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 2, 2]})
pd.merge(left, right, on='B', how='outer')
A_xBA_y
0124
1125
2126
3224
4225
5226
validate检验的是到底哪一边出现了重复索引,如果是“one_to_one”则两侧索引都是唯一,如果"one_to_many"则左侧唯一
left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})
right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 3, 4]})
#pd.merge(left, right, on='B', how='outer',validate='one_to_one') #报错
left = pd.DataFrame({'A': [1, 2], 'B': [2, 1]})
pd.merge(left, right, on='B', how='outer',validate='one_to_one')
A_xBA_y
01.024.0
12.01NaN
2NaN35.0
3NaN46.0
indicator参数指示了,合并后该行索引的来源
df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']})
df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_right': [2, 2, 2]})
pd.merge(df1, df2, on='col1', how='outer', indicator=True) #indicator='indicator_column'也是可以的
col1col_leftcol_right_merge
00aNaNleft_only
11b2.0both
22NaN2.0right_only
32NaN2.0right_only

2. join函数

join函数作用是将多个pandas对象横向拼接,遇到重复的索引项时会使用笛卡尔积,默认左连接,可选inner、outer、right连接
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
                      'D': ['D0', 'D2', 'D3']},
                    index=['K0', 'K2', 'K3'])
left.join(right)
ABCD
K0A0B0C0D0
K1A1B1NaNNaN
K2A2B2C2D2
对于many_to_one模式下的合并,往往join更为方便
同样可以指定key:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3'],
                     'key': ['K0', 'K1', 'K0', 'K1']})
right = pd.DataFrame({'C': ['C0', 'C1'],
                      'D': ['D0', 'D1']},
                     index=['K0', 'K1'])
left.join(right, on='key')
ABkeyCD
0A0B0K0C0D0
1A1B1K1C1D1
2A2B2K0C0D0
3A3B3K1C1D1
多层key:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3'],
                     'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1']})
index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),
                                   ('K2', 'K0'), ('K2', 'K1')],names=['key1','key2'])
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']},
                     index=index)
left.join(right, on=['key1','key2'])
ABkey1key2CD
0A0B0K0K0C0D0
1A1B1K0K1NaNNaN
2A2B2K1K0C1D1
3A3B3K2K1C3D3

五、问题与练习

1. 问题

【问题一】 请思考什么是append/assign/combine/update/concat/merge/join各自最适合使用的场景,并举出相应的例子。

append:增加行,必须要指定列名和索引名
s = pd.Series({‘Gender’:‘F’,‘Height’:188},name=‘new_row’)
df_append.append(s)
assign:增加列,列名由参数决定
s = pd.Series(list(‘abcd’),index=range(4))
df_append.assign(Letter=s)
combine:两个表进行填充时
# 例子1
df1 = pd.DataFrame({‘A’: [1,10], ‘B’: [3,4]})
df2 = pd.DataFrame({‘A’: [8, 7], ‘B’: [6, 5]})
df1.combine(df2,lambda x,y:x if x.mean()>y.mean() else y,overwrite=False)
update:用df2中的值替换df中的值,最后结果直接在df1中更改,形状不变
df1.update(df2)
concat:两个表进行连接,concat方法可以在两个维度上拼接,默认纵向凭借(axis=0),拼接方式默认外连接
所谓外连接,就是取拼接方向的并集,而’inner’时取拼接方向(若使用默认的纵向拼接,则为列的交集)的交集
pd.concat([df1,df2])
merge:merge函数的作用是将两个pandas对象横向合并,遇到重复的索引项时会使用笛卡尔积,默认inner连接,可选left、outer、right连接
所谓左连接,就是指以第一个表索引为基准,右边的表中如果不再左边的则不加入,如果在左边的就以笛卡尔积的方式加入
merge/join与concat的不同之处在于on参数,可以指定某一个对象为key来进行连接
pd.merge(left, right, on=‘key1’)
join:join函数作用是将多个pandas对象横向拼接,遇到重复的索引项时会使用笛卡尔积,默认左连接,可选inner、outer、right连接
left.join(right)

【问题二】 merge_ordered和merge_asof的作用是什么?和merge是什么关系?

merge_ordered函数允许组合时间序列和其他有序数据。 特别是它有一个可选的fill_method关键字来填充/插入缺失的数据。
merge_asof除了我们匹配最近的键而不是相等的键之外,其他的都类似于有序的left-join 。 对于左侧DataFrame中的每一行,我们选择右侧DataFrame中on键对应的值小于left的键对应的值的最后一行。 两个DataFrame必须按键排序。

【问题三】 请构造一个多级索引与多级索引合并的例子,尝试使用不同的合并函数。
left = pd.DataFrame({'A': [1, 2], 'B': [2, 2],'C':[9,8]}).set_index(['A','B'])
right = pd.DataFrame({'A': [2, 2, 6], 'B': [2, 3, 4],'C':[7,8,9]}).set_index(['A','B'])

left.append(right)
C
AB
129
228
27
38
649
left.combine(right,lambda x,y:x if x.mean()>y.mean() else y)
C
AB
129.0
228.0
3NaN
64NaN
pd.merge(df1,df2)
AB
086
175
【问题四】 上文提到了连接的笛卡尔积,那么当连接方式变化时(inner/outer/left/right),这种笛卡尔积规则会相应变化吗?请构造相应例子。
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
                      'D': ['D0', 'D2', 'D3']},
                    index=['K0', 'K2', 'K3'])
left.join(right,how='inner')
ABCD
K0A0B0C0D0
K2A2B2C2D2
left.join(right,how='left')
ABCD
K0A0B0C0D0
K1A1B1NaNNaN
K2A2B2C2D2
left.join(right,how='right')
ABCD
K0A0B0C0D0
K2A2B2C2D2
K3NaNNaNC3D3

会根据连接方式不同而不同

2. 练习

【练习一】有2张公司的员工信息表,每个公司共有16名员工,共有五个公司,请解决如下问题:
df1=pd.read_csv('data/Employee1.csv')
df1.head()
CompanyNameAgeHeightWeightSalary
0Aa14718863.725819
1Aa33917255.921983
2Aa44315862.521755
3Aa64218276.917354
4Aa74917194.66177
df2=pd.read_csv('data/Employee2.csv')
df2.head()
CompanyNameAgeHeightWeightSalary
0Aa13015691.228133
1Aa25019083.46673
2Aa33416896.616503
3Aa55117697.223294
4Aa63718393.219256
(a) 每个公司有多少员工满足如下条件:既出现第一张表,又出现在第二张表。
n = set(df1['Name'].values.tolist())&set(df2['Name'].values.tolist())
n
{'a1',
 'a3',
 'a6',
 'b1',
 'b15',
 'b3',
 'b7',
 'c10',
 'c12',
 'c13',
 'c3',
 'd10',
 'd5',
 'e10',
 'e11',
 'e8'}
(b) 将所有不符合(a)中条件的行筛选出来,合并为一张新表,列名与原表一致。
df = pd.concat([df1,df2])
b = df[~df['Name'].isin( n)]
b

CompanyNameAgeHeightWeightSalary
2Aa44315862.521755
4Aa74917194.66177
5Aa85116889.53246
6Aa93618662.83569
7Aa135819075.921854
8Aa153516297.24706
9Aa163515777.616130
12Bb53617168.422547
13Bb64618498.919493
15Bb95218780.521171
16Bb103717795.614376
17Bb145218151.911474
20Cc44119061.819258
21Cc53616584.36563
22Cc73218958.124791
23Cc93217692.511797
27Dd25219084.79382
29Dd64517892.519393
30Dd95216071.813531
32Dd115518393.912547
33Ee43716791.319171
34Ee74416451.913035
38Ee135718054.826837
39Ee143916383.020554
1Aa25019083.46673
3Aa55117697.223294
5Aa105616482.224799
6Aa123617796.910270
7Aa145619062.610229
9Bb24318470.113092
12Bb84015881.413511
13Bb113416174.415788
14Bb135715752.34549
16Cc16017283.814374
17Cc25918676.211086
19Cc65018356.720698
21Cc115417392.113031
24Dd15515575.121312
25Dd43816780.527224
27Dd73116854.922548
28Dd83416451.024060
30Ee26018367.315515
31Ee34018699.19976
32Ee64416591.528818
36Ee125415779.418490
© 现在需要编制所有80位员工的信息表,对于(b)中的员工要求不变,对于满足(a)条件员工,它们在某个指标的数值,取偏离它所属公司中满足(b)员工的均值数较小的哪一个,例如:P公司在两张表的交集为{p1},并集扣除交集为{p2,p3,p4},那么如果后者集合的工资均值为1万元,且p1在表1的工资为13000元,在表2的工资为9000元,那么应该最后取9000元作为p1的工资,最后对于没有信息的员工,利用缺失值填充。
df1 = pd.read_csv('data/Employee1.csv')
df2 = pd.read_csv('data/Employee2.csv')
df1['重复'] = ['Y_1' if df1.loc[i,'Name'] in n else 'N' for i in range(df1.shape[0])]
df2['重复'] = ['Y_2' if df2.loc[i,'Name'] in n else 'N' for i in range(df2.shape[0])]
df1 = df1.set_index(['Name','重复'])
df2 = df2.set_index(['Name','重复'])
df_c = pd.concat([df1,df2])
result = pd.DataFrame({'Company':[],'Name':[],'Age':[],'Height':[],'Weight':[],'Salary':[]})
group = df_c.groupby(['Company','重复'])
for i in n:
    first = group.get_group((i[0].upper(),'Y_1')).reset_index(level=1).loc[i,:][-4:]
    second = group.get_group((i[0].upper(),'Y_2')).reset_index(level=1).loc[i,:][-4:]
    mean = group.get_group((i[0].upper(),'N')).reset_index(level=1).mean()
    final = [i[0].upper(),i]
    for j in range(4):
        final.append(first[j] if abs(first[j]-mean[j])<abs(second[j]-mean[j]) else second[j])
    result = pd.concat([result,pd.DataFrame({result.columns.tolist()[k]:[final[k]] for k in range(6)})])
result = pd.concat([result.set_index('Name'),b])
for i in list('abcde'):
    for j in range(1,17):
        item = i+str(j)
        if item not in result.index:
            result = pd.concat([result,pd.DataFrame({'Company':[i.upper()],'Name':[item]
                 ,'Age':[np.nan],'Height':[np.nan],'Weight':[np.nan],'Salary':[np.nan]}).set_index('Name')])
print(result.index)
result['Number'] = [i for i in result.index]
result.reset_index().drop(columns='Name').set_index(['Company','Number']).sort_index()
/home/myth/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:18: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

/home/myth/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:24: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.



Index(['e10', 'd10', 'c13',  'a6',  'b1', 'c12', 'c10',  'c3', 'b15',  'a1',
       ...
        'e4',  'e5',  'e6',  'e7',  'e9', 'e12', 'e13', 'e14', 'e15', 'e16'],
      dtype='object', length=125)
indexAgeHeightSalaryWeight
CompanyNumber
A1150.0190.06673.083.4
2243.0158.021755.062.5
3351.0176.023294.097.2
4449.0171.06177.094.6
5551.0168.03246.089.5
.....................
Ee5e5NaNNaNNaNNaN
e6e6NaNNaNNaNNaN
e7e7NaNNaNNaNNaN
e8e845.0171.020836.068.1
e9e9NaNNaNNaNNaN

125 rows × 5 columns

【练习二】有2张课程的分数表(分数随机生成),但专业课(学科基础课、专业必修课、专业选修课)与其他课程混在一起,请解决如下问题:
df1 = pd.read_csv('data/Course1.csv')
df1.head()
课程名字课程类别学分分数
0思想道德修养与法律基础思政类389.0
1云计算应用与开发专业选修课396.0
2社会计算专业选修课378.0
3深度学习专业选修课375.0
4人工智能导论专业必修课384.0
df2=pd.read_csv('data/Course2.csv')
df2.head()
课程名字课程类别学分分数
0高等数学(一)学科基础课499.0
1数据科学与工程导论学科基础课3NaN
2专业英语学科基础课2100.0
3概率论学科基础课399.0
4计算机系统专业必修课480.0
(a) 将两张表分别拆分为专业课与非专业课(结果为四张表)。
df_a11,df_a12,df_a21,df_a22 =0,0,0,0
df_a11= df1.query('课程类别 in ["学科基础课","专业必修课","专业选修课"]')
df_a12= df1.query('课程类别 not in ["学科基础课","专业必修课","专业选修课"]')
df_a21= df2.query('课程类别 in ["学科基础课","专业必修课","专业选修课"]')
df_a22= df2.query('课程类别 not in ["学科基础课","专业必修课","专业选修课"]')
df_a11.head()
课程名字课程类别学分分数
1云计算应用与开发专业选修课396.0
2社会计算专业选修课378.0
3深度学习专业选修课375.0
4人工智能导论专业必修课384.0
6数据结构与算法学科基础课582.0
df_a12.head()
课程名字课程类别学分分数
0思想道德修养与法律基础思政类389.0
5中国近代史纲要思政类397.0
8网球(初)体育类181.0
10极端性气候与陆地生态系统公共任意选修类278.0
13游泳(初)体育类175.0
df_a21.head()
课程名字课程类别学分分数
0高等数学(一)学科基础课499.0
1数据科学与工程导论学科基础课3NaN
2专业英语学科基础课2100.0
3概率论学科基础课399.0
4计算机系统专业必修课480.0
df_a22.head()
课程名字课程类别学分分数
25学术英语听说(二)英语类292.0
26学术英语阅读英语类272.0
27学术英语写作英语类298.0
28美国社会与文化英语类277.0
29马克思主义基本原理概论思政类395.0
(b) 将两张专业课的分数表和两张非专业课的分数表分别合并。
df_a11.append(df_a21).reset_index().head()
index课程名字课程类别学分分数
01云计算应用与开发专业选修课396.0
12社会计算专业选修课378.0
23深度学习专业选修课375.0
34人工智能导论专业必修课384.0
46数据结构与算法学科基础课582.0
df_a12.append(df_a22).reset_index().head()
index课程名字课程类别学分分数
00思想道德修养与法律基础思政类389.0
15中国近代史纲要思政类397.0
28网球(初)体育类181.0
310极端性气候与陆地生态系统公共任意选修类278.0
413游泳(初)体育类175.0
© 不使用(a)中的步骤,请直接读取两张表合并后拆分。
df = df1.append(df2)
df_a1= df.query('课程类别 in ["学科基础课","专业必修课","专业选修课"]')
df_a1.head()
课程名字课程类别学分分数
1云计算应用与开发专业选修课396.0
2社会计算专业选修课378.0
3深度学习专业选修课375.0
4人工智能导论专业必修课384.0
6数据结构与算法学科基础课582.0
df_a2= df.query('课程类别 not in ["学科基础课","专业必修课","专业选修课"]')
df_a2.head()
课程名字课程类别学分分数
0思想道德修养与法律基础思政类389.0
5中国近代史纲要思政类397.0
8网球(初)体育类181.0
10极端性气候与陆地生态系统公共任意选修类278.0
13游泳(初)体育类175.0
(d) 专业课程中有缺失值吗,如果有的话请在完成(3)的同时,用组内(3种类型的专业课)均值填充缺失值后拆分。
df['分数'] = df.groupby('课程类别').transform(lambda x: x.fillna(x.mean()))['分数']
df.isnull().all()
课程名字    False
课程类别    False
学分      False
分数      False
dtype: bool
df_a1= df.query('课程类别 in ["学科基础课","专业必修课","专业选修课"]')
df_a1.head()
课程名字课程类别学分分数
1云计算应用与开发专业选修课396.0
2社会计算专业选修课378.0
3深度学习专业选修课375.0
4人工智能导论专业必修课384.0
6数据结构与算法学科基础课582.0
df_a2= df.query('课程类别 not in ["学科基础课","专业必修课","专业选修课"]')
df_a2.head()
课程名字课程类别学分分数
0思想道德修养与法律基础思政类389.0
5中国近代史纲要思政类397.0
8网球(初)体育类181.0
10极端性气候与陆地生态系统公共任意选修类278.0
13游泳(初)体育类175.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值