Панды - вычитать столбцы из разных фреймов данных со смешанным типом данных - PullRequest
0 голосов
/ 08 октября 2019

У меня есть два фрейма данных, которые импортируются из разных .csv.

df10=pd.read_csv(path10, usecols=["Registros validados"])
df25=pd.read_csv(path25, usecols=["Registros validados"])

Это 173 тыс. Строк и один столбец, в данных содержатся числа, но есть пустые измерения, которые при чтении изcsv обрабатываются как пустая строка (как и числа в этом отношении).

То, что мне нужно сделать, это просто, мне нужно вычитать их только тогда, когда в обоих столбцах есть число, и создать третий кадр данных.

Нашел две идеи, которые я получил из других постов этой веб-страницы. Следующие два - это те, которые работали (не дали мне ошибок), потому что в основном я видел .apply, но это всегда было так, когда использовались столбцы с одного и того же кадра данных, которого здесь нет.

Варианты, которые «работали», были

list(map(subs_PM, dfpm10, dfpm25))
# Returns ['']

и

dfpm10.combine(dfpm25, func=subs_PM)
# Actually returns a data frame, but is always empty with ''. 

Используемая функция вычитания была

def subs_PM_old(pm10, pm25):
   try: # Thinking the strings would fail at this
       pm10=int(pm10)
       pm25=int(pm25)
   except: 
       return ' '
   else:
       return pm10-pm25

Мысль может быть, расхожденияв вычитании было связано с тем, что датафрейм не состоял из цифр. Поэтому я сделал следующее, чтобы преобразовать числа в числа и оставить строки в виде строк.

df10=df10.apply(pd.to_numeric, errors='ignore')
df25=df25.apply(pd.to_numeric, errors='ignore')

и обновил функцию до

def subs_PM(pm10, pm25):
    boolpm10=isinstance(pm10, (int, long, float, complex)) and not isinstance(pm10, bool)
    boolpm25=isinstance(pm10, (int, long, float, complex)) and not isinstance(pm25, bool)

    if boolpm10 and boolpm25:
        return pm10-pm25
    else:
        return ''

Но ничего не изменилось

Похоже, происходит то, что в обоих случаях функция вычитания используется только для первой строки, а затем предполагается, что она будет такой же для остальных элементов.

Есть ли способ изменить это?


Очевидно, что это не мои кадры данных, но подумайте, чтобы поиграться с

df1 = pd.DataFrame({1: range(10)})
df2 = pd.DataFrame({1: [2, 3, '', '', 2, 1, '', 6, 2, 3]})
df1.combine(df2, func=subs_PM)
df1.combine(df2, func=subs_PM_old)
list(map(subs_PM, df1, df2))
list(map(subs_PM_old, df1, df2))

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Чтобы проверить все варианты, я определил исходные фреймы данных следующим образом:

df1 = pd.DataFrame({1: [0, '',  2,  3, 4, 5, '', 7, 8, 9]})
df2 = pd.DataFrame({1: [2,  3, '', '', 2, 1,  5, 6, 2, 3]})

Цель состояла в том, чтобы иметь «пары» аргументов, где либо df1 , либо df2 может содержать строку (исключается из окончательного результата).

Первоначальные операции включают:

  • объединение обоих фреймов данных,
  • замена пустых строк на NaN и отбросьте их,
  • измените тип обратно на int ,
  • дайте разные имена для обоих столбцов.

Код для этого:

res = df1.join(df2, rsuffix='_2').replace('', np.nan).dropna().astype(int)
res.columns=['c1', 'c2']

Для моих исходных данных результат:

   c1  c2
0   0   2
4   4   2
5   5   1
7   7   6
8   8   2
9   9   3

Затем просто вычислите разницу, сохранив ее в другом столбце:

res['dif'] = res.c1 - res.c2

Окончательный результат:

   c1  c2  dif
0   0   2   -2
4   4   2    2
5   5   1    4
7   7   6    1
8   8   2    6
9   9   3    6

Если хотите, отбросьте столбцы c1 и c2 .

1 голос
/ 08 октября 2019

Попробуйте это:

def subs_PM(pm10, pm25):
    #pm10 and pm25 are series... not a single number
    #print(pm10)
    try:
        pm10=pd.to_numeric(pm10)
        pm25=pd.to_numeric(pm25)
        return pm10-pm25
    except:
        return None

df1 = pd.DataFrame({1: range(10)})
df2 = pd.DataFrame({1: [2, 3, '', '', 2, 1, '', 6, 2, 3]})
df1.combine(df2, func=subs_PM)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...