首页 > 解决方案 > 基于模板在 PYTHON 中更改具有匹配列名的 pandas 数据框列的数据类型

问题描述

我有 2 个数据框。

我想根据第一个更改第二个数据帧的数据类型。假设我有以下数据框,我将其用作模板。

> template
id <- c(1,2,3,4)
a <- c(1,4,5,6)
b <- as.character(c(0,1,1,4))
c <- as.character(c(0,1,1,0))
d <- c(0,1,1,0)
template <- data.frame(id,a,b,c,d, stringsAsFactors = FALSE)

> str(template)
'data.frame':   4 obs. of  5 variables:
 $ id: num  1 2 3 4
 $ a : num  1 4 5 6
 $ b : chr  "0" "1" "1" "4"
 $ c : chr  "0" "1" "1" "0"
 $ d : num  0 1 1 0

我正在寻找下面的东西。

**注意 - 如果 df 中不可用,它应该添加带有所有 NA 的附加列。

> df
id <- c(6,7,12,14,1,3,4,4)
a <- c(0,1,13,1,3,4,5,6)
b <- c(1,4,12,3,4,5,6,7)
c <- c(0,0,13,3,4,45,6,7)
e <- c(0,0,13,3,4,45,6,7)
df <- data.frame(id,a,b,c,e)

> str(df)
'data.frame':   8 obs. of  5 variables:
 $ id: num  6 7 12 14 1 3 4 4
 $ a : num  0 1 13 1 3 4 5 6
 $ b : num  1 4 12 3 4 5 6 7
 $ c : num  0 0 13 3 4 45 6 7
 $ e : num  0 0 13 3 4 45 6 7

所需的输出 -

> output
    id  a  b  c  d
    1  6  0  1  0 NA
    2  7  1  4  0 NA
    3 12 13 12 13 NA
    4 14  1  3  3 NA
    5  1  3  4  4 NA
    6  3  4  5 45 NA
    7  4  5  6  6 NA
    8  4  6  7  7 NA

> str(output)

'data.frame':   8 obs. of  5 variables:
 $ id: num  6 7 12 14 1 3 4 4
 $ a : num  0 1 13 1 3 4 5 6
 $ b : chr  "1" "4" "12" "3" ...
 $ c : chr  "0" "0" "13" "3" ...
 $ d : logi  NA NA NA NA NA NA ...

@Frank 的 R 解决方案。

res = data.frame(
  lapply(setNames(,names(template)), function(x) 
    if (x %in% names(df)) as(df[[x]], class(template[[x]])) 
    else template[[x]][NA_integer_]
  ), stringsAsFactors = FALSE)

注意-我正在尝试在 Python 中做同样的事情。我是 python 新手,不知道如何处理。任何帮助将不胜感激。

标签: pythonpython-3.xpandasdataframepandas-groupby

解决方案


在一般情况下,您的问题无法解决,因为熊猫(numpy)中没有integer NaN和没有booleane NaNNaN应该提升存储数据类型https://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na。你可以这样做:

import numpy as np
import pandas as pd

TEMPLATE = pd.DataFrame(
    {'id': pd.Series(dtype=int),
     'a': pd.Series(dtype=int),
     'b': pd.Series(dtype=str),
     'c': pd.Series(dtype=str),
     'd': pd.Series(dtype=bool)})


def modify_with_template(df, template):

    # type promotion
    df_dtypes = df.dtypes.to_dict()
    t_dtypes = template.dtypes.to_dict()

    to_promote_int = {
        col: np.float_
        for col in set(t_dtypes.keys()).difference(df_dtypes.keys())
        if issubclass(t_dtypes[col].type, np.integer)}
    to_promote_bool = {
        col: np.object_
        for col in set(t_dtypes.keys()).difference(df_dtypes.keys())
        if t_dtypes[col].type is np.bool_}

    t_dtypes.update(to_promote_int)
    t_dtypes.update(to_promote_bool)

    # actual modifying
    return df.reindex(template.columns, axis=1).astype(t_dtypes)


df = pd.DataFrame({'id': ['1', '0', '1']})
print(df)
df = modify_with_template(df, TEMPLATE)
print(df)

输出:

  id
0  1
1  0
2  1
    a    b    c    d  id
0 NaN  NaN  NaN  NaN   1
1 NaN  NaN  NaN  NaN   0
2 NaN  NaN  NaN  NaN   1

推荐阅读