[python] 사전을 기반으로 데이터 프레임에 새 열 추가
데이터 프레임과 사전이 있습니다. 데이터 프레임에 새 열을 추가하고 사전을 기반으로 해당 값을 계산해야합니다.
기계 학습, 일부 테이블을 기반으로 새로운 기능 추가 :
score = {(1, 45, 1, 1) : 4, (0, 1, 2, 1) : 5}
df = pd.DataFrame(data = {
'gender' : [1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
'age' : [13, 45, 1, 45, 15, 16, 16, 16, 15, 15],
'cholesterol' : [1, 2, 2, 1, 1, 1, 1, 1, 1, 1],
'smoke' : [0, 0, 1, 1, 7, 8, 3, 4, 4, 2]},
dtype = np.int64)
print(df, '\n')
df['score'] = 0
df.score = score[(df.gender, df.age, df.cholesterol, df.smoke)]
print(df)
다음과 같은 결과가 기대됩니다.
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
답변
이후 score
(키가 고유 때문에) 사전은 우리가 사용할 수있는 MultiIndex
정렬을
df = df.set_index(['gender', 'age', 'cholesterol', 'smoke'])
df['score'] = pd.Series(score) # Assign values based on the tuple
df = df.fillna(0, downcast='infer').reset_index() # Back to columns
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
답변
assign
목록 이해와 함께 사용 하여 score
사전 에서 튜플 값 (각 행)을 가져 오며 찾을 수없는 경우 기본값은 0입니다.
>>> df.assign(score=[score.get(tuple(row), 0) for row in df.values])
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
타이밍
다양한 접근 방식을 고려할 때 일부 타이밍을 비교하는 것이 흥미로울 것입니다.
# Initial dataframe 100k rows (10 rows of identical data replicated 10k times).
df = pd.DataFrame(data = {
'gender' : [1, 1, 0, 1, 1, 0, 0, 0, 1, 0] * 10000,
'age' : [13, 45, 1, 45, 15, 16, 16, 16, 15, 15] * 10000,
'cholesterol' : [1, 2, 2, 1, 1, 1, 1, 1, 1, 1] * 10000,
'smoke' : [0, 0, 1, 1, 7, 8, 3, 4, 4, 2] * 10000},
dtype = np.int64)
%timeit -n 10 df.assign(score=[score.get(tuple(v), 0) for v in df.values])
# 223 ms ± 9.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
df.assign(score=[score.get(t, 0) for t in zip(*map(df.get, df))])
# 76.8 ms ± 2.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
df.assign(score=[score.get(v, 0) for v in df.itertuples(index=False)])
# 113 ms ± 2.58 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit -n 10 df.assign(score=df.apply(lambda x: score.get(tuple(x), 0), axis=1))
# 1.84 s ± 77.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
(df
.set_index(['gender', 'age', 'cholesterol', 'smoke'])
.assign(score=pd.Series(score))
.fillna(0, downcast='infer')
.reset_index()
)
# 138 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
s=pd.Series(score)
s.index.names=['gender','age','cholesterol','smoke']
df.merge(s.to_frame('score').reset_index(),how='left').fillna(0).astype(int)
# 24 ms ± 2.27 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
df.assign(score=pd.Series(zip(df.gender, df.age, df.cholesterol, df.smoke))
.map(score)
.fillna(0)
.astype(int))
# 191 ms ± 7.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit -n 10
df.assign(score=df[['gender', 'age', 'cholesterol', 'smoke']]
.apply(tuple, axis=1)
.map(score)
.fillna(0))
# 1.95 s ± 134 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
답변
score는 사전이므로 map을 사용할 수 있습니다 .
df['score'] = df[['gender', 'age', 'cholesterol', 'smoke']].apply(tuple, axis=1).map(score).fillna(0)
print(df)
산출
gender age cholesterol smoke score
0 1 13 1 0 0.0
1 1 45 2 0 0.0
2 0 1 2 1 5.0
3 1 45 1 1 4.0
4 1 15 1 7 0.0
5 0 16 1 8 0.0
6 0 16 1 3 0.0
7 0 16 1 4 0.0
8 1 15 1 4 0.0
9 0 15 1 2 0.0
대안으로 목록 이해를 사용할 수 있습니다.
df['score'] = [score.get(t, 0) for t in zip(df.gender, df.age, df.cholesterol, df.smoke)]
print(df)
답변
목록 이해 및지도 :
df['score'] = (pd.Series(zip(df.gender, df.age, df.cholesterol, df.smoke))
.map(score)
.fillna(0)
.astype(int)
)
산출:
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
9 0 15 1 2 0.0
답변
reindex
df['socre']=pd.Series(score).reindex(pd.MultiIndex.from_frame(df),fill_value=0).values
df
Out[173]:
gender age cholesterol smoke socre
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
또는 merge
s=pd.Series(score)
s.index.names=['gender','age','cholesterol','smoke']
df=df.merge(s.to_frame('score').reset_index(),how='left').fillna(0)
Out[166]:
gender age cholesterol smoke score
0 1 13 1 0 0.0
1 1 45 2 0 0.0
2 0 1 2 1 5.0
3 1 45 1 1 4.0
4 1 15 1 7 0.0
5 0 16 1 8 0.0
6 0 16 1 3 0.0
7 0 16 1 4 0.0
8 1 15 1 4 0.0
9 0 15 1 2 0.0
답변
다른 방법으로 사용할 수 있습니다 .loc[]
:
m=df.set_index(df.columns.tolist())
m.loc[list(score.keys())].assign(
score=score.values()).reindex(m.index,fill_value=0).reset_index()
gender age cholesterol smoke score
0 1 13 1 0 0
1 1 45 2 0 0
2 0 1 2 1 5
3 1 45 1 1 4
4 1 15 1 7 0
5 0 16 1 8 0
6 0 16 1 3 0
7 0 16 1 4 0
8 1 15 1 4 0
9 0 15 1 2 0
답변
간단한 한 줄 솔루션, 사용 get
및 tuple
행 단위
df['score'] = df.apply(lambda x: score.get(tuple(x), 0), axis=1)
위의 솔루션은 원하는 열 이외의 열이 순서대로 없다고 가정합니다. 그렇지 않은 경우 열만 사용하십시오.
cols = ['gender','age','cholesterol','smoke']
df['score'] = df[cols].apply(lambda x: score.get(tuple(x), 0), axis=1)